blob: 7593e58180d6d8f506b35e178cfe1640f5d29cde [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)
34 * - C99 NaN(n-char-sequence) missing
35 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
36 * for %a, because C99 used %a for other purposes. If specified as
37 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
38 * the C99 hex-float. This means that you cannot scan %as as a hex-float
39 * immediately followed by an 's'.
Bjorn Reese906ec8a2001-06-05 12:46:33 +000040 * - Scanning of collating symbols.
Daniel Veillard92ad2102001-03-27 12:47:33 +000041 */
42
Daniel Veillard92ad2102001-03-27 12:47:33 +000043/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +000044 * Trio include files
Daniel Veillard92ad2102001-03-27 12:47:33 +000045 */
Bjorn Reese45029602001-08-21 09:23:53 +000046#include "triodef.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000047#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000048#include "triop.h"
Bjorn Reese45029602001-08-21 09:23:53 +000049#include "trionan.h"
Daniel Veillardb7c29c32002-09-25 22:44:43 +000050#if !defined(TRIO_MINIMAL)
51# include "triostr.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000052#endif
53
Daniel Veillardb7c29c32002-09-25 22:44:43 +000054/**************************************************************************
55 *
56 * Definitions
57 *
58 *************************************************************************/
59
Bjorn Reese906ec8a2001-06-05 12:46:33 +000060#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
61# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
62# if !defined(MB_LEN_MAX)
63# define MB_LEN_MAX 6
64# endif
65#endif
66
Bjorn Reese906ec8a2001-06-05 12:46:33 +000067/*************************************************************************
68 * Generic definitions
69 */
70
71#if !(defined(DEBUG) || defined(NDEBUG))
72# define NDEBUG
73#endif
74#include <assert.h>
75#include <ctype.h>
76#if !defined(TRIO_COMPILER_SUPPORTS_C99)
77# define isblank(x) (((x)==32) || ((x)==9))
78#endif
79#include <math.h>
80#include <limits.h>
81#include <float.h>
Daniel Veillardb7c29c32002-09-25 22:44:43 +000082#if defined(TRIO_COMPILER_ANCIENT)
83# include <varargs.h>
84#else
85# include <stdarg.h>
86#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +000087#include <stddef.h>
88#include <errno.h>
89
90#ifndef NULL
91# define NULL 0
92#endif
93#define NIL ((char)0)
94#ifndef FALSE
95# define FALSE (1 == 0)
96# define TRUE (! FALSE)
97#endif
98#define BOOLEAN_T int
99
100/* mincore() can be used for debugging purposes */
101#define VALID(x) (NULL != (x))
102
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000103#if TRIO_ERRORS
104 /*
105 * Encode the error code and the position. This is decoded
106 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
107 */
108# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
109#else
110# define TRIO_ERROR_RETURN(x,y) (-1)
111#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000112
113
114/*************************************************************************
115 * Platform specific definitions
116 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000117#if defined(TRIO_PLATFORM_UNIX)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000118# include <unistd.h>
119# include <signal.h>
120# include <locale.h>
121# define USE_LOCALE
Bjorn Reese026d29f2002-01-19 15:40:18 +0000122#endif /* TRIO_PLATFORM_UNIX */
123#if defined(TRIO_PLATFORM_VMS)
124# include <unistd.h>
125#endif
126#if defined(TRIO_PLATFORM_WIN32)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000127# include <io.h>
128# define read _read
129# define write _write
Bjorn Reese026d29f2002-01-19 15:40:18 +0000130#endif /* TRIO_PLATFORM_WIN32 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000131
Bjorn Reese45029602001-08-21 09:23:53 +0000132#define TRIO_MSVC_VERSION_5 1100
133
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000134#if TRIO_WIDECHAR
135# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
136# include <wchar.h>
137# include <wctype.h>
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000138typedef wchar_t trio_wchar_t;
139typedef wint_t trio_wint_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000140# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000141typedef char trio_wchar_t;
142typedef int trio_wint_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000143# define WCONST(x) L ## x
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000144# define WEOF EOF
145# define iswalnum(x) isalnum(x)
146# define iswalpha(x) isalpha(x)
147# define iswblank(x) isblank(x)
148# define iswcntrl(x) iscntrl(x)
149# define iswdigit(x) isdigit(x)
150# define iswgraph(x) isgraph(x)
151# define iswlower(x) islower(x)
152# define iswprint(x) isprint(x)
153# define iswpunct(x) ispunct(x)
154# define iswspace(x) isspace(x)
155# define iswupper(x) isupper(x)
156# define iswxdigit(x) isxdigit(x)
157# endif
158#endif
159
160
161/*************************************************************************
162 * Compiler dependent definitions
163 */
164
165/* Support for long long */
166#ifndef __cplusplus
167# if !defined(USE_LONGLONG)
Bjorn Reese026d29f2002-01-19 15:40:18 +0000168# if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000169# define USE_LONGLONG
Bjorn Reese026d29f2002-01-19 15:40:18 +0000170# elif defined(TRIO_COMPILER_SUNPRO)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000171# define USE_LONGLONG
172# elif defined(_LONG_LONG) || defined(_LONGLONG)
173# define USE_LONGLONG
174# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000175# endif
176#endif
177
178/* The extra long numbers */
179#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000180typedef signed long long int trio_longlong_t;
181typedef unsigned long long int trio_ulonglong_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000182#elif defined(TRIO_COMPILER_MSVC)
Bjorn Reese45029602001-08-21 09:23:53 +0000183# if (_MSC_VER >= TRIO_MSVC_VERSION_5)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000184typedef signed __int64 trio_longlong_t;
185typedef unsigned __int64 trio_ulonglong_t;
186# else
187typedef signed long int trio_longlong_t;
188typedef unsigned long int trio_ulonglong_t;
189# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000190#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000191typedef TRIO_SIGNED long int trio_longlong_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000192typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000193#endif
194
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000195/* Maximal and fixed integer types */
196#if defined(TRIO_COMPILER_SUPPORTS_C99)
197# include <stdint.h>
198typedef intmax_t trio_intmax_t;
199typedef uintmax_t trio_uintmax_t;
200typedef int8_t trio_int8_t;
201typedef int16_t trio_int16_t;
202typedef int32_t trio_int32_t;
203typedef int64_t trio_int64_t;
204#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
205# include <inttypes.h>
206typedef intmax_t trio_intmax_t;
207typedef uintmax_t trio_uintmax_t;
208typedef int8_t trio_int8_t;
209typedef int16_t trio_int16_t;
210typedef int32_t trio_int32_t;
211typedef int64_t trio_int64_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000212#elif defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= TRIO_MSVC_VERSION_5)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000213typedef trio_longlong_t trio_intmax_t;
214typedef trio_ulonglong_t trio_uintmax_t;
215typedef __int8 trio_int8_t;
216typedef __int16 trio_int16_t;
217typedef __int32 trio_int32_t;
218typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000219#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000220typedef trio_longlong_t trio_intmax_t;
221typedef trio_ulonglong_t trio_uintmax_t;
222# if defined(TRIO_INT8_T)
223typedef TRIO_INT8_T trio_int8_t;
224# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000225typedef TRIO_SIGNED char trio_int8_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000226# endif
227# if defined(TRIO_INT16_T)
228typedef TRIO_INT16_T trio_int16_t;
229# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000230typedef TRIO_SIGNED short trio_int16_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000231# endif
232# if defined(TRIO_INT32_T)
233typedef TRIO_INT32_T trio_int32_t;
234# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000235typedef TRIO_SIGNED int trio_int32_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000236# endif
237# if defined(TRIO_INT64_T)
238typedef TRIO_INT64_T trio_int64_t;
239# else
240typedef trio_longlong_t trio_int64_t;
241# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000242#endif
243
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000244#if !(defined(TRIO_COMPILER_SUPPORTS_C99) \
245 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))
246# define floorl(x) floor((double)(x))
247# define fmodl(x,y) fmod((double)(x),(double)(y))
248# define powl(x,y) pow((double)(x),(double)(y))
249#endif
250
251#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000252
253/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000254 * Internal Definitions
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000255 */
256
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000257#ifndef DECIMAL_DIG
258# define DECIMAL_DIG DBL_DIG
259#endif
260
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000261/* Long double sizes */
262#ifdef LDBL_DIG
263# define MAX_MANTISSA_DIGITS LDBL_DIG
264# define MAX_EXPONENT_DIGITS 4
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000265# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000266#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000267# define MAX_MANTISSA_DIGITS DECIMAL_DIG
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000268# define MAX_EXPONENT_DIGITS 3
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000269# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
270#endif
271
272#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
273# undef LDBL_DIG
274# undef LDBL_MANT_DIG
275# undef LDBL_EPSILON
276# define LDBL_DIG DBL_DIG
277# define LDBL_MANT_DIG DBL_MANT_DIG
278# define LDBL_EPSILON DBL_EPSILON
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000279#endif
280
281/* The maximal number of digits is for base 2 */
282#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000283/* The width of a pointer. The number of bits in a hex digit is 4 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000284#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000285
286/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000287#define INFINITE_LOWER "inf"
288#define INFINITE_UPPER "INF"
289#define LONG_INFINITE_LOWER "infinite"
290#define LONG_INFINITE_UPPER "INFINITE"
291#define NAN_LOWER "nan"
292#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000293
294/* Various constants */
295enum {
296 TYPE_PRINT = 1,
297 TYPE_SCAN = 2,
298
299 /* Flags. Use maximum 32 */
300 FLAGS_NEW = 0,
301 FLAGS_STICKY = 1,
302 FLAGS_SPACE = 2 * FLAGS_STICKY,
303 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
304 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
305 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
306 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
307 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
308 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
309 FLAGS_QUAD = 2 * FLAGS_LONG,
310 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
311 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
312 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
313 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
314 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
315 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
316 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
317 FLAGS_WIDTH = 2 * FLAGS_UPPER,
318 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
319 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
320 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
321 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
322 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
323 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
324 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
325 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
326 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
327 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
328 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
329 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000330 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
331 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000332 /* Reused flags */
333 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000334 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000335 FLAGS_ROUNDING = FLAGS_INTMAX_T,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000336 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000337 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000338 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000339
340 NO_POSITION = -1,
341 NO_WIDTH = 0,
342 NO_PRECISION = -1,
343 NO_SIZE = -1,
344
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000345 /* Do not change these */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000346 NO_BASE = -1,
347 MIN_BASE = 2,
348 MAX_BASE = 36,
349 BASE_BINARY = 2,
350 BASE_OCTAL = 8,
351 BASE_DECIMAL = 10,
352 BASE_HEX = 16,
353
354 /* Maximal number of allowed parameters */
355 MAX_PARAMETERS = 64,
356 /* Maximal number of characters in class */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000357 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000358
Bjorn Reese70a9da52001-04-21 16:57:29 +0000359 /* Maximal string lengths for user-defined specifiers */
360 MAX_USER_NAME = 64,
361 MAX_USER_DATA = 256,
362
Daniel Veillard92ad2102001-03-27 12:47:33 +0000363 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000364 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000365 /* Maximal number of integers in grouping */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000366 MAX_LOCALE_GROUPS = 64,
367
368 /* Initial size of asprintf buffer */
369 DYNAMIC_START_SIZE = 32
Daniel Veillard92ad2102001-03-27 12:47:33 +0000370};
371
372#define NO_GROUPING ((int)CHAR_MAX)
373
374/* Fundamental formatting parameter types */
375#define FORMAT_UNKNOWN 0
376#define FORMAT_INT 1
377#define FORMAT_DOUBLE 2
378#define FORMAT_CHAR 3
379#define FORMAT_STRING 4
380#define FORMAT_POINTER 5
381#define FORMAT_COUNT 6
382#define FORMAT_PARAMETER 7
383#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000384#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000385# define FORMAT_ERRNO 9
386#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000387#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000388# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000389#endif
390
391/* Character constants */
392#define CHAR_IDENTIFIER '%'
393#define CHAR_BACKSLASH '\\'
394#define CHAR_QUOTE '\"'
395#define CHAR_ADJUST ' '
396
397/* Character class expressions */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000398#define CLASS_ALNUM "[:alnum:]"
399#define CLASS_ALPHA "[:alpha:]"
400#define CLASS_BLANK "[:blank:]"
401#define CLASS_CNTRL "[:cntrl:]"
402#define CLASS_DIGIT "[:digit:]"
403#define CLASS_GRAPH "[:graph:]"
404#define CLASS_LOWER "[:lower:]"
405#define CLASS_PRINT "[:print:]"
406#define CLASS_PUNCT "[:punct:]"
407#define CLASS_SPACE "[:space:]"
408#define CLASS_UPPER "[:upper:]"
409#define CLASS_XDIGIT "[:xdigit:]"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000410
411/*
412 * SPECIFIERS:
413 *
414 *
415 * a Hex-float
416 * A Hex-float
417 * c Character
418 * C Widechar character (wint_t)
419 * d Decimal
420 * e Float
421 * E Float
422 * F Float
423 * F Float
424 * g Float
425 * G Float
426 * i Integer
427 * m Error message
428 * n Count
429 * o Octal
430 * p Pointer
431 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000432 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000433 * u Unsigned
434 * x Hex
435 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000436 * [] Group
437 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000438 *
439 * Reserved:
440 *
441 * D Binary Coded Decimal %D(length,precision) (OS/390)
442 */
443#define SPECIFIER_CHAR 'c'
444#define SPECIFIER_STRING 's'
445#define SPECIFIER_DECIMAL 'd'
446#define SPECIFIER_INTEGER 'i'
447#define SPECIFIER_UNSIGNED 'u'
448#define SPECIFIER_OCTAL 'o'
449#define SPECIFIER_HEX 'x'
450#define SPECIFIER_HEX_UPPER 'X'
451#define SPECIFIER_FLOAT_E 'e'
452#define SPECIFIER_FLOAT_E_UPPER 'E'
453#define SPECIFIER_FLOAT_F 'f'
454#define SPECIFIER_FLOAT_F_UPPER 'F'
455#define SPECIFIER_FLOAT_G 'g'
456#define SPECIFIER_FLOAT_G_UPPER 'G'
457#define SPECIFIER_POINTER 'p'
458#define SPECIFIER_GROUP '['
459#define SPECIFIER_UNGROUP ']'
460#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000461#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000462# define SPECIFIER_CHAR_UPPER 'C'
463# define SPECIFIER_STRING_UPPER 'S'
464#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000465#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000466# define SPECIFIER_HEXFLOAT 'a'
467# define SPECIFIER_HEXFLOAT_UPPER 'A'
468#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000469#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000470# define SPECIFIER_ERRNO 'm'
471#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000472#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000473# define SPECIFIER_BINARY 'b'
474# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000475# define SPECIFIER_USER_DEFINED_BEGIN '<'
476# define SPECIFIER_USER_DEFINED_END '>'
477# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000478#endif
479
480/*
481 * QUALIFIERS:
482 *
483 *
484 * Numbers = d,i,o,u,x,X
485 * Float = a,A,e,E,f,F,g,G
486 * String = s
487 * Char = c
488 *
489 *
490 * 9$ Position
491 * Use the 9th parameter. 9 can be any number between 1 and
492 * the maximal argument
493 *
494 * 9 Width
495 * Set width to 9. 9 can be any number, but must not be postfixed
496 * by '$'
497 *
498 * h Short
499 * Numbers:
500 * (unsigned) short int
501 *
502 * hh Short short
503 * Numbers:
504 * (unsigned) char
505 *
506 * l Long
507 * Numbers:
508 * (unsigned) long int
509 * String:
510 * as the S specifier
511 * Char:
512 * as the C specifier
513 *
514 * ll Long Long
515 * Numbers:
516 * (unsigned) long long int
517 *
518 * L Long Double
519 * Float
520 * long double
521 *
522 * # Alternative
523 * Float:
524 * Decimal-point is always present
525 * String:
526 * non-printable characters are handled as \number
527 *
528 * Spacing
529 *
530 * + Sign
531 *
532 * - Alignment
533 *
534 * . Precision
535 *
536 * * Parameter
537 * print: use parameter
538 * scan: no parameter (ignore)
539 *
540 * q Quad
541 *
542 * Z size_t
543 *
544 * w Widechar
545 *
546 * ' Thousands/quote
547 * Numbers:
548 * Integer part grouped in thousands
549 * Binary numbers:
550 * Number grouped in nibbles (4 bits)
551 * String:
552 * Quoted string
553 *
554 * j intmax_t
555 * t prtdiff_t
556 * z size_t
557 *
558 * ! Sticky
559 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000560 *
561 * I n-bit Integer
562 * Numbers:
563 * The following options exists
564 * I8 = 8-bit integer
565 * I16 = 16-bit integer
566 * I32 = 32-bit integer
567 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000568 */
569#define QUALIFIER_POSITION '$'
570#define QUALIFIER_SHORT 'h'
571#define QUALIFIER_LONG 'l'
572#define QUALIFIER_LONG_UPPER 'L'
573#define QUALIFIER_ALTERNATIVE '#'
574#define QUALIFIER_SPACE ' '
575#define QUALIFIER_PLUS '+'
576#define QUALIFIER_MINUS '-'
577#define QUALIFIER_DOT '.'
578#define QUALIFIER_STAR '*'
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000579#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000580#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000581# define QUALIFIER_SIZE_T 'z'
582# define QUALIFIER_PTRDIFF_T 't'
583# define QUALIFIER_INTMAX_T 'j'
584#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000585#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000586# define QUALIFIER_QUAD 'q'
587#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000588#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000589# define QUALIFIER_SIZE_T_UPPER 'Z'
590#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000591#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000592# define QUALIFIER_WIDECHAR 'w'
593#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000594#if TRIO_MICROSOFT
595# define QUALIFIER_FIXED_SIZE 'I'
596#endif
597#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000598# define QUALIFIER_QUOTE '\''
599# define QUALIFIER_STICKY '!'
600# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
601# define QUALIFIER_PARAM '@' /* Experimental */
602# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000603# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000604# define QUALIFIER_ROUNDING_UPPER 'R'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000605#endif
606
Bjorn Reese70a9da52001-04-21 16:57:29 +0000607
608/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000609 *
610 * Internal Structures
611 *
612 *************************************************************************/
Bjorn Reese70a9da52001-04-21 16:57:29 +0000613
614/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000615typedef struct {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000616 /* An indication of which entry in the data union is used */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000617 int type;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000618 /* The flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000619 unsigned long flags;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000620 /* The width qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000621 int width;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000622 /* The precision qualifier */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000623 int precision;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000624 /* The base qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000625 int base;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000626 /* The size for the variable size qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000627 int varsize;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000628 /* The marker of the end of the specifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000629 int indexAfterSpecifier;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000630 /* The data from the argument list */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000631 union {
632 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000633#if TRIO_WIDECHAR
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000634 trio_wchar_t *wstring;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000635#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000636 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000637 union {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000638 trio_intmax_t as_signed;
639 trio_uintmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000640 } number;
641 double doubleNumber;
642 double *doublePointer;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000643 trio_long_double_t longdoubleNumber;
644 trio_long_double_t *longdoublePointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000645 int errorNumber;
646 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000647 /* For the user-defined specifier */
648 char user_name[MAX_USER_NAME];
649 char user_data[MAX_USER_DATA];
Bjorn Reese026d29f2002-01-19 15:40:18 +0000650} trio_parameter_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000651
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000652/* Container for customized functions */
653typedef struct {
654 union {
655 trio_outstream_t out;
656 trio_instream_t in;
657 } stream;
658 trio_pointer_t closure;
659} trio_custom_t;
660
Bjorn Reese70a9da52001-04-21 16:57:29 +0000661/* General trio "class" */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000662typedef struct _trio_class_t {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000663 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +0000664 * The function to write characters to a stream.
665 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000666 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000667 /*
668 * The function to read characters from a stream.
669 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000670 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000671 /*
672 * The current location in the stream.
673 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000674 trio_pointer_t location;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000675 /*
676 * The character currently being processed.
677 */
678 int current;
679 /*
680 * The number of characters that would have been written/read
681 * if there had been sufficient space.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000682 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000683 int processed;
684 /*
685 * The number of characters that are actually written/read.
Bjorn Reese026d29f2002-01-19 15:40:18 +0000686 * Processed and committed will only differ for the *nprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +0000687 * and *nscanf functions.
688 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000689 int committed;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000690 /*
691 * The upper limit of characters that may be written/read.
692 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000693 int max;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000694 /*
695 * The last output error that was detected.
696 */
697 int error;
698} trio_class_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000699
Bjorn Reese70a9da52001-04-21 16:57:29 +0000700/* References (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000701typedef struct _trio_reference_t {
702 trio_class_t *data;
703 trio_parameter_t *parameter;
704} trio_reference_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000705
706/* Registered entries (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000707typedef struct _trio_userdef_t {
708 struct _trio_userdef_t *next;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000709 trio_callback_t callback;
710 char *name;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000711} trio_userdef_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000712
Daniel Veillard92ad2102001-03-27 12:47:33 +0000713
714/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000715 *
716 * Internal Variables
717 *
718 *************************************************************************/
Daniel Veillard92ad2102001-03-27 12:47:33 +0000719
Bjorn Reese026d29f2002-01-19 15:40:18 +0000720static TRIO_CONST char rcsid[] = "@(#)$Id$";
721
722/*
723 * Need this to workaround a parser bug in HP C/iX compiler that fails
724 * to resolves macro definitions that includes type 'long double',
725 * e.g: va_arg(arg_ptr, long double)
726 */
727#if defined(TRIO_PLATFORM_MPEIX)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000728static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000729#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +0000730
731static TRIO_CONST char internalNullString[] = "(nil)";
Daniel Veillard92ad2102001-03-27 12:47:33 +0000732
Bjorn Reese70a9da52001-04-21 16:57:29 +0000733#if defined(USE_LOCALE)
734static struct lconv *internalLocaleValues = NULL;
735#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000736
Bjorn Reese70a9da52001-04-21 16:57:29 +0000737/*
738 * UNIX98 says "in a locale where the radix character is not defined,
739 * the radix character defaults to a period (.)"
740 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000741static int internalDecimalPointLength = 1;
742static int internalThousandSeparatorLength = 1;
743static char internalDecimalPoint = '.';
744static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000745static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000746static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
747
Bjorn Reese026d29f2002-01-19 15:40:18 +0000748static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
749static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000750static BOOLEAN_T internalDigitsUnconverted = TRUE;
751static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000752#if TRIO_EXTENSION
753static BOOLEAN_T internalCollationUnconverted = TRUE;
754static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
755#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000756
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000757#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +0000758static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
759static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
760static trio_userdef_t *internalUserDef = NULL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000761#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000762
763
764/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000765 *
766 * Internal Functions
767 *
768 ************************************************************************/
769
770#if defined(TRIO_MINIMAL)
771# define TRIO_STRING_PUBLIC static
772# include "triostr.c"
773#endif /* defined(TRIO_MINIMAL) */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000774
775/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000776 * TrioIsQualifier
Daniel Veillard92ad2102001-03-27 12:47:33 +0000777 *
778 * Description:
779 * Remember to add all new qualifiers to this function.
780 * QUALIFIER_POSITION must not be added.
781 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000782TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000783TrioIsQualifier
784TRIO_ARGS1((character),
785 TRIO_CONST char character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000786{
787 /* QUALIFIER_POSITION is not included */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000788 switch (character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000789 {
790 case '0': case '1': case '2': case '3': case '4':
791 case '5': case '6': case '7': case '8': case '9':
792 case QUALIFIER_PLUS:
793 case QUALIFIER_MINUS:
794 case QUALIFIER_SPACE:
795 case QUALIFIER_DOT:
796 case QUALIFIER_STAR:
797 case QUALIFIER_ALTERNATIVE:
798 case QUALIFIER_SHORT:
799 case QUALIFIER_LONG:
800 case QUALIFIER_LONG_UPPER:
801 case QUALIFIER_CIRCUMFLEX:
802#if defined(QUALIFIER_SIZE_T)
803 case QUALIFIER_SIZE_T:
804#endif
805#if defined(QUALIFIER_PTRDIFF_T)
806 case QUALIFIER_PTRDIFF_T:
807#endif
808#if defined(QUALIFIER_INTMAX_T)
809 case QUALIFIER_INTMAX_T:
810#endif
811#if defined(QUALIFIER_QUAD)
812 case QUALIFIER_QUAD:
813#endif
814#if defined(QUALIFIER_SIZE_T_UPPER)
815 case QUALIFIER_SIZE_T_UPPER:
816#endif
817#if defined(QUALIFIER_WIDECHAR)
818 case QUALIFIER_WIDECHAR:
819#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000820#if defined(QUALIFIER_QUOTE)
821 case QUALIFIER_QUOTE:
822#endif
823#if defined(QUALIFIER_STICKY)
824 case QUALIFIER_STICKY:
825#endif
826#if defined(QUALIFIER_VARSIZE)
827 case QUALIFIER_VARSIZE:
828#endif
829#if defined(QUALIFIER_PARAM)
830 case QUALIFIER_PARAM:
831#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000832#if defined(QUALIFIER_FIXED_SIZE)
833 case QUALIFIER_FIXED_SIZE:
834#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000835#if defined(QUALIFIER_ROUNDING_UPPER)
836 case QUALIFIER_ROUNDING_UPPER:
837#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000838 return TRUE;
839 default:
840 return FALSE;
841 }
842}
843
844/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000845 * TrioSetLocale
Bjorn Reese70a9da52001-04-21 16:57:29 +0000846 */
847#if defined(USE_LOCALE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000848TRIO_PRIVATE void
849TrioSetLocale(TRIO_NOARGS)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000850{
851 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000852 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000853 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000854 if ((internalLocaleValues->decimal_point) &&
855 (internalLocaleValues->decimal_point[0] != NIL))
856 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000857 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
858 if (internalDecimalPointLength == 1)
859 {
860 internalDecimalPoint = internalLocaleValues->decimal_point[0];
861 }
862 else
863 {
864 internalDecimalPoint = NIL;
865 trio_copy_max(internalDecimalPointString,
866 sizeof(internalDecimalPointString),
867 internalLocaleValues->decimal_point);
868 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000869 }
870 if ((internalLocaleValues->thousands_sep) &&
871 (internalLocaleValues->thousands_sep[0] != NIL))
872 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000873 trio_copy_max(internalThousandSeparator,
874 sizeof(internalThousandSeparator),
875 internalLocaleValues->thousands_sep);
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000876 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000877 }
878 if ((internalLocaleValues->grouping) &&
879 (internalLocaleValues->grouping[0] != NIL))
880 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000881 trio_copy_max(internalGrouping,
882 sizeof(internalGrouping),
883 internalLocaleValues->grouping);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000884 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000885 }
886}
887#endif /* defined(USE_LOCALE) */
888
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000889TRIO_PRIVATE int
890TrioCalcThousandSeparatorLength
891TRIO_ARGS1((digits),
892 int digits)
893{
894#if TRIO_EXTENSION
895 int count = 0;
896 int step = NO_GROUPING;
897 char *groupingPointer = internalGrouping;
898
899 while (digits > 0)
900 {
901 if (*groupingPointer == CHAR_MAX)
902 {
903 /* Disable grouping */
904 break; /* while */
905 }
906 else if (*groupingPointer == 0)
907 {
908 /* Repeat last group */
909 if (step == NO_GROUPING)
910 {
911 /* Error in locale */
912 break; /* while */
913 }
914 }
915 else
916 {
917 step = *groupingPointer++;
918 }
919 if (digits > step)
920 count += internalThousandSeparatorLength;
921 digits -= step;
922 }
923 return count;
924#else
925 return 0;
926#endif
927}
928
929TRIO_PRIVATE BOOLEAN_T
930TrioFollowedBySeparator
931TRIO_ARGS1((position),
932 int position)
933{
934#if TRIO_EXTENSION
935 int step = 0;
936 char *groupingPointer = internalGrouping;
937
938 position--;
939 if (position == 0)
940 return FALSE;
941 while (position > 0)
942 {
943 if (*groupingPointer == CHAR_MAX)
944 {
945 /* Disable grouping */
946 break; /* while */
947 }
948 else if (*groupingPointer != 0)
949 {
950 step = *groupingPointer++;
951 }
952 if (step == 0)
953 break;
954 position -= step;
955 }
956 return (position == 0);
957#else
958 return FALSE;
959#endif
960}
961
Bjorn Reese70a9da52001-04-21 16:57:29 +0000962/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000963 * TrioGetPosition
Daniel Veillard92ad2102001-03-27 12:47:33 +0000964 *
965 * Get the %n$ position.
966 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000967TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000968TrioGetPosition
969TRIO_ARGS2((format, indexPointer),
970 TRIO_CONST char *format,
971 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000972{
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000973#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000974 char *tmpformat;
975 int number = 0;
976 int index = *indexPointer;
977
Bjorn Reese026d29f2002-01-19 15:40:18 +0000978 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +0000979 index = (int)(tmpformat - format);
980 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
981 {
982 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000983 /*
984 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000985 * the array it is indexing starts from 0.
986 */
987 return number - 1;
988 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000989#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000990 return NO_POSITION;
991}
992
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000993#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000994/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000995 * TrioFindNamespace
Bjorn Reese70a9da52001-04-21 16:57:29 +0000996 *
997 * Find registered user-defined specifier.
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000998 * The prev argument is used for optimization only.
Bjorn Reese70a9da52001-04-21 16:57:29 +0000999 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001000TRIO_PRIVATE trio_userdef_t *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001001TrioFindNamespace
1002TRIO_ARGS2((name, prev),
1003 TRIO_CONST char *name,
1004 trio_userdef_t **prev)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001005{
Bjorn Reese026d29f2002-01-19 15:40:18 +00001006 trio_userdef_t *def;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001007
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001008 if (internalEnterCriticalRegion)
1009 (void)internalEnterCriticalRegion(NULL);
1010
Bjorn Reese70a9da52001-04-21 16:57:29 +00001011 for (def = internalUserDef; def; def = def->next)
1012 {
1013 /* Case-sensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001014 if (trio_equal_case(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001015 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001016
1017 if (prev)
1018 *prev = def;
1019 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001020
1021 if (internalLeaveCriticalRegion)
1022 (void)internalLeaveCriticalRegion(NULL);
1023
Bjorn Reese70a9da52001-04-21 16:57:29 +00001024 return def;
1025}
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001026#endif
1027
1028/*************************************************************************
1029 * TrioPower
1030 *
1031 * Description:
1032 * Calculate pow(base, exponent), where number and exponent are integers.
1033 */
1034TRIO_PRIVATE trio_long_double_t
1035TrioPower
1036TRIO_ARGS2((number, exponent),
1037 int number,
1038 int exponent)
1039{
1040 trio_long_double_t result;
1041
1042 if (number == 10)
1043 {
1044 switch (exponent)
1045 {
1046 /* Speed up calculation of common cases */
1047 case 0:
1048 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1049 break;
1050 case 1:
1051 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1052 break;
1053 case 2:
1054 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1055 break;
1056 case 3:
1057 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1058 break;
1059 case 4:
1060 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1061 break;
1062 case 5:
1063 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1064 break;
1065 case 6:
1066 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1067 break;
1068 case 7:
1069 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1070 break;
1071 case 8:
1072 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1073 break;
1074 case 9:
1075 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1076 break;
1077 default:
1078 result = powl((trio_long_double_t)number,
1079 (trio_long_double_t)exponent);
1080 break;
1081 }
1082 }
1083 else
1084 {
1085 return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1086 }
1087 return result;
1088}
1089
1090/*************************************************************************
1091 * TrioLogarithm
1092 */
1093TRIO_PRIVATE double
1094TrioLogarithm
1095TRIO_ARGS2((number, base),
1096 double number,
1097 int base)
1098{
1099 double result;
1100
1101 if (number <= 0.0)
1102 {
1103 /* xlC crashes on log(0) */
1104 result = (number == 0.0) ? trio_ninf() : trio_nan();
1105 }
1106 else
1107 {
1108 if (base == 10)
1109 {
1110 result = log10(number);
1111 }
1112 else
1113 {
1114 result = log10(number) / log10((double)base);
1115 }
1116 }
1117 return result;
1118}
1119
1120/*************************************************************************
1121 * TrioLogarithmBase
1122 */
1123TRIO_PRIVATE double
1124TrioLogarithmBase
1125TRIO_ARGS1((base),
1126 int base)
1127{
1128 switch (base)
1129 {
1130 case BASE_BINARY : return 1.0;
1131 case BASE_OCTAL : return 3.0;
1132 case BASE_DECIMAL: return 3.321928094887362345;
1133 case BASE_HEX : return 4.0;
1134 default : return TrioLogarithm((double)base, 2);
1135 }
1136}
Bjorn Reese70a9da52001-04-21 16:57:29 +00001137
1138/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00001139 * TrioParse
Daniel Veillard92ad2102001-03-27 12:47:33 +00001140 *
1141 * Description:
1142 * Parse the format string
1143 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001144TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001145TrioParse
1146TRIO_ARGS5((type, format, parameters, arglist, argarray),
1147 int type,
1148 TRIO_CONST char *format,
1149 trio_parameter_t *parameters,
1150 va_list *arglist,
1151 trio_pointer_t *argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001152{
Daniel Veillard92ad2102001-03-27 12:47:33 +00001153 /* Count the number of times a parameter is referenced */
1154 unsigned short usedEntries[MAX_PARAMETERS];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001155 /* Parameter counters */
1156 int parameterPosition;
1157 int currentParam;
1158 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001159 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001160 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001161 int width;
1162 int precision;
1163 int varsize;
1164 int base;
1165 int index; /* Index into formatting string */
1166 int dots; /* Count number of dots in modifier part */
1167 BOOLEAN_T positional; /* Does the specifier have a positional? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001168 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001169 /*
1170 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +00001171 * read from the va_args (this is necessary to handle positionals)
1172 */
1173 int indices[MAX_PARAMETERS];
1174 int pos = 0;
1175 /* Various variables */
1176 char ch;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001177#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001178 int charlen;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001179#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001180 int save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001181 int i = -1;
1182 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001183 char *tmpformat;
1184
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001185 /* One and only one of arglist and argarray must be used */
1186 assert((arglist != NULL) ^ (argarray != NULL));
1187
Bjorn Reese70a9da52001-04-21 16:57:29 +00001188 /*
1189 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +00001190 * know which entries we have used.
1191 */
1192 memset(usedEntries, 0, sizeof(usedEntries));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001193
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001194 save_errno = errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001195 index = 0;
1196 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001197#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001198 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001199#endif
1200
1201 while (format[index])
1202 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001203#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001204 if (! isascii(format[index]))
1205 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001206 /*
1207 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001208 * modifiers, so we skip over them.
1209 */
1210 charlen = mblen(&format[index], MB_LEN_MAX);
1211 index += (charlen > 0) ? charlen : 1;
1212 continue; /* while */
1213 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001214#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001215 if (CHAR_IDENTIFIER == format[index++])
1216 {
1217 if (CHAR_IDENTIFIER == format[index])
1218 {
1219 index++;
1220 continue; /* while */
1221 }
1222
1223 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001224 dots = 0;
1225 currentParam = TrioGetPosition(format, &index);
1226 positional = (NO_POSITION != currentParam);
1227 if (!positional)
1228 {
1229 /* We have no positional, get the next counter */
1230 currentParam = parameterPosition;
1231 }
1232 if(currentParam >= MAX_PARAMETERS)
1233 {
1234 /* Bail out completely to make the error more obvious */
1235 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1236 }
1237
1238 if (currentParam > maxParam)
1239 maxParam = currentParam;
1240
1241 /* Default values */
1242 width = NO_WIDTH;
1243 precision = NO_PRECISION;
1244 base = NO_BASE;
1245 varsize = NO_SIZE;
1246
Bjorn Reese70a9da52001-04-21 16:57:29 +00001247 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001248 {
1249 ch = format[index++];
1250
Daniel Veillard92ad2102001-03-27 12:47:33 +00001251 switch (ch)
1252 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001253 case QUALIFIER_SPACE:
1254 flags |= FLAGS_SPACE;
1255 break;
1256
1257 case QUALIFIER_PLUS:
1258 flags |= FLAGS_SHOWSIGN;
1259 break;
1260
1261 case QUALIFIER_MINUS:
1262 flags |= FLAGS_LEFTADJUST;
1263 flags &= ~FLAGS_NILPADDING;
1264 break;
1265
1266 case QUALIFIER_ALTERNATIVE:
1267 flags |= FLAGS_ALTERNATIVE;
1268 break;
1269
1270 case QUALIFIER_DOT:
1271 if (dots == 0) /* Precision */
1272 {
1273 dots++;
1274
1275 /* Skip if no precision */
1276 if (QUALIFIER_DOT == format[index])
1277 break;
1278
1279 /* After the first dot we have the precision */
1280 flags |= FLAGS_PRECISION;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001281 if ((QUALIFIER_STAR == format[index])
1282#if defined(QUALIFIER_PARAM)
1283 || (QUALIFIER_PARAM == format[index])
1284#endif
1285 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001286 {
1287 index++;
1288 flags |= FLAGS_PRECISION_PARAMETER;
1289
1290 precision = TrioGetPosition(format, &index);
1291 if (precision == NO_POSITION)
1292 {
1293 parameterPosition++;
1294 if (positional)
1295 precision = parameterPosition;
1296 else
1297 {
1298 precision = currentParam;
1299 currentParam = precision + 1;
1300 }
1301 }
1302 else
1303 {
1304 if (! positional)
1305 currentParam = precision + 1;
1306 if (width > maxParam)
1307 maxParam = precision;
1308 }
1309 if (currentParam > maxParam)
1310 maxParam = currentParam;
1311 }
1312 else
1313 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001314 precision = trio_to_long(&format[index],
1315 &tmpformat,
1316 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001317 index = (int)(tmpformat - format);
1318 }
1319 }
1320 else if (dots == 1) /* Base */
1321 {
1322 dots++;
1323
1324 /* After the second dot we have the base */
1325 flags |= FLAGS_BASE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001326 if ((QUALIFIER_STAR == format[index])
1327#if defined(QUALIFIER_PARAM)
1328 || (QUALIFIER_PARAM == format[index])
1329#endif
1330 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001331 {
1332 index++;
1333 flags |= FLAGS_BASE_PARAMETER;
1334 base = TrioGetPosition(format, &index);
1335 if (base == NO_POSITION)
1336 {
1337 parameterPosition++;
1338 if (positional)
1339 base = parameterPosition;
1340 else
1341 {
1342 base = currentParam;
1343 currentParam = base + 1;
1344 }
1345 }
1346 else
1347 {
1348 if (! positional)
1349 currentParam = base + 1;
1350 if (base > maxParam)
1351 maxParam = base;
1352 }
1353 if (currentParam > maxParam)
1354 maxParam = currentParam;
1355 }
1356 else
1357 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001358 base = trio_to_long(&format[index],
1359 &tmpformat,
1360 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001361 if (base > MAX_BASE)
1362 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1363 index = (int)(tmpformat - format);
1364 }
1365 }
1366 else
1367 {
1368 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1369 }
1370 break; /* QUALIFIER_DOT */
1371
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001372#if defined(QUALIFIER_PARAM)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001373 case QUALIFIER_PARAM:
1374 type = TYPE_PRINT;
1375 /* FALLTHROUGH */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001376#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001377 case QUALIFIER_STAR:
1378 /* This has different meanings for print and scan */
1379 if (TYPE_PRINT == type)
1380 {
1381 /* Read with from parameter */
1382 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1383 width = TrioGetPosition(format, &index);
1384 if (width == NO_POSITION)
1385 {
1386 parameterPosition++;
1387 if (positional)
1388 width = parameterPosition;
1389 else
1390 {
1391 width = currentParam;
1392 currentParam = width + 1;
1393 }
1394 }
1395 else
1396 {
1397 if (! positional)
1398 currentParam = width + 1;
1399 if (width > maxParam)
1400 maxParam = width;
1401 }
1402 if (currentParam > maxParam)
1403 maxParam = currentParam;
1404 }
1405 else
1406 {
1407 /* Scan, but do not store result */
1408 flags |= FLAGS_IGNORE;
1409 }
1410
1411 break; /* QUALIFIER_STAR */
1412
1413 case '0':
1414 if (! (flags & FLAGS_LEFTADJUST))
1415 flags |= FLAGS_NILPADDING;
1416 /* FALLTHROUGH */
1417 case '1': case '2': case '3': case '4':
1418 case '5': case '6': case '7': case '8': case '9':
1419 flags |= FLAGS_WIDTH;
1420 /* &format[index - 1] is used to "rewind" the read
1421 * character from format
1422 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001423 width = trio_to_long(&format[index - 1],
1424 &tmpformat,
1425 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001426 index = (int)(tmpformat - format);
1427 break;
1428
1429 case QUALIFIER_SHORT:
1430 if (flags & FLAGS_SHORTSHORT)
1431 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1432 else if (flags & FLAGS_SHORT)
1433 flags |= FLAGS_SHORTSHORT;
1434 else
1435 flags |= FLAGS_SHORT;
1436 break;
1437
1438 case QUALIFIER_LONG:
1439 if (flags & FLAGS_QUAD)
1440 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1441 else if (flags & FLAGS_LONG)
1442 flags |= FLAGS_QUAD;
1443 else
1444 flags |= FLAGS_LONG;
1445 break;
1446
1447 case QUALIFIER_LONG_UPPER:
1448 flags |= FLAGS_LONGDOUBLE;
1449 break;
1450
1451#if defined(QUALIFIER_SIZE_T)
1452 case QUALIFIER_SIZE_T:
1453 flags |= FLAGS_SIZE_T;
1454 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001455 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001456 flags |= FLAGS_QUAD;
1457 else if (sizeof(size_t) == sizeof(long))
1458 flags |= FLAGS_LONG;
1459 break;
1460#endif
1461
1462#if defined(QUALIFIER_PTRDIFF_T)
1463 case QUALIFIER_PTRDIFF_T:
1464 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001465 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001466 flags |= FLAGS_QUAD;
1467 else if (sizeof(ptrdiff_t) == sizeof(long))
1468 flags |= FLAGS_LONG;
1469 break;
1470#endif
1471
1472#if defined(QUALIFIER_INTMAX_T)
1473 case QUALIFIER_INTMAX_T:
1474 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001475 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001476 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001477 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001478 flags |= FLAGS_LONG;
1479 break;
1480#endif
1481
1482#if defined(QUALIFIER_QUAD)
1483 case QUALIFIER_QUAD:
1484 flags |= FLAGS_QUAD;
1485 break;
1486#endif
1487
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001488#if defined(QUALIFIER_FIXED_SIZE)
1489 case QUALIFIER_FIXED_SIZE:
1490 if (flags & FLAGS_FIXED_SIZE)
1491 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1492
1493 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1494 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1495 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1496
1497 if ((format[index] == '6') &&
1498 (format[index + 1] == '4'))
1499 {
1500 varsize = sizeof(trio_int64_t);
1501 index += 2;
1502 }
1503 else if ((format[index] == '3') &&
1504 (format[index + 1] == '2'))
1505 {
1506 varsize = sizeof(trio_int32_t);
1507 index += 2;
1508 }
1509 else if ((format[index] == '1') &&
1510 (format[index + 1] == '6'))
1511 {
1512 varsize = sizeof(trio_int16_t);
1513 index += 2;
1514 }
1515 else if (format[index] == '8')
1516 {
1517 varsize = sizeof(trio_int8_t);
1518 index++;
1519 }
1520 else
1521 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1522
1523 flags |= FLAGS_FIXED_SIZE;
1524 break;
1525#endif
1526
Daniel Veillard92ad2102001-03-27 12:47:33 +00001527#if defined(QUALIFIER_WIDECHAR)
1528 case QUALIFIER_WIDECHAR:
1529 flags |= FLAGS_WIDECHAR;
1530 break;
1531#endif
1532
1533#if defined(QUALIFIER_SIZE_T_UPPER)
1534 case QUALIFIER_SIZE_T_UPPER:
1535 break;
1536#endif
1537
1538#if defined(QUALIFIER_QUOTE)
1539 case QUALIFIER_QUOTE:
1540 flags |= FLAGS_QUOTE;
1541 break;
1542#endif
1543
1544#if defined(QUALIFIER_STICKY)
1545 case QUALIFIER_STICKY:
1546 flags |= FLAGS_STICKY;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001547 gotSticky = TRUE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001548 break;
1549#endif
1550
1551#if defined(QUALIFIER_VARSIZE)
1552 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001553 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001554 parameterPosition++;
1555 if (positional)
1556 varsize = parameterPosition;
1557 else
1558 {
1559 varsize = currentParam;
1560 currentParam = varsize + 1;
1561 }
1562 if (currentParam > maxParam)
1563 maxParam = currentParam;
1564 break;
1565#endif
1566
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001567#if defined(QUALIFIER_ROUNDING_UPPER)
1568 case QUALIFIER_ROUNDING_UPPER:
1569 flags |= FLAGS_ROUNDING;
1570 break;
1571#endif
1572
Daniel Veillard92ad2102001-03-27 12:47:33 +00001573 default:
1574 /* Bail out completely to make the error more obvious */
1575 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1576 }
1577 } /* while qualifier */
1578
Bjorn Reese70a9da52001-04-21 16:57:29 +00001579 /*
1580 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001581 * read later.
1582 */
1583 if (flags & FLAGS_WIDTH_PARAMETER)
1584 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001585 usedEntries[width] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001586 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001587 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001588 indices[width] = pos;
1589 width = pos++;
1590 }
1591 if (flags & FLAGS_PRECISION_PARAMETER)
1592 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001593 usedEntries[precision] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001594 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001595 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001596 indices[precision] = pos;
1597 precision = pos++;
1598 }
1599 if (flags & FLAGS_BASE_PARAMETER)
1600 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001601 usedEntries[base] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001602 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001603 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001604 indices[base] = pos;
1605 base = pos++;
1606 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001607 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001608 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001609 usedEntries[varsize] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001610 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001611 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001612 indices[varsize] = pos;
1613 varsize = pos++;
1614 }
1615
1616 indices[currentParam] = pos;
1617
1618 switch (format[index++])
1619 {
1620#if defined(SPECIFIER_CHAR_UPPER)
1621 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001622 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001623 /* FALLTHROUGH */
1624#endif
1625 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001626 if (flags & FLAGS_LONG)
1627 flags |= FLAGS_WIDECHAR;
1628 else if (flags & FLAGS_SHORT)
1629 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001630 parameters[pos].type = FORMAT_CHAR;
1631 break;
1632
1633#if defined(SPECIFIER_STRING_UPPER)
1634 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001635 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001636 /* FALLTHROUGH */
1637#endif
1638 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001639 if (flags & FLAGS_LONG)
1640 flags |= FLAGS_WIDECHAR;
1641 else if (flags & FLAGS_SHORT)
1642 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001643 parameters[pos].type = FORMAT_STRING;
1644 break;
1645
1646 case SPECIFIER_GROUP:
1647 if (TYPE_SCAN == type)
1648 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001649 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001650 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001651 if (format[index] == QUALIFIER_CIRCUMFLEX)
1652 index++;
1653 if (format[index] == SPECIFIER_UNGROUP)
1654 index++;
1655 if (format[index] == QUALIFIER_MINUS)
1656 index++;
1657 /* Skip nested brackets */
1658 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001659 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001660 if (format[index] == SPECIFIER_GROUP)
1661 {
1662 depth++;
1663 }
1664 else if (format[index] == SPECIFIER_UNGROUP)
1665 {
1666 if (--depth <= 0)
1667 {
1668 index++;
1669 break;
1670 }
1671 }
1672 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001673 }
1674 }
1675 break;
1676
1677 case SPECIFIER_INTEGER:
1678 parameters[pos].type = FORMAT_INT;
1679 break;
1680
1681 case SPECIFIER_UNSIGNED:
1682 flags |= FLAGS_UNSIGNED;
1683 parameters[pos].type = FORMAT_INT;
1684 break;
1685
1686 case SPECIFIER_DECIMAL:
1687 /* Disable base modifier */
1688 flags &= ~FLAGS_BASE_PARAMETER;
1689 base = BASE_DECIMAL;
1690 parameters[pos].type = FORMAT_INT;
1691 break;
1692
1693 case SPECIFIER_OCTAL:
1694 flags &= ~FLAGS_BASE_PARAMETER;
1695 base = BASE_OCTAL;
1696 parameters[pos].type = FORMAT_INT;
1697 break;
1698
1699#if defined(SPECIFIER_BINARY)
1700 case SPECIFIER_BINARY_UPPER:
1701 flags |= FLAGS_UPPER;
1702 /* FALLTHROUGH */
1703 case SPECIFIER_BINARY:
1704 flags |= FLAGS_NILPADDING;
1705 flags &= ~FLAGS_BASE_PARAMETER;
1706 base = BASE_BINARY;
1707 parameters[pos].type = FORMAT_INT;
1708 break;
1709#endif
1710
1711 case SPECIFIER_HEX_UPPER:
1712 flags |= FLAGS_UPPER;
1713 /* FALLTHROUGH */
1714 case SPECIFIER_HEX:
1715 flags |= FLAGS_UNSIGNED;
1716 flags &= ~FLAGS_BASE_PARAMETER;
1717 base = BASE_HEX;
1718 parameters[pos].type = FORMAT_INT;
1719 break;
1720
1721 case SPECIFIER_FLOAT_E_UPPER:
1722 flags |= FLAGS_UPPER;
1723 /* FALLTHROUGH */
1724 case SPECIFIER_FLOAT_E:
1725 flags |= FLAGS_FLOAT_E;
1726 parameters[pos].type = FORMAT_DOUBLE;
1727 break;
1728
1729 case SPECIFIER_FLOAT_G_UPPER:
1730 flags |= FLAGS_UPPER;
1731 /* FALLTHROUGH */
1732 case SPECIFIER_FLOAT_G:
1733 flags |= FLAGS_FLOAT_G;
1734 parameters[pos].type = FORMAT_DOUBLE;
1735 break;
1736
1737 case SPECIFIER_FLOAT_F_UPPER:
1738 flags |= FLAGS_UPPER;
1739 /* FALLTHROUGH */
1740 case SPECIFIER_FLOAT_F:
1741 parameters[pos].type = FORMAT_DOUBLE;
1742 break;
1743
1744 case SPECIFIER_POINTER:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001745 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1746 flags |= FLAGS_QUAD;
1747 else if (sizeof(trio_pointer_t) == sizeof(long))
1748 flags |= FLAGS_LONG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001749 parameters[pos].type = FORMAT_POINTER;
1750 break;
1751
1752 case SPECIFIER_COUNT:
1753 parameters[pos].type = FORMAT_COUNT;
1754 break;
1755
1756#if defined(SPECIFIER_HEXFLOAT)
1757# if defined(SPECIFIER_HEXFLOAT_UPPER)
1758 case SPECIFIER_HEXFLOAT_UPPER:
1759 flags |= FLAGS_UPPER;
1760 /* FALLTHROUGH */
1761# endif
1762 case SPECIFIER_HEXFLOAT:
1763 base = BASE_HEX;
1764 parameters[pos].type = FORMAT_DOUBLE;
1765 break;
1766#endif
1767
1768#if defined(FORMAT_ERRNO)
1769 case SPECIFIER_ERRNO:
1770 parameters[pos].type = FORMAT_ERRNO;
1771 break;
1772#endif
1773
Bjorn Reese70a9da52001-04-21 16:57:29 +00001774#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1775 case SPECIFIER_USER_DEFINED_BEGIN:
1776 {
1777 unsigned int max;
1778 int without_namespace = TRUE;
1779
1780 parameters[pos].type = FORMAT_USER_DEFINED;
1781 parameters[pos].user_name[0] = NIL;
1782 tmpformat = (char *)&format[index];
1783
1784 while ((ch = format[index]))
1785 {
1786 index++;
1787 if (ch == SPECIFIER_USER_DEFINED_END)
1788 {
1789 if (without_namespace)
1790 {
1791 /* We must get the handle first */
1792 parameters[pos].type = FORMAT_PARAMETER;
1793 parameters[pos].indexAfterSpecifier = index;
1794 parameters[pos].flags = FLAGS_USER_DEFINED;
1795 /* Adjust parameters for insertion of new one */
1796 pos++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001797 usedEntries[currentParam] += 1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001798 parameters[pos].type = FORMAT_USER_DEFINED;
1799 currentParam++;
1800 indices[currentParam] = pos;
1801 if (currentParam > maxParam)
1802 maxParam = currentParam;
1803 }
1804 /* Copy the user data */
1805 max = (unsigned int)(&format[index] - tmpformat);
1806 if (max > MAX_USER_DATA)
1807 max = MAX_USER_DATA;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001808 trio_copy_max(parameters[pos].user_data,
1809 max,
1810 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001811 break; /* while */
1812 }
1813 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1814 {
1815 without_namespace = FALSE;
1816 /* Copy the namespace for later looking-up */
1817 max = (int)(&format[index] - tmpformat);
1818 if (max > MAX_USER_NAME)
1819 max = MAX_USER_NAME;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001820 trio_copy_max(parameters[pos].user_name,
1821 max,
1822 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001823 tmpformat = (char *)&format[index];
1824 }
1825 }
1826 if (ch != SPECIFIER_USER_DEFINED_END)
1827 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1828 }
1829 break;
1830#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1831
Daniel Veillard92ad2102001-03-27 12:47:33 +00001832 default:
1833 /* Bail out completely to make the error more obvious */
1834 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1835 }
1836
Daniel Veillard92ad2102001-03-27 12:47:33 +00001837 /* Count the number of times this entry has been used */
1838 usedEntries[currentParam] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001839
1840 /* Find last sticky parameters */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001841 if (gotSticky && !(flags & FLAGS_STICKY))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001842 {
1843 for (i = pos - 1; i >= 0; i--)
1844 {
1845 if (parameters[i].type == FORMAT_PARAMETER)
1846 continue;
1847 if ((parameters[i].flags & FLAGS_STICKY) &&
1848 (parameters[i].type == parameters[pos].type))
1849 {
1850 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001851 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001852 if (width == NO_WIDTH)
1853 width = parameters[i].width;
1854 if (precision == NO_PRECISION)
1855 precision = parameters[i].precision;
1856 if (base == NO_BASE)
1857 base = parameters[i].base;
1858 break;
1859 }
1860 }
1861 }
1862
1863 parameters[pos].indexAfterSpecifier = index;
1864 parameters[pos].flags = flags;
1865 parameters[pos].width = width;
1866 parameters[pos].precision = precision;
1867 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1868 parameters[pos].varsize = varsize;
1869 pos++;
1870
Bjorn Reese70a9da52001-04-21 16:57:29 +00001871 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001872 parameterPosition++;
1873
1874 } /* if identifier */
1875
1876 } /* while format characters left */
1877
1878 for (num = 0; num <= maxParam; num++)
1879 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001880 if (usedEntries[num] != 1)
1881 {
1882 if (usedEntries[num] == 0) /* gap detected */
1883 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1884 else /* double references detected */
1885 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1886 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001887
1888 i = indices[num];
1889
Bjorn Reese70a9da52001-04-21 16:57:29 +00001890 /*
1891 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001892 * so it makes no sense to check the ignore flag (besides,
1893 * the flags variable is not set for that particular type)
1894 */
1895 if ((parameters[i].type != FORMAT_PARAMETER) &&
1896 (parameters[i].flags & FLAGS_IGNORE))
1897 continue; /* for all arguments */
1898
Bjorn Reese70a9da52001-04-21 16:57:29 +00001899 /*
1900 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001901 * default argument promotions:
1902 *
1903 * char = int
1904 * short = int
1905 * unsigned char = unsigned int
1906 * unsigned short = unsigned int
1907 * float = double
1908 *
1909 * In addition to the ANSI C89 these types are read (the
1910 * default argument promotions of C99 has not been
1911 * considered yet)
1912 *
1913 * long long
1914 * long double
1915 * size_t
1916 * ptrdiff_t
1917 * intmax_t
1918 */
1919 switch (parameters[i].type)
1920 {
1921 case FORMAT_GROUP:
1922 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001923#if TRIO_WIDECHAR
1924 if (flags & FLAGS_WIDECHAR)
1925 {
1926 parameters[i].data.wstring = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001927 ? va_arg(*arglist, trio_wchar_t *)
1928 : (trio_wchar_t *)(argarray[num]);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001929 }
1930 else
1931#endif
1932 {
1933 parameters[i].data.string = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001934 ? va_arg(*arglist, char *)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001935 : (char *)(argarray[num]);
1936 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001937 break;
1938
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001939#if defined(FORMAT_USER_DEFINED)
1940 case FORMAT_USER_DEFINED:
1941#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001942 case FORMAT_POINTER:
1943 case FORMAT_COUNT:
1944 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001945 parameters[i].data.pointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001946 ? va_arg(*arglist, trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00001947 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001948 break;
1949
1950 case FORMAT_CHAR:
1951 case FORMAT_INT:
1952 if (TYPE_SCAN == type)
1953 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001954 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001955 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001956 (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001957 else
1958 {
1959 if (parameters[i].type == FORMAT_CHAR)
1960 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001961 (trio_pointer_t)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001962 else if (parameters[i].flags & FLAGS_SHORT)
1963 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001964 (trio_pointer_t)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001965 else
1966 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001967 (trio_pointer_t)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001968 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001969 }
1970 else
1971 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001972#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
Bjorn Reese026d29f2002-01-19 15:40:18 +00001973 if (parameters[i].flags
1974 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001975 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001976 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1977 {
1978 /*
1979 * Variable sizes are mapped onto the fixed sizes, in
1980 * accordance with integer promotion.
1981 *
1982 * Please note that this may not be portable, as we
1983 * only guess the size, not the layout of the numbers.
1984 * For example, if int is little-endian, and long is
1985 * big-endian, then this will fail.
1986 */
1987 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1988 }
1989 else
1990 {
1991 /* Used for the I<bits> modifiers */
1992 varsize = parameters[i].varsize;
1993 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001994 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001995
Daniel Veillard92ad2102001-03-27 12:47:33 +00001996 if (varsize <= (int)sizeof(int))
1997 ;
1998 else if (varsize <= (int)sizeof(long))
1999 parameters[i].flags |= FLAGS_LONG;
2000#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002001 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002002 parameters[i].flags |= FLAGS_QUAD;
2003 else
2004 parameters[i].flags |= FLAGS_INTMAX_T;
2005#else
2006 else
2007 parameters[i].flags |= FLAGS_QUAD;
2008#endif
2009 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002010#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002011#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2012 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002013 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002014 ? (trio_uintmax_t)va_arg(*arglist, size_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002015 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002016 else
2017#endif
2018#if defined(QUALIFIER_PTRDIFF_T)
2019 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002020 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002021 ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002022 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002023 else
2024#endif
2025#if defined(QUALIFIER_INTMAX_T)
2026 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002027 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002028 ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002029 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002030 else
2031#endif
2032 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002033 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002034 ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002035 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002036 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002037 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002038 ? (trio_uintmax_t)va_arg(*arglist, long)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002039 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002040 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002041 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002042 if (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002043 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002044 else
2045 {
2046 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002047 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002048 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002049 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002050 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002051 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002052 }
2053 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002054 }
2055 break;
2056
2057 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002058 /*
2059 * The parameter for the user-defined specifier is a pointer,
2060 * whereas the rest (width, precision, base) uses an integer.
2061 */
2062 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002063 parameters[i].data.pointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002064 ? va_arg(*arglist, trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00002065 : argarray[num];
2066 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002067 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002068 ? (trio_uintmax_t)va_arg(*arglist, int)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002069 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002070 break;
2071
2072 case FORMAT_DOUBLE:
2073 if (TYPE_SCAN == type)
2074 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002075 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002076 parameters[i].data.longdoublePointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002077 ? va_arg(*arglist, trio_long_double_t *)
2078 : (trio_long_double_t *)argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002079 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002080 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002081 if (parameters[i].flags & FLAGS_LONG)
2082 parameters[i].data.doublePointer = (argarray == NULL)
2083 ? va_arg(*arglist, double *)
2084 : (double *)argarray[num];
2085 else
2086 parameters[i].data.doublePointer = (argarray == NULL)
2087 ? (double *)va_arg(*arglist, float *)
2088 : (double *)((float *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002089 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002090 }
2091 else
2092 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002093 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002094 parameters[i].data.longdoubleNumber = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002095 ? va_arg(*arglist, trio_long_double_t)
2096 : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002097 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002098 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002099 if (argarray == NULL)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002100 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002101 (trio_long_double_t)va_arg(*arglist, double);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002102 else
2103 {
2104 if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002105 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002106 (trio_long_double_t)(*((float *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002107 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00002108 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002109 (trio_long_double_t)(*((double *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002110 }
2111 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002112 }
2113 break;
2114
2115#if defined(FORMAT_ERRNO)
2116 case FORMAT_ERRNO:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002117 parameters[i].data.errorNumber = save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002118 break;
2119#endif
2120
2121 default:
2122 break;
2123 }
2124 } /* for all specifiers */
2125 return num;
2126}
2127
2128
2129/*************************************************************************
2130 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00002131 * FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00002132 *
2133 ************************************************************************/
2134
2135
2136/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002137 * TrioWriteNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00002138 *
2139 * Description:
2140 * Output a number.
2141 * The complexity of this function is a result of the complexity
2142 * of the dependencies of the flags.
2143 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002144TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002145TrioWriteNumber
2146TRIO_ARGS6((self, number, flags, width, precision, base),
2147 trio_class_t *self,
2148 trio_uintmax_t number,
2149 unsigned long flags,
2150 int width,
2151 int precision,
2152 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002153{
2154 BOOLEAN_T isNegative;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002155 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002156 char *bufferend;
2157 char *pointer;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002158 TRIO_CONST char *digits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002159 int i;
2160 int length;
2161 char *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002162 int count;
2163
2164 assert(VALID(self));
2165 assert(VALID(self->OutStream));
Bjorn Reese026d29f2002-01-19 15:40:18 +00002166 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002167
Bjorn Reese70a9da52001-04-21 16:57:29 +00002168 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002169 if (base == NO_BASE)
2170 base = BASE_DECIMAL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002171
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002172 isNegative = (flags & FLAGS_UNSIGNED)
2173 ? FALSE
Bjorn Reese026d29f2002-01-19 15:40:18 +00002174 : ((trio_intmax_t)number < 0);
2175 if (isNegative)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002176 number = -((trio_intmax_t)number);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002177
2178 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002179 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002180 else if (flags & FLAGS_LONG)
2181 number &= (unsigned long)-1;
2182 else
2183 number &= (unsigned int)-1;
2184
2185 /* Build number */
2186 pointer = bufferend = &buffer[sizeof(buffer) - 1];
2187 *pointer-- = NIL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002188 for (i = 1; i < (int)sizeof(buffer); i++)
2189 {
2190 *pointer-- = digits[number % base];
2191 number /= base;
2192 if (number == 0)
2193 break;
2194
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002195 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002196 {
2197 /*
2198 * We are building the number from the least significant
2199 * to the most significant digit, so we have to copy the
2200 * thousand separator backwards
2201 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002202 length = internalThousandSeparatorLength;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002203 if (((int)(pointer - buffer) - length) > 0)
2204 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002205 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002206 while (length-- > 0)
2207 *pointer-- = *p--;
2208 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002209 }
2210 }
2211
2212 /* Adjust width */
2213 width -= (bufferend - pointer) - 1;
2214
2215 /* Adjust precision */
2216 if (NO_PRECISION != precision)
2217 {
2218 precision -= (bufferend - pointer) - 1;
2219 if (precision < 0)
2220 precision = 0;
2221 flags |= FLAGS_NILPADDING;
2222 }
2223
2224 /* Adjust width further */
2225 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2226 width--;
2227 if (flags & FLAGS_ALTERNATIVE)
2228 {
2229 switch (base)
2230 {
2231 case BASE_BINARY:
2232 case BASE_HEX:
2233 width -= 2;
2234 break;
2235 case BASE_OCTAL:
2236 width--;
2237 break;
2238 default:
2239 break;
2240 }
2241 }
2242
2243 /* Output prefixes spaces if needed */
2244 if (! ((flags & FLAGS_LEFTADJUST) ||
2245 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2246 {
2247 count = (precision == NO_PRECISION) ? 0 : precision;
2248 while (width-- > count)
2249 self->OutStream(self, CHAR_ADJUST);
2250 }
2251
2252 /* width has been adjusted for signs and alternatives */
2253 if (isNegative)
2254 self->OutStream(self, '-');
2255 else if (flags & FLAGS_SHOWSIGN)
2256 self->OutStream(self, '+');
2257 else if (flags & FLAGS_SPACE)
2258 self->OutStream(self, ' ');
2259
2260 if (flags & FLAGS_ALTERNATIVE)
2261 {
2262 switch (base)
2263 {
2264 case BASE_BINARY:
2265 self->OutStream(self, '0');
2266 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2267 break;
2268
2269 case BASE_OCTAL:
2270 self->OutStream(self, '0');
2271 break;
2272
2273 case BASE_HEX:
2274 self->OutStream(self, '0');
2275 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2276 break;
2277
2278 default:
2279 break;
2280 } /* switch base */
2281 }
2282
2283 /* Output prefixed zero padding if needed */
2284 if (flags & FLAGS_NILPADDING)
2285 {
2286 if (precision == NO_PRECISION)
2287 precision = width;
2288 while (precision-- > 0)
2289 {
2290 self->OutStream(self, '0');
2291 width--;
2292 }
2293 }
2294
2295 /* Output the number itself */
2296 while (*(++pointer))
2297 {
2298 self->OutStream(self, *pointer);
2299 }
2300
2301 /* Output trailing spaces if needed */
2302 if (flags & FLAGS_LEFTADJUST)
2303 {
2304 while (width-- > 0)
2305 self->OutStream(self, CHAR_ADJUST);
2306 }
2307}
2308
2309/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002310 * TrioWriteStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002311 *
2312 * Description:
2313 * Output a single character of a string
2314 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002315TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002316TrioWriteStringCharacter
2317TRIO_ARGS3((self, ch, flags),
2318 trio_class_t *self,
2319 int ch,
2320 unsigned long flags)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002321{
2322 if (flags & FLAGS_ALTERNATIVE)
2323 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002324 if (! isprint(ch))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002325 {
2326 /*
2327 * Non-printable characters are converted to C escapes or
2328 * \number, if no C escape exists.
2329 */
2330 self->OutStream(self, CHAR_BACKSLASH);
2331 switch (ch)
2332 {
2333 case '\007': self->OutStream(self, 'a'); break;
2334 case '\b': self->OutStream(self, 'b'); break;
2335 case '\f': self->OutStream(self, 'f'); break;
2336 case '\n': self->OutStream(self, 'n'); break;
2337 case '\r': self->OutStream(self, 'r'); break;
2338 case '\t': self->OutStream(self, 't'); break;
2339 case '\v': self->OutStream(self, 'v'); break;
2340 case '\\': self->OutStream(self, '\\'); break;
2341 default:
2342 self->OutStream(self, 'x');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002343 TrioWriteNumber(self, (trio_uintmax_t)ch,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002344 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2345 2, 2, BASE_HEX);
2346 break;
2347 }
2348 }
2349 else if (ch == CHAR_BACKSLASH)
2350 {
2351 self->OutStream(self, CHAR_BACKSLASH);
2352 self->OutStream(self, CHAR_BACKSLASH);
2353 }
2354 else
2355 {
2356 self->OutStream(self, ch);
2357 }
2358 }
2359 else
2360 {
2361 self->OutStream(self, ch);
2362 }
2363}
2364
2365/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002366 * TrioWriteString
Daniel Veillard92ad2102001-03-27 12:47:33 +00002367 *
2368 * Description:
2369 * Output a string
2370 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002371TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002372TrioWriteString
2373TRIO_ARGS5((self, string, flags, width, precision),
2374 trio_class_t *self,
2375 TRIO_CONST char *string,
2376 unsigned long flags,
2377 int width,
2378 int precision)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002379{
2380 int length;
2381 int ch;
2382
2383 assert(VALID(self));
2384 assert(VALID(self->OutStream));
2385
2386 if (string == NULL)
2387 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002388 string = internalNullString;
2389 length = sizeof(internalNullString) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002390 /* Disable quoting for the null pointer */
2391 flags &= (~FLAGS_QUOTE);
2392 width = 0;
2393 }
2394 else
2395 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002396 length = trio_length(string);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002397 }
2398 if ((NO_PRECISION != precision) &&
2399 (precision < length))
2400 {
2401 length = precision;
2402 }
2403 width -= length;
2404
2405 if (flags & FLAGS_QUOTE)
2406 self->OutStream(self, CHAR_QUOTE);
2407
2408 if (! (flags & FLAGS_LEFTADJUST))
2409 {
2410 while (width-- > 0)
2411 self->OutStream(self, CHAR_ADJUST);
2412 }
2413
2414 while (length-- > 0)
2415 {
2416 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002417 ch = (int)((unsigned char)(*string++));
2418 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002419 }
2420
2421 if (flags & FLAGS_LEFTADJUST)
2422 {
2423 while (width-- > 0)
2424 self->OutStream(self, CHAR_ADJUST);
2425 }
2426 if (flags & FLAGS_QUOTE)
2427 self->OutStream(self, CHAR_QUOTE);
2428}
2429
2430/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002431 * TrioWriteWideStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002432 *
2433 * Description:
2434 * Output a wide string as a multi-byte sequence
2435 */
2436#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002437TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002438TrioWriteWideStringCharacter
2439TRIO_ARGS4((self, wch, flags, width),
2440 trio_class_t *self,
2441 trio_wchar_t wch,
2442 unsigned long flags,
2443 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002444{
2445 int size;
2446 int i;
2447 int ch;
2448 char *string;
2449 char buffer[MB_LEN_MAX + 1];
2450
2451 if (width == NO_WIDTH)
2452 width = sizeof(buffer);
2453
2454 size = wctomb(buffer, wch);
2455 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2456 return 0;
2457
2458 string = buffer;
2459 i = size;
2460 while ((width >= i) && (width-- > 0) && (i-- > 0))
2461 {
2462 /* The ctype parameters must be an unsigned char (or EOF) */
2463 ch = (int)((unsigned char)(*string++));
2464 TrioWriteStringCharacter(self, ch, flags);
2465 }
2466 return size;
2467}
2468#endif /* TRIO_WIDECHAR */
2469
2470/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002471 * TrioWriteWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002472 *
2473 * Description:
2474 * Output a wide character string as a multi-byte string
2475 */
2476#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002477TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002478TrioWriteWideString
2479TRIO_ARGS5((self, wstring, flags, width, precision),
2480 trio_class_t *self,
2481 TRIO_CONST trio_wchar_t *wstring,
2482 unsigned long flags,
2483 int width,
2484 int precision)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002485{
2486 int length;
2487 int size;
2488
2489 assert(VALID(self));
2490 assert(VALID(self->OutStream));
2491
2492#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002493 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002494#endif
2495
2496 if (wstring == NULL)
2497 {
2498 TrioWriteString(self, NULL, flags, width, precision);
2499 return;
2500 }
2501
2502 if (NO_PRECISION == precision)
2503 {
2504 length = INT_MAX;
2505 }
2506 else
2507 {
2508 length = precision;
2509 width -= length;
2510 }
2511
2512 if (flags & FLAGS_QUOTE)
2513 self->OutStream(self, CHAR_QUOTE);
2514
2515 if (! (flags & FLAGS_LEFTADJUST))
2516 {
2517 while (width-- > 0)
2518 self->OutStream(self, CHAR_ADJUST);
2519 }
2520
2521 while (length > 0)
2522 {
2523 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2524 if (size == 0)
2525 break; /* while */
2526 length -= size;
2527 }
2528
2529 if (flags & FLAGS_LEFTADJUST)
2530 {
2531 while (width-- > 0)
2532 self->OutStream(self, CHAR_ADJUST);
2533 }
2534 if (flags & FLAGS_QUOTE)
2535 self->OutStream(self, CHAR_QUOTE);
2536}
2537#endif /* TRIO_WIDECHAR */
2538
2539/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002540 * TrioWriteDouble
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002541 *
2542 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2543 *
2544 * "5.2.4.2.2 paragraph #4
2545 *
2546 * The accuracy [...] is implementation defined, as is the accuracy
2547 * of the conversion between floating-point internal representations
2548 * and string representations performed by the libray routine in
2549 * <stdio.h>"
2550 */
2551/* FIXME: handle all instances of constant long-double number (L)
2552 * and *l() math functions.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002553 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002554TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002555TrioWriteDouble
2556TRIO_ARGS6((self, number, flags, width, precision, base),
2557 trio_class_t *self,
2558 trio_long_double_t number,
2559 unsigned long flags,
2560 int width,
2561 int precision,
2562 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002563{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002564 trio_long_double_t integerNumber;
2565 trio_long_double_t fractionNumber;
2566 trio_long_double_t workNumber;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002567 int integerDigits;
2568 int fractionDigits;
2569 int exponentDigits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002570 int baseDigits;
2571 int integerThreshold;
2572 int fractionThreshold;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002573 int expectedWidth;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002574 int exponent = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002575 unsigned int uExponent = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002576 int exponentBase;
2577 trio_long_double_t dblBase;
2578 trio_long_double_t dblIntegerBase;
2579 trio_long_double_t dblFractionBase;
2580 trio_long_double_t integerAdjust;
2581 trio_long_double_t fractionAdjust;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002582 BOOLEAN_T isNegative;
2583 BOOLEAN_T isExponentNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002584 BOOLEAN_T requireTwoDigitExponent;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002585 BOOLEAN_T isHex;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002586 TRIO_CONST char *digits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002587 char *groupingPointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002588 int i;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002589 int index;
2590 BOOLEAN_T hasOnlyZeroes;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002591 int zeroes = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002592 register int trailingZeroes;
2593 BOOLEAN_T keepTrailingZeroes;
2594 BOOLEAN_T keepDecimalPoint;
2595 trio_long_double_t epsilon;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002596
2597 assert(VALID(self));
2598 assert(VALID(self->OutStream));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002599 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002600
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002601 /* Determine sign and look for special quantities */
2602 switch (trio_fpclassify_and_signbit(number, &isNegative))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002603 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002604 case TRIO_FP_NAN:
Daniel Veillard92ad2102001-03-27 12:47:33 +00002605 TrioWriteString(self,
2606 (flags & FLAGS_UPPER)
2607 ? NAN_UPPER
2608 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002609 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002610 return;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002611
2612 case TRIO_FP_INFINITE:
2613 if (isNegative)
2614 {
2615 /* Negative infinity */
2616 TrioWriteString(self,
2617 (flags & FLAGS_UPPER)
2618 ? "-" INFINITE_UPPER
2619 : "-" INFINITE_LOWER,
2620 flags, width, precision);
2621 return;
2622 }
2623 else
2624 {
2625 /* Positive infinity */
2626 TrioWriteString(self,
2627 (flags & FLAGS_UPPER)
2628 ? INFINITE_UPPER
2629 : INFINITE_LOWER,
2630 flags, width, precision);
2631 return;
2632 }
2633
2634 default:
2635 /* Finitude */
2636 break;
2637 }
2638
2639 /* Normal numbers */
2640 if (flags & FLAGS_LONGDOUBLE)
2641 {
2642 baseDigits = (base == 10)
2643 ? LDBL_DIG
2644 : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2645 epsilon = LDBL_EPSILON;
2646 }
2647 else if (flags & FLAGS_SHORT)
2648 {
2649 baseDigits = (base == BASE_DECIMAL)
2650 ? FLT_DIG
2651 : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2652 epsilon = FLT_EPSILON;
2653 }
2654 else
2655 {
2656 baseDigits = (base == BASE_DECIMAL)
2657 ? DBL_DIG
2658 : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2659 epsilon = DBL_EPSILON;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002660 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002661
Bjorn Reese70a9da52001-04-21 16:57:29 +00002662 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002663 isHex = (base == BASE_HEX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002664 if (base == NO_BASE)
2665 base = BASE_DECIMAL;
2666 dblBase = (trio_long_double_t)base;
2667 keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2668 ( (flags & FLAGS_FLOAT_G) &&
2669 !(flags & FLAGS_ALTERNATIVE) ) );
2670
2671 if (flags & FLAGS_ROUNDING)
2672 precision = baseDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002673
2674 if (precision == NO_PRECISION)
2675 precision = FLT_DIG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002676
Daniel Veillard92ad2102001-03-27 12:47:33 +00002677 if (isNegative)
2678 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002679
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002680 if (isHex)
2681 flags |= FLAGS_FLOAT_E;
2682
2683 if (flags & FLAGS_FLOAT_G)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002684 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002685 if (precision == 0)
2686 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002687
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002688 if ((number < 1.0E-4) || (number > powl(base,
2689 (trio_long_double_t)precision)))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002690 {
2691 /* Use scientific notation */
2692 flags |= FLAGS_FLOAT_E;
2693 }
2694 else if (number < 1.0)
2695 {
2696 /*
2697 * Use normal notation. If the integer part of the number is
2698 * zero, then adjust the precision to include leading fractional
2699 * zeros.
2700 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002701 workNumber = TrioLogarithm(number, base);
2702 workNumber = TRIO_FABS(workNumber);
2703 if (workNumber - floorl(workNumber) < 0.001)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002704 workNumber--;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002705 zeroes = (int)floorl(workNumber);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002706 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002707 }
2708
2709 if (flags & FLAGS_FLOAT_E)
2710 {
2711 /* Scale the number */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002712 workNumber = TrioLogarithm(number, base);
Bjorn Reese45029602001-08-21 09:23:53 +00002713 if (trio_isinf(workNumber) == -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002714 {
2715 exponent = 0;
2716 /* Undo setting */
2717 if (flags & FLAGS_FLOAT_G)
2718 flags &= ~FLAGS_FLOAT_E;
2719 }
2720 else
2721 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002722 exponent = (int)floorl(workNumber);
2723 number /= powl(dblBase, (trio_long_double_t)exponent);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002724 isExponentNegative = (exponent < 0);
2725 uExponent = (isExponentNegative) ? -exponent : exponent;
2726 /* No thousand separators */
2727 flags &= ~FLAGS_QUOTE;
2728 }
2729 }
2730
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002731 integerNumber = floorl(number);
2732 fractionNumber = number - integerNumber;
2733
Daniel Veillard92ad2102001-03-27 12:47:33 +00002734 /*
2735 * Truncated number.
2736 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002737 * Precision is number of significant digits for FLOAT_G
2738 * and number of fractional digits for others.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002739 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002740 integerDigits = (integerNumber > epsilon)
2741 ? 1 + (int)TrioLogarithm(integerNumber, base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002742 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002743 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002744 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002745 : zeroes + precision;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002746
2747 dblFractionBase = TrioPower(base, fractionDigits);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002748
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002749 workNumber = number + 0.5 / dblFractionBase;
2750 if (floorl(number) != floorl(workNumber))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002751 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002752 if (flags & FLAGS_FLOAT_E)
2753 {
2754 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002755 exponent++;
2756 isExponentNegative = (exponent < 0);
2757 uExponent = (isExponentNegative) ? -exponent : exponent;
2758 workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2759 integerNumber = floorl(workNumber);
2760 fractionNumber = workNumber - integerNumber;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002761 }
2762 else
2763 {
2764 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002765 integerNumber = floorl(number + 0.5);
2766 fractionNumber = 0.0;
2767 integerDigits = (integerNumber > epsilon)
2768 ? 1 + (int)TrioLogarithm(integerNumber, base)
2769 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002770 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002771 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002772
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002773 /* Estimate accuracy */
2774 integerAdjust = fractionAdjust = 0.5;
2775 if (flags & FLAGS_ROUNDING)
2776 {
2777 if (integerDigits > baseDigits)
2778 {
2779 integerThreshold = baseDigits;
2780 fractionDigits = 0;
2781 dblFractionBase = 1.0;
2782 fractionThreshold = 0;
2783 precision = 0; /* Disable decimal-point */
2784 integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2785 fractionAdjust = 0.0;
2786 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002787 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002788 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002789 integerThreshold = integerDigits;
2790 fractionThreshold = fractionDigits - integerThreshold;
2791 fractionAdjust = 1.0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002792 }
2793 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002794 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002795 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002796 integerThreshold = INT_MAX;
2797 fractionThreshold = INT_MAX;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002798 }
2799
Bjorn Reese70a9da52001-04-21 16:57:29 +00002800 /*
2801 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002802 * sign + integer part + thousands separators + decimal point
2803 * + fraction + exponent
2804 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002805 fractionAdjust /= dblFractionBase;
2806 hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2807 keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2808 !((precision == 0) ||
2809 (!keepTrailingZeroes && hasOnlyZeroes)) );
2810 if (flags & FLAGS_FLOAT_E)
2811 {
2812 exponentDigits = (uExponent == 0)
2813 ? 1
2814 : (int)ceil(TrioLogarithm((double)(uExponent + 1), base));
2815 }
2816 else
2817 exponentDigits = 0;
2818 requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2819
2820 expectedWidth = integerDigits + fractionDigits
2821 + (keepDecimalPoint
2822 ? internalDecimalPointLength
2823 : 0)
2824 + ((flags & FLAGS_QUOTE)
2825 ? TrioCalcThousandSeparatorLength(integerDigits)
2826 : 0);
2827 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002828 expectedWidth += sizeof("-") - 1;
2829 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002830 expectedWidth += exponentDigits +
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002831 ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002832 if (isHex)
2833 expectedWidth += sizeof("0X") - 1;
2834
2835 /* Output prefixing */
2836 if (flags & FLAGS_NILPADDING)
2837 {
2838 /* Leading zeros must be after sign */
2839 if (isNegative)
2840 self->OutStream(self, '-');
2841 else if (flags & FLAGS_SHOWSIGN)
2842 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002843 else if (flags & FLAGS_SPACE)
2844 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002845 if (isHex)
2846 {
2847 self->OutStream(self, '0');
2848 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2849 }
2850 if (!(flags & FLAGS_LEFTADJUST))
2851 {
2852 for (i = expectedWidth; i < width; i++)
2853 {
2854 self->OutStream(self, '0');
2855 }
2856 }
2857 }
2858 else
2859 {
2860 /* Leading spaces must be before sign */
2861 if (!(flags & FLAGS_LEFTADJUST))
2862 {
2863 for (i = expectedWidth; i < width; i++)
2864 {
2865 self->OutStream(self, CHAR_ADJUST);
2866 }
2867 }
2868 if (isNegative)
2869 self->OutStream(self, '-');
2870 else if (flags & FLAGS_SHOWSIGN)
2871 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002872 else if (flags & FLAGS_SPACE)
2873 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 if (isHex)
2875 {
2876 self->OutStream(self, '0');
2877 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2878 }
2879 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002880
2881 /* Output the integer part and thousand separators */
2882 dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2883 for (i = 0; i < integerDigits; i++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002884 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002885 workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2886 if (i > integerThreshold)
2887 {
2888 /* Beyond accuracy */
2889 self->OutStream(self, digits[0]);
2890 }
2891 else
2892 {
2893 self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2894 }
2895 dblIntegerBase *= dblBase;
2896
2897 if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2898 && TrioFollowedBySeparator(integerDigits - i))
2899 {
2900 for (groupingPointer = internalThousandSeparator;
2901 *groupingPointer != NIL;
2902 groupingPointer++)
2903 {
2904 self->OutStream(self, *groupingPointer);
2905 }
2906 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002907 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002908
2909 /* Insert decimal point and build the fraction part */
2910 trailingZeroes = 0;
2911
2912 if (keepDecimalPoint)
2913 {
2914 if (internalDecimalPoint)
2915 {
2916 self->OutStream(self, internalDecimalPoint);
2917 }
2918 else
2919 {
2920 for (i = 0; i < internalDecimalPointLength; i++)
2921 {
2922 self->OutStream(self, internalDecimalPointString[i]);
2923 }
2924 }
2925 }
2926
2927 for (i = 0; i < fractionDigits; i++)
2928 {
2929 if ((integerDigits > integerThreshold) || (i > fractionThreshold))
2930 {
2931 /* Beyond accuracy */
2932 trailingZeroes++;
2933 }
2934 else
2935 {
2936 fractionNumber *= dblBase;
2937 fractionAdjust *= dblBase;
2938 workNumber = floorl(fractionNumber + fractionAdjust);
2939 fractionNumber -= workNumber;
2940 index = (int)fmodl(workNumber, dblBase);
2941 if (index == 0)
2942 {
2943 trailingZeroes++;
2944 }
2945 else
2946 {
2947 while (trailingZeroes > 0)
2948 {
2949 /* Not trailing zeroes after all */
2950 self->OutStream(self, digits[0]);
2951 trailingZeroes--;
2952 }
2953 self->OutStream(self, digits[index]);
2954 }
2955 }
2956 }
2957
2958 if (keepTrailingZeroes)
2959 {
2960 while (trailingZeroes > 0)
2961 {
2962 self->OutStream(self, digits[0]);
2963 trailingZeroes--;
2964 }
2965 }
2966
Daniel Veillard92ad2102001-03-27 12:47:33 +00002967 /* Output exponent */
2968 if (exponentDigits > 0)
2969 {
2970 self->OutStream(self,
2971 isHex
2972 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2973 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2974 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002975
2976 /* The exponent must contain at least two digits */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002977 if (requireTwoDigitExponent)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002978 self->OutStream(self, '0');
2979
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002980 exponentBase = (int)TrioPower(base, exponentDigits - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002981 for (i = 0; i < exponentDigits; i++)
2982 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002983 self->OutStream(self, digits[(uExponent / exponentBase) % base]);
2984 exponentBase /= base;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002985 }
2986 }
2987 /* Output trailing spaces */
2988 if (flags & FLAGS_LEFTADJUST)
2989 {
2990 for (i = expectedWidth; i < width; i++)
2991 {
2992 self->OutStream(self, CHAR_ADJUST);
2993 }
2994 }
2995}
2996
2997/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002998 * TrioFormatProcess
2999 *
3000 * Description:
3001 * This is the main engine for formatting output
Daniel Veillard92ad2102001-03-27 12:47:33 +00003002 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003003TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003004TrioFormatProcess
3005TRIO_ARGS3((data, format, parameters),
3006 trio_class_t *data,
3007 TRIO_CONST char *format,
3008 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003009{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003010#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003011 int charlen;
3012#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00003013 int i;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003014 TRIO_CONST char *string;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003015 trio_pointer_t pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003016 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003017 int width;
3018 int precision;
3019 int base;
3020 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003021
Daniel Veillard92ad2102001-03-27 12:47:33 +00003022 index = 0;
3023 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003024#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003025 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003026#endif
3027
3028 while (format[index])
3029 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003030#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003031 if (! isascii(format[index]))
3032 {
3033 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003034 /*
3035 * Only valid multibyte characters are handled here. Invalid
3036 * multibyte characters (charlen == -1) are handled as normal
3037 * characters.
3038 */
3039 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003040 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003041 while (charlen-- > 0)
3042 {
3043 data->OutStream(data, format[index++]);
3044 }
3045 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003046 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003047 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003048#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003049 if (CHAR_IDENTIFIER == format[index])
3050 {
3051 if (CHAR_IDENTIFIER == format[index + 1])
3052 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003053 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003054 index += 2;
3055 }
3056 else
3057 {
3058 /* Skip the parameter entries */
3059 while (parameters[i].type == FORMAT_PARAMETER)
3060 i++;
3061
3062 flags = parameters[i].flags;
3063
3064 /* Find width */
3065 width = parameters[i].width;
3066 if (flags & FLAGS_WIDTH_PARAMETER)
3067 {
3068 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003069 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003070 }
3071
3072 /* Find precision */
3073 if (flags & FLAGS_PRECISION)
3074 {
3075 precision = parameters[i].precision;
3076 if (flags & FLAGS_PRECISION_PARAMETER)
3077 {
3078 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003079 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003080 }
3081 }
3082 else
3083 {
3084 precision = NO_PRECISION;
3085 }
3086
3087 /* Find base */
3088 base = parameters[i].base;
3089 if (flags & FLAGS_BASE_PARAMETER)
3090 {
3091 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003092 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003093 }
3094
3095 switch (parameters[i].type)
3096 {
3097 case FORMAT_CHAR:
3098 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003099 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003100 if (! (flags & FLAGS_LEFTADJUST))
3101 {
3102 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003103 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003104 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003105#if TRIO_WIDECHAR
3106 if (flags & FLAGS_WIDECHAR)
3107 {
3108 TrioWriteWideStringCharacter(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003109 (trio_wchar_t)parameters[i].data.number.as_signed,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003110 flags,
3111 NO_WIDTH);
3112 }
3113 else
3114#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +00003115 {
3116 TrioWriteStringCharacter(data,
3117 (int)parameters[i].data.number.as_signed,
3118 flags);
3119 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003120
3121 if (flags & FLAGS_LEFTADJUST)
3122 {
3123 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003124 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003125 }
3126 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003127 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003128
3129 break; /* FORMAT_CHAR */
3130
3131 case FORMAT_INT:
Daniel Veillard92ad2102001-03-27 12:47:33 +00003132 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003133 parameters[i].data.number.as_unsigned,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003134 flags,
3135 width,
3136 precision,
3137 base);
3138
3139 break; /* FORMAT_INT */
3140
3141 case FORMAT_DOUBLE:
3142 TrioWriteDouble(data,
3143 parameters[i].data.longdoubleNumber,
3144 flags,
3145 width,
3146 precision,
3147 base);
3148 break; /* FORMAT_DOUBLE */
3149
3150 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003151#if TRIO_WIDECHAR
3152 if (flags & FLAGS_WIDECHAR)
3153 {
3154 TrioWriteWideString(data,
3155 parameters[i].data.wstring,
3156 flags,
3157 width,
3158 precision);
3159 }
3160 else
3161#endif
3162 {
3163 TrioWriteString(data,
3164 parameters[i].data.string,
3165 flags,
3166 width,
3167 precision);
3168 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003169 break; /* FORMAT_STRING */
3170
3171 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00003172 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003173 trio_reference_t reference;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003174
3175 reference.data = data;
3176 reference.parameter = &parameters[i];
3177 trio_print_pointer(&reference, parameters[i].data.pointer);
3178 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003179 break; /* FORMAT_POINTER */
3180
3181 case FORMAT_COUNT:
3182 pointer = parameters[i].data.pointer;
3183 if (NULL != pointer)
3184 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003185 /*
3186 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00003187 * characters written to the output stream so far by
3188 * this call", which is data->committed
3189 */
3190#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3191 if (flags & FLAGS_SIZE_T)
3192 *(size_t *)pointer = (size_t)data->committed;
3193 else
3194#endif
3195#if defined(QUALIFIER_PTRDIFF_T)
3196 if (flags & FLAGS_PTRDIFF_T)
3197 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3198 else
3199#endif
3200#if defined(QUALIFIER_INTMAX_T)
3201 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003202 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003203 else
3204#endif
3205 if (flags & FLAGS_QUAD)
3206 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003207 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003208 }
3209 else if (flags & FLAGS_LONG)
3210 {
3211 *(long int *)pointer = (long int)data->committed;
3212 }
3213 else if (flags & FLAGS_SHORT)
3214 {
3215 *(short int *)pointer = (short int)data->committed;
3216 }
3217 else
3218 {
3219 *(int *)pointer = (int)data->committed;
3220 }
3221 }
3222 break; /* FORMAT_COUNT */
3223
3224 case FORMAT_PARAMETER:
3225 break; /* FORMAT_PARAMETER */
3226
3227#if defined(FORMAT_ERRNO)
3228 case FORMAT_ERRNO:
Bjorn Reese026d29f2002-01-19 15:40:18 +00003229 string = trio_error(parameters[i].data.errorNumber);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003230 if (string)
3231 {
3232 TrioWriteString(data,
3233 string,
3234 flags,
3235 width,
3236 precision);
3237 }
3238 else
3239 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003240 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00003241 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003242 (trio_uintmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003243 flags,
3244 width,
3245 precision,
3246 BASE_DECIMAL);
3247 }
3248 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003249#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003250
Bjorn Reese70a9da52001-04-21 16:57:29 +00003251#if defined(FORMAT_USER_DEFINED)
3252 case FORMAT_USER_DEFINED:
3253 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003254 trio_reference_t reference;
3255 trio_userdef_t *def = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003256
3257 if (parameters[i].user_name[0] == NIL)
3258 {
3259 /* Use handle */
3260 if ((i > 0) ||
3261 (parameters[i - 1].type == FORMAT_PARAMETER))
Bjorn Reese026d29f2002-01-19 15:40:18 +00003262 def = (trio_userdef_t *)parameters[i - 1].data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003263 }
3264 else
3265 {
3266 /* Look up namespace */
3267 def = TrioFindNamespace(parameters[i].user_name, NULL);
3268 }
3269 if (def) {
3270 reference.data = data;
3271 reference.parameter = &parameters[i];
3272 def->callback(&reference);
3273 }
3274 }
3275 break;
3276#endif /* defined(FORMAT_USER_DEFINED) */
3277
Daniel Veillard92ad2102001-03-27 12:47:33 +00003278 default:
3279 break;
3280 } /* switch parameter type */
3281
3282 /* Prepare for next */
3283 index = parameters[i].indexAfterSpecifier;
3284 i++;
3285 }
3286 }
3287 else /* not identifier */
3288 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003289 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003290 }
3291 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003292 return data->processed;
3293}
3294
3295/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003296 * TrioFormatRef
Bjorn Reese70a9da52001-04-21 16:57:29 +00003297 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003298TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003299TrioFormatRef
3300TRIO_ARGS4((reference, format, arglist, argarray),
3301 trio_reference_t *reference,
3302 TRIO_CONST char *format,
3303 va_list *arglist,
3304 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003305{
3306 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003307 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003308
Bjorn Reese026d29f2002-01-19 15:40:18 +00003309 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003310 if (status < 0)
3311 return status;
3312
Bjorn Reese026d29f2002-01-19 15:40:18 +00003313 status = TrioFormatProcess(reference->data, format, parameters);
3314 if (reference->data->error != 0)
3315 {
3316 status = reference->data->error;
3317 }
3318 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003319}
3320
3321/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003322 * TrioFormat
Bjorn Reese70a9da52001-04-21 16:57:29 +00003323 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003324TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003325TrioFormat
3326TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3327 trio_pointer_t destination,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003328 size_t destinationSize,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003329 void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
Bjorn Reese026d29f2002-01-19 15:40:18 +00003330 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003331 va_list *arglist,
3332 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003333{
3334 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003335 trio_class_t data;
3336 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003337
3338 assert(VALID(OutStream));
3339 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003340
3341 memset(&data, 0, sizeof(data));
3342 data.OutStream = OutStream;
3343 data.location = destination;
3344 data.max = destinationSize;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003345 data.error = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003346
3347#if defined(USE_LOCALE)
3348 if (NULL == internalLocaleValues)
3349 {
3350 TrioSetLocale();
3351 }
3352#endif
3353
Bjorn Reese026d29f2002-01-19 15:40:18 +00003354 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003355 if (status < 0)
3356 return status;
3357
Bjorn Reese026d29f2002-01-19 15:40:18 +00003358 status = TrioFormatProcess(&data, format, parameters);
3359 if (data.error != 0)
3360 {
3361 status = data.error;
3362 }
3363 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003364}
3365
3366/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003367 * TrioOutStreamFile
Daniel Veillard92ad2102001-03-27 12:47:33 +00003368 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003369TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003370TrioOutStreamFile
3371TRIO_ARGS2((self, output),
3372 trio_class_t *self,
3373 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003374{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003375 FILE *file;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003376
3377 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003378 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003379
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003380 file = (FILE *)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003381 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003382 if (fputc(output, file) == EOF)
3383 {
3384 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3385 }
3386 else
3387 {
3388 self->committed++;
3389 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003390}
3391
3392/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003393 * TrioOutStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00003394 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003395TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003396TrioOutStreamFileDescriptor
3397TRIO_ARGS2((self, output),
3398 trio_class_t *self,
3399 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003400{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003401 int fd;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003402 char ch;
3403
3404 assert(VALID(self));
3405
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003406 fd = *((int *)self->location);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003407 ch = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003408 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003409 if (write(fd, &ch, sizeof(char)) == -1)
3410 {
3411 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3412 }
3413 else
3414 {
3415 self->committed++;
3416 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003417}
3418
3419/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003420 * TrioOutStreamCustom
3421 */
3422TRIO_PRIVATE void
3423TrioOutStreamCustom
3424TRIO_ARGS2((self, output),
3425 trio_class_t *self,
3426 int output)
3427{
3428 int status;
3429 trio_custom_t *data;
3430
3431 assert(VALID(self));
3432 assert(VALID(self->location));
3433
3434 data = (trio_custom_t *)self->location;
3435 if (data->stream.out)
3436 {
3437 status = (data->stream.out)(data->closure, output);
3438 if (status >= 0)
3439 {
3440 self->committed++;
3441 }
3442 else
3443 {
3444 if (self->error == 0)
3445 {
3446 self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3447 }
3448 }
3449 }
3450 self->processed++;
3451}
3452
3453/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003454 * TrioOutStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00003455 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003456TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003457TrioOutStreamString
3458TRIO_ARGS2((self, output),
3459 trio_class_t *self,
3460 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003461{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003462 char **buffer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003463
3464 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003465 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003466
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003467 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003468 **buffer = (char)output;
3469 (*buffer)++;
3470 self->processed++;
3471 self->committed++;
3472}
3473
3474/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003475 * TrioOutStreamStringMax
Daniel Veillard92ad2102001-03-27 12:47:33 +00003476 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003477TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003478TrioOutStreamStringMax
3479TRIO_ARGS2((self, output),
3480 trio_class_t *self,
3481 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003482{
3483 char **buffer;
3484
3485 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003486 assert(VALID(self->location));
3487
Daniel Veillard92ad2102001-03-27 12:47:33 +00003488 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003489
3490 if (self->processed < self->max)
3491 {
3492 **buffer = (char)output;
3493 (*buffer)++;
3494 self->committed++;
3495 }
3496 self->processed++;
3497}
3498
3499/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003500 * TrioOutStreamStringDynamic
Daniel Veillard92ad2102001-03-27 12:47:33 +00003501 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003502TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003503TrioOutStreamStringDynamic
3504TRIO_ARGS2((self, output),
3505 trio_class_t *self,
3506 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003507{
Daniel Veillard92ad2102001-03-27 12:47:33 +00003508 assert(VALID(self));
3509 assert(VALID(self->location));
3510
Bjorn Reese026d29f2002-01-19 15:40:18 +00003511 if (self->error == 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003512 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003513 trio_xstring_append_char((trio_string_t *)self->location,
3514 (char)output);
3515 self->committed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003516 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003517 /* The processed variable must always be increased */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003518 self->processed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003519}
3520
Daniel Veillard92ad2102001-03-27 12:47:33 +00003521/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003522 *
3523 * Formatted printing functions
3524 *
3525 ************************************************************************/
3526
3527#if defined(TRIO_DOCUMENTATION)
3528# include "doc/doc_printf.h"
3529#endif
3530/** @addtogroup Printf
3531 @{
3532*/
3533
3534/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003535 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003536 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003537
3538/**
3539 Print to standard output stream.
3540
3541 @param format Formatting string.
3542 @param ... Arguments.
3543 @return Number of printed characters.
3544 */
3545TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003546trio_printf
3547TRIO_VARGS2((format, va_alist),
3548 TRIO_CONST char *format,
3549 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003550{
3551 int status;
3552 va_list args;
3553
3554 assert(VALID(format));
3555
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003556 TRIO_VA_START(args, format);
3557 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3558 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003559 return status;
3560}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003561
Bjorn Reese026d29f2002-01-19 15:40:18 +00003562/**
3563 Print to standard output stream.
3564
3565 @param format Formatting string.
3566 @param args Arguments.
3567 @return Number of printed characters.
3568 */
3569TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003570trio_vprintf
3571TRIO_ARGS2((format, args),
3572 TRIO_CONST char *format,
3573 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003574{
3575 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003576
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003577 return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003578}
3579
Bjorn Reese026d29f2002-01-19 15:40:18 +00003580/**
3581 Print to standard output stream.
3582
3583 @param format Formatting string.
3584 @param args Arguments.
3585 @return Number of printed characters.
3586 */
3587TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003588trio_printfv
3589TRIO_ARGS2((format, args),
3590 TRIO_CONST char *format,
3591 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003592{
3593 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003594
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003595 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003596}
3597
Daniel Veillard92ad2102001-03-27 12:47:33 +00003598/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003599 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003600 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003601
3602/**
3603 Print to file.
3604
3605 @param file File pointer.
3606 @param format Formatting string.
3607 @param ... Arguments.
3608 @return Number of printed characters.
3609 */
3610TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003611trio_fprintf
3612TRIO_VARGS3((file, format, va_alist),
3613 FILE *file,
3614 TRIO_CONST char *format,
3615 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003616{
3617 int status;
3618 va_list args;
3619
3620 assert(VALID(file));
3621 assert(VALID(format));
3622
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003623 TRIO_VA_START(args, format);
3624 status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3625 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003626 return status;
3627}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003628
Bjorn Reese026d29f2002-01-19 15:40:18 +00003629/**
3630 Print to file.
3631
3632 @param file File pointer.
3633 @param format Formatting string.
3634 @param args Arguments.
3635 @return Number of printed characters.
3636 */
3637TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003638trio_vfprintf
3639TRIO_ARGS3((file, format, args),
3640 FILE *file,
3641 TRIO_CONST char *format,
3642 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003643{
3644 assert(VALID(file));
3645 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003646
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003647 return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003648}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003649
Bjorn Reese026d29f2002-01-19 15:40:18 +00003650/**
3651 Print to file.
3652
3653 @param file File pointer.
3654 @param format Formatting string.
3655 @param args Arguments.
3656 @return Number of printed characters.
3657 */
3658TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003659trio_fprintfv
3660TRIO_ARGS3((file, format, args),
3661 FILE *file,
3662 TRIO_CONST char *format,
3663 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003664{
3665 assert(VALID(file));
3666 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003667
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003668 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003669}
3670
Daniel Veillard92ad2102001-03-27 12:47:33 +00003671/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003672 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003673 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003674
3675/**
3676 Print to file descriptor.
3677
3678 @param fd File descriptor.
3679 @param format Formatting string.
3680 @param ... Arguments.
3681 @return Number of printed characters.
3682 */
3683TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003684trio_dprintf
3685TRIO_VARGS3((fd, format, va_alist),
3686 int fd,
3687 TRIO_CONST char *format,
3688 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003689{
3690 int status;
3691 va_list args;
3692
3693 assert(VALID(format));
3694
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003695 TRIO_VA_START(args, format);
3696 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3697 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003698 return status;
3699}
3700
Bjorn Reese026d29f2002-01-19 15:40:18 +00003701/**
3702 Print to file descriptor.
3703
3704 @param fd File descriptor.
3705 @param format Formatting string.
3706 @param args Arguments.
3707 @return Number of printed characters.
3708 */
3709TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003710trio_vdprintf
3711TRIO_ARGS3((fd, format, args),
3712 int fd,
3713 TRIO_CONST char *format,
3714 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003715{
3716 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003717
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003718 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003719}
3720
Bjorn Reese026d29f2002-01-19 15:40:18 +00003721/**
3722 Print to file descriptor.
3723
3724 @param fd File descriptor.
3725 @param format Formatting string.
3726 @param args Arguments.
3727 @return Number of printed characters.
3728 */
3729TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003730trio_dprintfv
3731TRIO_ARGS3((fd, format, args),
3732 int fd,
3733 TRIO_CONST char *format,
3734 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003735{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003736 assert(VALID(format));
3737
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003738 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3739}
3740
3741/*************************************************************************
3742 * cprintf
3743 */
3744TRIO_PUBLIC int
3745trio_cprintf
3746TRIO_VARGS4((stream, closure, format, va_alist),
3747 trio_outstream_t stream,
3748 trio_pointer_t closure,
3749 TRIO_CONST char *format,
3750 TRIO_VA_DECL)
3751{
3752 int status;
3753 va_list args;
3754 trio_custom_t data;
3755
3756 assert(VALID(stream));
3757 assert(VALID(format));
3758
3759 TRIO_VA_START(args, format);
3760 data.stream.out = stream;
3761 data.closure = closure;
3762 status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3763 TRIO_VA_END(args);
3764 return status;
3765}
3766
3767TRIO_PUBLIC int
3768trio_vcprintf
3769TRIO_ARGS4((stream, closure, format, args),
3770 trio_outstream_t stream,
3771 trio_pointer_t closure,
3772 TRIO_CONST char *format,
3773 va_list args)
3774{
3775 trio_custom_t data;
3776
3777 assert(VALID(stream));
3778 assert(VALID(format));
3779
3780 data.stream.out = stream;
3781 data.closure = closure;
3782 return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3783}
3784
3785TRIO_PUBLIC int
3786trio_cprintfv
3787TRIO_ARGS4((stream, closure, format, args),
3788 trio_outstream_t stream,
3789 trio_pointer_t closure,
3790 TRIO_CONST char *format,
3791 void **args)
3792{
3793 trio_custom_t data;
3794
3795 assert(VALID(stream));
3796 assert(VALID(format));
3797
3798 data.stream.out = stream;
3799 data.closure = closure;
3800 return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003801}
3802
3803/*************************************************************************
3804 * sprintf
3805 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003806
3807/**
3808 Print to string.
3809
3810 @param buffer Output string.
3811 @param format Formatting string.
3812 @param ... Arguments.
3813 @return Number of printed characters.
3814 */
3815TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003816trio_sprintf
3817TRIO_VARGS3((buffer, format, va_alist),
3818 char *buffer,
3819 TRIO_CONST char *format,
3820 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003821{
3822 int status;
3823 va_list args;
3824
3825 assert(VALID(buffer));
3826 assert(VALID(format));
3827
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003828 TRIO_VA_START(args, format);
3829 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003830 *buffer = NIL; /* Terminate with NIL character */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003831 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003832 return status;
3833}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003834
Bjorn Reese026d29f2002-01-19 15:40:18 +00003835/**
3836 Print to string.
3837
3838 @param buffer Output string.
3839 @param format Formatting string.
3840 @param args Arguments.
3841 @return Number of printed characters.
3842 */
3843TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003844trio_vsprintf
3845TRIO_ARGS3((buffer, format, args),
3846 char *buffer,
3847 TRIO_CONST char *format,
3848 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003849{
3850 int status;
3851
3852 assert(VALID(buffer));
3853 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003854
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003855 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003856 *buffer = NIL;
3857 return status;
3858}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003859
Bjorn Reese026d29f2002-01-19 15:40:18 +00003860/**
3861 Print to string.
3862
3863 @param buffer Output string.
3864 @param format Formatting string.
3865 @param args Arguments.
3866 @return Number of printed characters.
3867 */
3868TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003869trio_sprintfv
3870TRIO_ARGS3((buffer, format, args),
3871 char *buffer,
3872 TRIO_CONST char *format,
3873 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003874{
3875 int status;
3876
3877 assert(VALID(buffer));
3878 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003879
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003880 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003881 *buffer = NIL;
3882 return status;
3883}
3884
Daniel Veillard92ad2102001-03-27 12:47:33 +00003885/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003886 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003887 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003888
3889/**
3890 Print at most @p max characters to string.
3891
3892 @param buffer Output string.
3893 @param max Maximum number of characters to print.
3894 @param format Formatting string.
3895 @param ... Arguments.
3896 @return Number of printed characters.
3897 */
3898TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003899trio_snprintf
3900TRIO_VARGS4((buffer, max, format, va_alist),
3901 char *buffer,
3902 size_t max,
3903 TRIO_CONST char *format,
3904 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003905{
3906 int status;
3907 va_list args;
3908
3909 assert(VALID(buffer));
3910 assert(VALID(format));
3911
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003912 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003913 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003914 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003915 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003916 *buffer = NIL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003917 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003918 return status;
3919}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003920
Bjorn Reese026d29f2002-01-19 15:40:18 +00003921/**
3922 Print at most @p max characters to string.
3923
3924 @param buffer Output string.
3925 @param max Maximum number of characters to print.
3926 @param format Formatting string.
3927 @param args Arguments.
3928 @return Number of printed characters.
3929 */
3930TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003931trio_vsnprintf
3932TRIO_ARGS4((buffer, max, format, args),
3933 char *buffer,
3934 size_t max,
3935 TRIO_CONST char *format,
3936 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003937{
3938 int status;
3939
3940 assert(VALID(buffer));
3941 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003942
Bjorn Reese026d29f2002-01-19 15:40:18 +00003943 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003944 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003945 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003946 *buffer = NIL;
3947 return status;
3948}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003949
Bjorn Reese026d29f2002-01-19 15:40:18 +00003950/**
3951 Print at most @p max characters to string.
3952
3953 @param buffer Output string.
3954 @param max Maximum number of characters to print.
3955 @param format Formatting string.
3956 @param args Arguments.
3957 @return Number of printed characters.
3958 */
3959TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003960trio_snprintfv
3961TRIO_ARGS4((buffer, max, format, args),
3962 char *buffer,
3963 size_t max,
3964 TRIO_CONST char *format,
3965 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003966{
3967 int status;
3968
3969 assert(VALID(buffer));
3970 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003971
Bjorn Reese026d29f2002-01-19 15:40:18 +00003972 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003973 TrioOutStreamStringMax, format, NULL, args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003974 if (max > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003975 *buffer = NIL;
3976 return status;
3977}
3978
3979/*************************************************************************
3980 * snprintfcat
3981 * Appends the new string to the buffer string overwriting the '\0'
3982 * character at the end of buffer.
3983 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003984TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003985trio_snprintfcat
3986TRIO_VARGS4((buffer, max, format, va_alist),
3987 char *buffer,
3988 size_t max,
3989 TRIO_CONST char *format,
3990 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003991{
3992 int status;
3993 va_list args;
3994 size_t buf_len;
3995
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003996 TRIO_VA_START(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003997
3998 assert(VALID(buffer));
3999 assert(VALID(format));
4000
Bjorn Reese026d29f2002-01-19 15:40:18 +00004001 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004002 buffer = &buffer[buf_len];
4003
Bjorn Reese026d29f2002-01-19 15:40:18 +00004004 status = TrioFormat(&buffer, max - 1 - buf_len,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004005 TrioOutStreamStringMax, format, &args, NULL);
4006 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004007 *buffer = NIL;
4008 return status;
4009}
4010
Bjorn Reese026d29f2002-01-19 15:40:18 +00004011TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004012trio_vsnprintfcat
4013TRIO_ARGS4((buffer, max, format, args),
4014 char *buffer,
4015 size_t max,
4016 TRIO_CONST char *format,
4017 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004018{
4019 int status;
4020 size_t buf_len;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004021
Bjorn Reese70a9da52001-04-21 16:57:29 +00004022 assert(VALID(buffer));
4023 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004024
Bjorn Reese026d29f2002-01-19 15:40:18 +00004025 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004026 buffer = &buffer[buf_len];
Bjorn Reese026d29f2002-01-19 15:40:18 +00004027 status = TrioFormat(&buffer, max - 1 - buf_len,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004028 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004029 *buffer = NIL;
4030 return status;
4031}
4032
4033/*************************************************************************
4034 * trio_aprintf
4035 */
4036
4037/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004038TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004039trio_aprintf
4040TRIO_VARGS2((format, va_alist),
4041 TRIO_CONST char *format,
4042 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004043{
4044 va_list args;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004045 trio_string_t *info;
4046 char *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004047
4048 assert(VALID(format));
4049
Bjorn Reese026d29f2002-01-19 15:40:18 +00004050 info = trio_xstring_duplicate("");
4051 if (info)
4052 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004053 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004054 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004055 format, &args, NULL);
4056 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004057
Bjorn Reese026d29f2002-01-19 15:40:18 +00004058 trio_string_terminate(info);
4059 result = trio_string_extract(info);
4060 trio_string_destroy(info);
4061 }
4062 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004063}
4064
4065/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004066TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004067trio_vaprintf
4068TRIO_ARGS2((format, args),
4069 TRIO_CONST char *format,
4070 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004071{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004072 trio_string_t *info;
4073 char *result = NULL;
4074
Bjorn Reese70a9da52001-04-21 16:57:29 +00004075 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004076
Bjorn Reese026d29f2002-01-19 15:40:18 +00004077 info = trio_xstring_duplicate("");
4078 if (info)
4079 {
4080 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004081 format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004082 trio_string_terminate(info);
4083 result = trio_string_extract(info);
4084 trio_string_destroy(info);
4085 }
4086 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004087}
4088
Bjorn Reese026d29f2002-01-19 15:40:18 +00004089TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004090trio_asprintf
4091TRIO_VARGS3((result, format, va_alist),
4092 char **result,
4093 TRIO_CONST char *format,
4094 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004095{
4096 va_list args;
4097 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004098 trio_string_t *info;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004099
4100 assert(VALID(format));
4101
Bjorn Reese026d29f2002-01-19 15:40:18 +00004102 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004103
Bjorn Reese026d29f2002-01-19 15:40:18 +00004104 info = trio_xstring_duplicate("");
4105 if (info == NULL)
4106 {
4107 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4108 }
4109 else
4110 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004111 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004112 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004113 format, &args, NULL);
4114 TRIO_VA_END(args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004115 if (status >= 0)
4116 {
4117 trio_string_terminate(info);
4118 *result = trio_string_extract(info);
4119 }
4120 trio_string_destroy(info);
4121 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004122 return status;
4123}
4124
Bjorn Reese026d29f2002-01-19 15:40:18 +00004125TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004126trio_vasprintf
4127TRIO_ARGS3((result, format, args),
4128 char **result,
4129 TRIO_CONST char *format,
4130 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004131{
4132 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004133 trio_string_t *info;
4134
Bjorn Reese70a9da52001-04-21 16:57:29 +00004135 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004136
Bjorn Reese026d29f2002-01-19 15:40:18 +00004137 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004138
Bjorn Reese026d29f2002-01-19 15:40:18 +00004139 info = trio_xstring_duplicate("");
4140 if (info == NULL)
4141 {
4142 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4143 }
4144 else
4145 {
4146 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004147 format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004148 if (status >= 0)
4149 {
4150 trio_string_terminate(info);
4151 *result = trio_string_extract(info);
4152 }
4153 trio_string_destroy(info);
4154 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004155 return status;
4156}
4157
Bjorn Reese026d29f2002-01-19 15:40:18 +00004158/** @} End of Printf documentation module */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004159
4160/*************************************************************************
4161 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00004162 * CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00004163 *
4164 ************************************************************************/
4165
Bjorn Reese026d29f2002-01-19 15:40:18 +00004166#if defined(TRIO_DOCUMENTATION)
4167# include "doc/doc_register.h"
4168#endif
4169/**
4170 @addtogroup UserDefined
4171 @{
4172*/
4173
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004174#if TRIO_EXTENSION
4175
Bjorn Reese70a9da52001-04-21 16:57:29 +00004176/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004177 * trio_register
Bjorn Reese70a9da52001-04-21 16:57:29 +00004178 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004179
4180/**
4181 Register new user-defined specifier.
4182
4183 @param callback
4184 @param name
4185 @return Handle.
4186 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004187TRIO_PUBLIC trio_pointer_t
4188trio_register
4189TRIO_ARGS2((callback, name),
4190 trio_callback_t callback,
4191 TRIO_CONST char *name)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004192{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004193 trio_userdef_t *def;
4194 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004195
4196 if (callback == NULL)
4197 return NULL;
4198
4199 if (name)
4200 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004201 /* Handle built-in namespaces */
4202 if (name[0] == ':')
4203 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004204 if (trio_equal(name, ":enter"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004205 {
4206 internalEnterCriticalRegion = callback;
4207 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004208 else if (trio_equal(name, ":leave"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004209 {
4210 internalLeaveCriticalRegion = callback;
4211 }
4212 return NULL;
4213 }
4214
Bjorn Reese70a9da52001-04-21 16:57:29 +00004215 /* Bail out if namespace is too long */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004216 if (trio_length(name) >= MAX_USER_NAME)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004217 return NULL;
4218
4219 /* Bail out if namespace already is registered */
4220 def = TrioFindNamespace(name, &prev);
4221 if (def)
4222 return NULL;
4223 }
4224
Bjorn Reese026d29f2002-01-19 15:40:18 +00004225 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004226 if (def)
4227 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004228 if (internalEnterCriticalRegion)
4229 (void)internalEnterCriticalRegion(NULL);
4230
Bjorn Reese70a9da52001-04-21 16:57:29 +00004231 if (name)
4232 {
4233 /* Link into internal list */
4234 if (prev == NULL)
4235 internalUserDef = def;
4236 else
4237 prev->next = def;
4238 }
4239 /* Initialize */
4240 def->callback = callback;
4241 def->name = (name == NULL)
4242 ? NULL
Bjorn Reese026d29f2002-01-19 15:40:18 +00004243 : trio_duplicate(name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004244 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004245
4246 if (internalLeaveCriticalRegion)
4247 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004248 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004249 return (trio_pointer_t)def;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004250}
4251
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004252/**
4253 Unregister an existing user-defined specifier.
4254
4255 @param handle
Bjorn Reese70a9da52001-04-21 16:57:29 +00004256 */
4257void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004258trio_unregister
4259TRIO_ARGS1((handle),
4260 trio_pointer_t handle)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004261{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004262 trio_userdef_t *self = (trio_userdef_t *)handle;
4263 trio_userdef_t *def;
4264 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004265
4266 assert(VALID(self));
4267
4268 if (self->name)
4269 {
4270 def = TrioFindNamespace(self->name, &prev);
4271 if (def)
4272 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004273 if (internalEnterCriticalRegion)
4274 (void)internalEnterCriticalRegion(NULL);
4275
Bjorn Reese70a9da52001-04-21 16:57:29 +00004276 if (prev == NULL)
4277 internalUserDef = NULL;
4278 else
4279 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004280
4281 if (internalLeaveCriticalRegion)
4282 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004283 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004284 trio_destroy(self->name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004285 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004286 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004287}
4288
4289/*************************************************************************
4290 * trio_get_format [public]
4291 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004292TRIO_CONST char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004293trio_get_format
4294TRIO_ARGS1((ref),
4295 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004296{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004297#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004298 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004299#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00004300
Bjorn Reese026d29f2002-01-19 15:40:18 +00004301 return (((trio_reference_t *)ref)->parameter->user_data);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004302}
4303
4304/*************************************************************************
4305 * trio_get_argument [public]
4306 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004307trio_pointer_t
4308trio_get_argument
4309TRIO_ARGS1((ref),
4310 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004311{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004312#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004313 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004314#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00004315
Bjorn Reese026d29f2002-01-19 15:40:18 +00004316 return ((trio_reference_t *)ref)->parameter->data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004317}
4318
4319/*************************************************************************
4320 * trio_get_width / trio_set_width [public]
4321 */
4322int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004323trio_get_width
4324TRIO_ARGS1((ref),
4325 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004326{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004327 return ((trio_reference_t *)ref)->parameter->width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004328}
4329
4330void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004331trio_set_width
4332TRIO_ARGS2((ref, width),
4333 trio_pointer_t ref,
4334 int width)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004335{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004336 ((trio_reference_t *)ref)->parameter->width = width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004337}
4338
4339/*************************************************************************
4340 * trio_get_precision / trio_set_precision [public]
4341 */
4342int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004343trio_get_precision
4344TRIO_ARGS1((ref),
4345 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004346{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004347 return (((trio_reference_t *)ref)->parameter->precision);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004348}
4349
4350void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004351trio_set_precision
4352TRIO_ARGS2((ref, precision),
4353 trio_pointer_t ref,
4354 int precision)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004355{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004356 ((trio_reference_t *)ref)->parameter->precision = precision;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004357}
4358
4359/*************************************************************************
4360 * trio_get_base / trio_set_base [public]
4361 */
4362int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004363trio_get_base
4364TRIO_ARGS1((ref),
4365 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004366{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004367 return (((trio_reference_t *)ref)->parameter->base);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004368}
4369
4370void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004371trio_set_base
4372TRIO_ARGS2((ref, base),
4373 trio_pointer_t ref,
4374 int base)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004375{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004376 ((trio_reference_t *)ref)->parameter->base = base;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004377}
4378
4379/*************************************************************************
4380 * trio_get_long / trio_set_long [public]
4381 */
4382int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004383trio_get_long
4384TRIO_ARGS1((ref),
4385 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004386{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004387 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004388}
4389
4390void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004391trio_set_long
4392TRIO_ARGS2((ref, is_long),
4393 trio_pointer_t ref,
4394 int is_long)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004395{
4396 if (is_long)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004397 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004398 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004399 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004400}
4401
4402/*************************************************************************
4403 * trio_get_longlong / trio_set_longlong [public]
4404 */
4405int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004406trio_get_longlong
4407TRIO_ARGS1((ref),
4408 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004409{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004410 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004411}
4412
4413void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004414trio_set_longlong
4415TRIO_ARGS2((ref, is_longlong),
4416 trio_pointer_t ref,
4417 int is_longlong)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004418{
4419 if (is_longlong)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004420 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004421 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004422 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004423}
4424
4425/*************************************************************************
4426 * trio_get_longdouble / trio_set_longdouble [public]
4427 */
4428int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004429trio_get_longdouble
4430TRIO_ARGS1((ref),
4431 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004432{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004433 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004434}
4435
4436void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004437trio_set_longdouble
4438TRIO_ARGS2((ref, is_longdouble),
4439 trio_pointer_t ref,
4440 int is_longdouble)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004441{
4442 if (is_longdouble)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004443 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004444 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004445 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004446}
4447
4448/*************************************************************************
4449 * trio_get_short / trio_set_short [public]
4450 */
4451int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004452trio_get_short
4453TRIO_ARGS1((ref),
4454 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004455{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004456 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004457}
4458
4459void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004460trio_set_short
4461TRIO_ARGS2((ref, is_short),
4462 trio_pointer_t ref,
4463 int is_short)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004464{
4465 if (is_short)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004466 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004467 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004468 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004469}
4470
4471/*************************************************************************
4472 * trio_get_shortshort / trio_set_shortshort [public]
4473 */
4474int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004475trio_get_shortshort
4476TRIO_ARGS1((ref),
4477 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004478{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004479 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004480}
4481
4482void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004483trio_set_shortshort
4484TRIO_ARGS2((ref, is_shortshort),
4485 trio_pointer_t ref,
4486 int is_shortshort)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004487{
4488 if (is_shortshort)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004489 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004490 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004491 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004492}
4493
4494/*************************************************************************
4495 * trio_get_alternative / trio_set_alternative [public]
4496 */
4497int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004498trio_get_alternative
4499TRIO_ARGS1((ref),
4500 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004501{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004502 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004503}
4504
4505void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004506trio_set_alternative
4507TRIO_ARGS2((ref, is_alternative),
4508 trio_pointer_t ref,
4509 int is_alternative)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004510{
4511 if (is_alternative)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004512 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004513 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004514 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004515}
4516
4517/*************************************************************************
4518 * trio_get_alignment / trio_set_alignment [public]
4519 */
4520int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004521trio_get_alignment
4522TRIO_ARGS1((ref),
4523 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004524{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004525 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004526}
4527
4528void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004529trio_set_alignment
4530TRIO_ARGS2((ref, is_leftaligned),
4531 trio_pointer_t ref,
4532 int is_leftaligned)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004533{
4534 if (is_leftaligned)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004535 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004536 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004537 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004538}
4539
4540/*************************************************************************
4541 * trio_get_spacing /trio_set_spacing [public]
4542 */
4543int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004544trio_get_spacing
4545TRIO_ARGS1((ref),
4546 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004547{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004548 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004549}
4550
4551void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004552trio_set_spacing
4553TRIO_ARGS2((ref, is_space),
4554 trio_pointer_t ref,
4555 int is_space)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004556{
4557 if (is_space)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004558 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004559 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004560 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004561}
4562
4563/*************************************************************************
4564 * trio_get_sign / trio_set_sign [public]
4565 */
4566int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004567trio_get_sign
4568TRIO_ARGS1((ref),
4569 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004570{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004571 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004572}
4573
4574void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004575trio_set_sign
4576TRIO_ARGS2((ref, is_sign),
4577 trio_pointer_t ref,
4578 int is_sign)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004579{
4580 if (is_sign)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004581 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004582 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004583 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004584}
4585
4586/*************************************************************************
4587 * trio_get_padding / trio_set_padding [public]
4588 */
4589int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004590trio_get_padding
4591TRIO_ARGS1((ref),
4592 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004593{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004594 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004595}
4596
4597void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004598trio_set_padding
4599TRIO_ARGS2((ref, is_padding),
4600 trio_pointer_t ref,
4601 int is_padding)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004602{
4603 if (is_padding)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004604 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004605 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004606 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004607}
4608
4609/*************************************************************************
4610 * trio_get_quote / trio_set_quote [public]
4611 */
4612int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004613trio_get_quote
4614TRIO_ARGS1((ref),
4615 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004616{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004617 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004618}
4619
4620void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004621trio_set_quote
4622TRIO_ARGS2((ref, is_quote),
4623 trio_pointer_t ref,
4624 int is_quote)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004625{
4626 if (is_quote)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004627 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004628 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004629 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004630}
4631
4632/*************************************************************************
4633 * trio_get_upper / trio_set_upper [public]
4634 */
4635int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004636trio_get_upper
4637TRIO_ARGS1((ref),
4638 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004639{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004640 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004641}
4642
4643void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004644trio_set_upper
4645TRIO_ARGS2((ref, is_upper),
4646 trio_pointer_t ref,
4647 int is_upper)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004648{
4649 if (is_upper)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004650 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004651 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004652 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004653}
4654
4655/*************************************************************************
4656 * trio_get_largest / trio_set_largest [public]
4657 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004658#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004659int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004660trio_get_largest
4661TRIO_ARGS1((ref),
4662 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004663{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004664 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004665}
4666
4667void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004668trio_set_largest
4669TRIO_ARGS2((ref, is_largest),
4670 trio_pointer_t ref,
4671 int is_largest)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004672{
4673 if (is_largest)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004674 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004675 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004676 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004677}
4678#endif
4679
4680/*************************************************************************
4681 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4682 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004683int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004684trio_get_ptrdiff
4685TRIO_ARGS1((ref),
4686 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004687{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004688 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004689}
4690
4691void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004692trio_set_ptrdiff
4693TRIO_ARGS2((ref, is_ptrdiff),
4694 trio_pointer_t ref,
4695 int is_ptrdiff)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004696{
4697 if (is_ptrdiff)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004698 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004699 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004700 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004701}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004702
4703/*************************************************************************
4704 * trio_get_size / trio_set_size [public]
4705 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004706#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004707int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004708trio_get_size
4709TRIO_ARGS1((ref),
4710 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004711{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004712 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004713}
4714
4715void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004716trio_set_size
4717TRIO_ARGS2((ref, is_size),
4718 trio_pointer_t ref,
4719 int is_size)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004720{
4721 if (is_size)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004722 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004723 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004724 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004725}
4726#endif
4727
4728/*************************************************************************
4729 * trio_print_int [public]
4730 */
4731void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004732trio_print_int
4733TRIO_ARGS2((ref, number),
4734 trio_pointer_t ref,
4735 int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004736{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004737 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004738
4739 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004740 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004741 self->parameter->flags,
4742 self->parameter->width,
4743 self->parameter->precision,
4744 self->parameter->base);
4745}
4746
4747/*************************************************************************
4748 * trio_print_uint [public]
4749 */
4750void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004751trio_print_uint
4752TRIO_ARGS2((ref, number),
4753 trio_pointer_t ref,
4754 unsigned int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004755{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004756 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004757
4758 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004759 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004760 self->parameter->flags | FLAGS_UNSIGNED,
4761 self->parameter->width,
4762 self->parameter->precision,
4763 self->parameter->base);
4764}
4765
4766/*************************************************************************
4767 * trio_print_double [public]
4768 */
4769void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004770trio_print_double
4771TRIO_ARGS2((ref, number),
4772 trio_pointer_t ref,
4773 double number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004774{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004775 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004776
4777 TrioWriteDouble(self->data,
4778 number,
4779 self->parameter->flags,
4780 self->parameter->width,
4781 self->parameter->precision,
4782 self->parameter->base);
4783}
4784
4785/*************************************************************************
4786 * trio_print_string [public]
4787 */
4788void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004789trio_print_string
4790TRIO_ARGS2((ref, string),
4791 trio_pointer_t ref,
4792 char *string)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004793{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004794 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004795
4796 TrioWriteString(self->data,
4797 string,
4798 self->parameter->flags,
4799 self->parameter->width,
4800 self->parameter->precision);
4801}
4802
4803/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004804 * trio_print_ref [public]
4805 */
4806int
4807trio_print_ref
4808TRIO_VARGS3((ref, format, va_alist),
4809 trio_pointer_t ref,
4810 TRIO_CONST char *format,
4811 TRIO_VA_DECL)
4812{
4813 int status;
4814 va_list arglist;
4815
4816 assert(VALID(format));
4817
4818 TRIO_VA_START(arglist, format);
4819 status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4820 TRIO_VA_END(arglist);
4821 return status;
4822}
4823
4824/*************************************************************************
4825 * trio_vprint_ref [public]
4826 */
4827int
4828trio_vprint_ref
4829TRIO_ARGS3((ref, format, arglist),
4830 trio_pointer_t ref,
4831 TRIO_CONST char *format,
4832 va_list arglist)
4833{
4834 assert(VALID(format));
4835
4836 return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4837}
4838
4839/*************************************************************************
4840 * trio_printv_ref [public]
4841 */
4842int
4843trio_printv_ref
4844TRIO_ARGS3((ref, format, argarray),
4845 trio_pointer_t ref,
4846 TRIO_CONST char *format,
4847 trio_pointer_t *argarray)
4848{
4849 assert(VALID(format));
4850
4851 return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4852}
4853
4854#endif /* TRIO_EXTENSION */
4855
4856/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00004857 * trio_print_pointer [public]
4858 */
4859void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004860trio_print_pointer
4861TRIO_ARGS2((ref, pointer),
4862 trio_pointer_t ref,
4863 trio_pointer_t pointer)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004864{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004865 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004866 unsigned long flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004867 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004868
4869 if (NULL == pointer)
4870 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004871 TRIO_CONST char *string = internalNullString;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004872 while (*string)
4873 self->data->OutStream(self->data, *string++);
4874 }
4875 else
4876 {
4877 /*
4878 * The subtraction of the null pointer is a workaround
4879 * to avoid a compiler warning. The performance overhead
4880 * is negligible (and likely to be removed by an
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004881 * optimizing compiler). The (char *) casting is done
Bjorn Reese70a9da52001-04-21 16:57:29 +00004882 * to please ANSI C++.
4883 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004884 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004885 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004886 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004887 flags = self->parameter->flags;
4888 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4889 FLAGS_NILPADDING);
4890 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004891 number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004892 flags,
4893 POINTER_WIDTH,
4894 NO_PRECISION,
4895 BASE_HEX);
4896 }
4897}
4898
Bjorn Reese026d29f2002-01-19 15:40:18 +00004899/** @} End of UserDefined documentation module */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004900
4901/*************************************************************************
4902 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004903 * LOCALES
4904 *
4905 ************************************************************************/
4906
4907/*************************************************************************
4908 * trio_locale_set_decimal_point
4909 *
4910 * Decimal point can only be one character. The input argument is a
4911 * string to enable multibyte characters. At most MB_LEN_MAX characters
4912 * will be used.
4913 */
4914TRIO_PUBLIC void
4915trio_locale_set_decimal_point
4916TRIO_ARGS1((decimalPoint),
4917 char *decimalPoint)
4918{
4919#if defined(USE_LOCALE)
4920 if (NULL == internalLocaleValues)
4921 {
4922 TrioSetLocale();
4923 }
4924#endif
4925 internalDecimalPointLength = trio_length(decimalPoint);
4926 if (internalDecimalPointLength == 1)
4927 {
4928 internalDecimalPoint = *decimalPoint;
4929 }
4930 else
4931 {
4932 internalDecimalPoint = NIL;
4933 trio_copy_max(internalDecimalPointString,
4934 sizeof(internalDecimalPointString),
4935 decimalPoint);
4936 }
4937}
4938
4939/*************************************************************************
4940 * trio_locale_set_thousand_separator
4941 *
4942 * See trio_locale_set_decimal_point
4943 */
4944TRIO_PUBLIC void
4945trio_locale_set_thousand_separator
4946TRIO_ARGS1((thousandSeparator),
4947 char *thousandSeparator)
4948{
4949#if defined(USE_LOCALE)
4950 if (NULL == internalLocaleValues)
4951 {
4952 TrioSetLocale();
4953 }
4954#endif
4955 trio_copy_max(internalThousandSeparator,
4956 sizeof(internalThousandSeparator),
4957 thousandSeparator);
4958 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
4959}
4960
4961/*************************************************************************
4962 * trio_locale_set_grouping
4963 *
4964 * Array of bytes. Reversed order.
4965 *
4966 * CHAR_MAX : No further grouping
4967 * 0 : Repeat last group for the remaining digits (not necessary
4968 * as C strings are zero-terminated)
4969 * n : Set current group to n
4970 *
4971 * Same order as the grouping attribute in LC_NUMERIC.
4972 */
4973TRIO_PUBLIC void
4974trio_locale_set_grouping
4975TRIO_ARGS1((grouping),
4976 char *grouping)
4977{
4978#if defined(USE_LOCALE)
4979 if (NULL == internalLocaleValues)
4980 {
4981 TrioSetLocale();
4982 }
4983#endif
4984 trio_copy_max(internalGrouping,
4985 sizeof(internalGrouping),
4986 grouping);
4987}
4988
4989
4990/*************************************************************************
4991 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00004992 * SCANNING
Bjorn Reese70a9da52001-04-21 16:57:29 +00004993 *
4994 ************************************************************************/
4995
Daniel Veillard92ad2102001-03-27 12:47:33 +00004996/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004997 * TrioSkipWhitespaces
Daniel Veillard92ad2102001-03-27 12:47:33 +00004998 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004999TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005000TrioSkipWhitespaces
5001TRIO_ARGS1((self),
5002 trio_class_t *self)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005003{
5004 int ch;
5005
5006 ch = self->current;
5007 while (isspace(ch))
5008 {
5009 self->InStream(self, &ch);
5010 }
5011 return ch;
5012}
5013
5014/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005015 * TrioGetCollation
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005016 */
5017#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +00005018TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005019TrioGetCollation(TRIO_NOARGS)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005020{
5021 int i;
5022 int j;
5023 int k;
5024 char first[2];
5025 char second[2];
5026
5027 /* This is computational expensive */
5028 first[1] = NIL;
5029 second[1] = NIL;
5030 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5031 {
5032 k = 0;
5033 first[0] = (char)i;
5034 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5035 {
5036 second[0] = (char)j;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005037 if (trio_equal_locale(first, second))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005038 internalCollationArray[i][k++] = (char)j;
5039 }
5040 internalCollationArray[i][k] = NIL;
5041 }
5042}
5043#endif
5044
5045/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005046 * TrioGetCharacterClass
Daniel Veillard92ad2102001-03-27 12:47:33 +00005047 *
5048 * FIXME:
5049 * multibyte
5050 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005051TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005052TrioGetCharacterClass
5053TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5054 TRIO_CONST char *format,
5055 int *indexPointer,
5056 unsigned long *flagsPointer,
5057 int *characterclass)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005058{
5059 int index = *indexPointer;
5060 int i;
5061 char ch;
5062 char range_begin;
5063 char range_end;
5064
5065 *flagsPointer &= ~FLAGS_EXCLUDE;
5066
5067 if (format[index] == QUALIFIER_CIRCUMFLEX)
5068 {
5069 *flagsPointer |= FLAGS_EXCLUDE;
5070 index++;
5071 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005072 /*
5073 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005074 * it will be part of the class, and a second ungroup character
5075 * must follow to end the group.
5076 */
5077 if (format[index] == SPECIFIER_UNGROUP)
5078 {
5079 characterclass[(int)SPECIFIER_UNGROUP]++;
5080 index++;
5081 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005082 /*
5083 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005084 * it must be at the beginning of the list
5085 */
5086 if (format[index] == QUALIFIER_MINUS)
5087 {
5088 characterclass[(int)QUALIFIER_MINUS]++;
5089 index++;
5090 }
5091 /* Collect characters */
5092 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005093 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005094 ch = format[++index])
5095 {
5096 switch (ch)
5097 {
5098 case QUALIFIER_MINUS: /* Scanlist ranges */
5099
Bjorn Reese70a9da52001-04-21 16:57:29 +00005100 /*
5101 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00005102 * defined.
5103 *
5104 * We support the following behaviour (although this may
5105 * change as we become wiser)
5106 * - only increasing ranges, ie. [a-b] but not [b-a]
5107 * - transitive ranges, ie. [a-b-c] == [a-c]
5108 * - trailing minus, ie. [a-] is interpreted as an 'a'
5109 * and a '-'
5110 * - duplicates (although we can easily convert these
5111 * into errors)
5112 */
5113 range_begin = format[index - 1];
5114 range_end = format[++index];
5115 if (range_end == SPECIFIER_UNGROUP)
5116 {
5117 /* Trailing minus is included */
5118 characterclass[(int)ch]++;
5119 ch = range_end;
5120 break; /* for */
5121 }
5122 if (range_end == NIL)
5123 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5124 if (range_begin > range_end)
5125 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5126
5127 for (i = (int)range_begin; i <= (int)range_end; i++)
5128 characterclass[i]++;
5129
5130 ch = range_end;
5131 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005132
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005133#if TRIO_EXTENSION
5134
5135 case SPECIFIER_GROUP:
5136
5137 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005138 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005139 case QUALIFIER_DOT: /* Collating symbol */
5140 /*
5141 * FIXME: This will be easier to implement when multibyte
5142 * characters have been implemented. Until now, we ignore
5143 * this feature.
5144 */
5145 for (i = index + 2; ; i++)
5146 {
5147 if (format[i] == NIL)
5148 /* Error in syntax */
5149 return -1;
5150 else if (format[i] == QUALIFIER_DOT)
5151 break; /* for */
5152 }
5153 if (format[++i] != SPECIFIER_UNGROUP)
5154 return -1;
5155
5156 index = i;
5157 break;
5158
5159 case QUALIFIER_EQUAL: /* Equivalence class expressions */
5160 {
5161 unsigned int j;
5162 unsigned int k;
5163
5164 if (internalCollationUnconverted)
5165 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005166 /* Lazy evaluation of collation array */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005167 TrioGetCollation();
5168 internalCollationUnconverted = FALSE;
5169 }
5170 for (i = index + 2; ; i++)
5171 {
5172 if (format[i] == NIL)
5173 /* Error in syntax */
5174 return -1;
5175 else if (format[i] == QUALIFIER_EQUAL)
5176 break; /* for */
5177 else
5178 {
5179 /* Mark any equivalent character */
5180 k = (unsigned int)format[i];
5181 for (j = 0; internalCollationArray[k][j] != NIL; j++)
5182 characterclass[(int)internalCollationArray[k][j]]++;
5183 }
5184 }
5185 if (format[++i] != SPECIFIER_UNGROUP)
5186 return -1;
5187
5188 index = i;
5189 }
5190 break;
5191
5192 case QUALIFIER_COLON: /* Character class expressions */
5193
Bjorn Reese026d29f2002-01-19 15:40:18 +00005194 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5195 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005196 {
5197 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5198 if (isalnum(i))
5199 characterclass[i]++;
5200 index += sizeof(CLASS_ALNUM) - 1;
5201 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005202 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5203 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005204 {
5205 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5206 if (isalpha(i))
5207 characterclass[i]++;
5208 index += sizeof(CLASS_ALPHA) - 1;
5209 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005210 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5211 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005212 {
5213 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5214 if (iscntrl(i))
5215 characterclass[i]++;
5216 index += sizeof(CLASS_CNTRL) - 1;
5217 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005218 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5219 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005220 {
5221 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5222 if (isdigit(i))
5223 characterclass[i]++;
5224 index += sizeof(CLASS_DIGIT) - 1;
5225 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005226 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5227 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005228 {
5229 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5230 if (isgraph(i))
5231 characterclass[i]++;
5232 index += sizeof(CLASS_GRAPH) - 1;
5233 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005234 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5235 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005236 {
5237 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5238 if (islower(i))
5239 characterclass[i]++;
5240 index += sizeof(CLASS_LOWER) - 1;
5241 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005242 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5243 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005244 {
5245 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5246 if (isprint(i))
5247 characterclass[i]++;
5248 index += sizeof(CLASS_PRINT) - 1;
5249 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005250 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5251 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005252 {
5253 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5254 if (ispunct(i))
5255 characterclass[i]++;
5256 index += sizeof(CLASS_PUNCT) - 1;
5257 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005258 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5259 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005260 {
5261 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5262 if (isspace(i))
5263 characterclass[i]++;
5264 index += sizeof(CLASS_SPACE) - 1;
5265 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005266 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5267 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005268 {
5269 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5270 if (isupper(i))
5271 characterclass[i]++;
5272 index += sizeof(CLASS_UPPER) - 1;
5273 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005274 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5275 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005276 {
5277 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5278 if (isxdigit(i))
5279 characterclass[i]++;
5280 index += sizeof(CLASS_XDIGIT) - 1;
5281 }
5282 else
5283 {
5284 characterclass[(int)ch]++;
5285 }
5286 break;
5287
5288 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005289 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005290 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005291 }
5292 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005293
5294#endif /* TRIO_EXTENSION */
5295
Daniel Veillard92ad2102001-03-27 12:47:33 +00005296 default:
5297 characterclass[(int)ch]++;
5298 break;
5299 }
5300 }
5301 return 0;
5302}
5303
5304/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005305 * TrioReadNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00005306 *
5307 * We implement our own number conversion in preference of strtol and
5308 * strtoul, because we must handle 'long long' and thousand separators.
5309 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005310TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005311TrioReadNumber
5312TRIO_ARGS5((self, target, flags, width, base),
5313 trio_class_t *self,
5314 trio_uintmax_t *target,
5315 unsigned long flags,
5316 int width,
5317 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005318{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005319 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005320 int digit;
5321 int count;
5322 BOOLEAN_T isNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005323 BOOLEAN_T gotNumber = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005324 int j;
5325
5326 assert(VALID(self));
5327 assert(VALID(self->InStream));
5328 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5329
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005330 if (internalDigitsUnconverted)
5331 {
5332 /* Lazy evaluation of digits array */
5333 memset(internalDigitArray, -1, sizeof(internalDigitArray));
5334 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5335 {
5336 internalDigitArray[(int)internalDigitsLower[j]] = j;
5337 internalDigitArray[(int)internalDigitsUpper[j]] = j;
5338 }
5339 internalDigitsUnconverted = FALSE;
5340 }
5341
Daniel Veillard92ad2102001-03-27 12:47:33 +00005342 TrioSkipWhitespaces(self);
5343
5344 if (!(flags & FLAGS_UNSIGNED))
5345 {
5346 /* Leading sign */
5347 if (self->current == '+')
5348 {
5349 self->InStream(self, NULL);
5350 }
5351 else if (self->current == '-')
5352 {
5353 self->InStream(self, NULL);
5354 isNegative = TRUE;
5355 }
5356 }
5357
5358 count = self->processed;
5359
5360 if (flags & FLAGS_ALTERNATIVE)
5361 {
5362 switch (base)
5363 {
5364 case NO_BASE:
5365 case BASE_OCTAL:
5366 case BASE_HEX:
5367 case BASE_BINARY:
5368 if (self->current == '0')
5369 {
5370 self->InStream(self, NULL);
5371 if (self->current)
5372 {
5373 if ((base == BASE_HEX) &&
5374 (toupper(self->current) == 'X'))
5375 {
5376 self->InStream(self, NULL);
5377 }
5378 else if ((base == BASE_BINARY) &&
5379 (toupper(self->current) == 'B'))
5380 {
5381 self->InStream(self, NULL);
5382 }
5383 }
5384 }
5385 else
5386 return FALSE;
5387 break;
5388 default:
5389 break;
5390 }
5391 }
5392
5393 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5394 (! ((self->current == EOF) || isspace(self->current))))
5395 {
5396 if (isascii(self->current))
5397 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005398 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005399 /* Abort if digit is not allowed in the specified base */
5400 if ((digit == -1) || (digit >= base))
5401 break;
5402 }
5403 else if (flags & FLAGS_QUOTE)
5404 {
5405 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005406 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005407 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005408 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005409 break;
5410
5411 self->InStream(self, NULL);
5412 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005413 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005414 break; /* Mismatch */
5415 else
5416 continue; /* Match */
5417 }
5418 else
5419 break;
5420
5421 number *= base;
5422 number += digit;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005423 gotNumber = TRUE; /* we need at least one digit */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005424
5425 self->InStream(self, NULL);
5426 }
5427
5428 /* Was anything read at all? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005429 if (!gotNumber)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005430 return FALSE;
5431
5432 if (target)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005433 *target = (isNegative) ? -((trio_intmax_t)number) : number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005434 return TRUE;
5435}
5436
5437/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005438 * TrioReadChar
Daniel Veillard92ad2102001-03-27 12:47:33 +00005439 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005440TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005441TrioReadChar
5442TRIO_ARGS4((self, target, flags, width),
5443 trio_class_t *self,
5444 char *target,
5445 unsigned long flags,
5446 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005447{
5448 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005449 char ch;
5450 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005451
5452 assert(VALID(self));
5453 assert(VALID(self->InStream));
5454
5455 for (i = 0;
5456 (self->current != EOF) && (i < width);
5457 i++)
5458 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005459 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005460 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005461 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5462 {
5463 switch (self->current)
5464 {
5465 case '\\': ch = '\\'; break;
5466 case 'a': ch = '\007'; break;
5467 case 'b': ch = '\b'; break;
5468 case 'f': ch = '\f'; break;
5469 case 'n': ch = '\n'; break;
5470 case 'r': ch = '\r'; break;
5471 case 't': ch = '\t'; break;
5472 case 'v': ch = '\v'; break;
5473 default:
5474 if (isdigit(self->current))
5475 {
5476 /* Read octal number */
5477 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5478 return 0;
5479 ch = (char)number;
5480 }
5481 else if (toupper(self->current) == 'X')
5482 {
5483 /* Read hexadecimal number */
5484 self->InStream(self, NULL);
5485 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5486 return 0;
5487 ch = (char)number;
5488 }
5489 else
5490 {
5491 ch = (char)self->current;
5492 }
5493 break;
5494 }
5495 }
5496
5497 if (target)
5498 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005499 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005500 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005501}
5502
5503/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005504 * TrioReadString
Daniel Veillard92ad2102001-03-27 12:47:33 +00005505 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005506TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005507TrioReadString
5508TRIO_ARGS4((self, target, flags, width),
5509 trio_class_t *self,
5510 char *target,
5511 unsigned long flags,
5512 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005513{
5514 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005515
5516 assert(VALID(self));
5517 assert(VALID(self->InStream));
5518
5519 TrioSkipWhitespaces(self);
5520
Bjorn Reese70a9da52001-04-21 16:57:29 +00005521 /*
5522 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005523 * or width is exceeded
5524 */
5525 for (i = 0;
5526 ((width == NO_WIDTH) || (i < width)) &&
5527 (! ((self->current == EOF) || isspace(self->current)));
5528 i++)
5529 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005530 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005531 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005532 }
5533 if (target)
5534 target[i] = NIL;
5535 return TRUE;
5536}
5537
5538/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005539 * TrioReadWideChar
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005540 */
5541#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005542TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005543TrioReadWideChar
5544TRIO_ARGS4((self, target, flags, width),
5545 trio_class_t *self,
5546 trio_wchar_t *target,
5547 unsigned long flags,
5548 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005549{
5550 int i;
5551 int j;
5552 int size;
5553 int amount = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005554 trio_wchar_t wch;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005555 char buffer[MB_LEN_MAX + 1];
5556
5557 assert(VALID(self));
5558 assert(VALID(self->InStream));
5559
5560 for (i = 0;
5561 (self->current != EOF) && (i < width);
5562 i++)
5563 {
5564 if (isascii(self->current))
5565 {
5566 if (TrioReadChar(self, buffer, flags, 1) == 0)
5567 return 0;
5568 buffer[1] = NIL;
5569 }
5570 else
5571 {
5572 /*
5573 * Collect a multibyte character, by enlarging buffer until
5574 * it contains a fully legal multibyte character, or the
5575 * buffer is full.
5576 */
5577 j = 0;
5578 do
5579 {
5580 buffer[j++] = (char)self->current;
5581 buffer[j] = NIL;
5582 self->InStream(self, NULL);
5583 }
5584 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5585 }
5586 if (target)
5587 {
5588 size = mbtowc(&wch, buffer, sizeof(buffer));
5589 if (size > 0)
5590 target[i] = wch;
5591 }
5592 amount += size;
5593 self->InStream(self, NULL);
5594 }
5595 return amount;
5596}
5597#endif /* TRIO_WIDECHAR */
5598
5599/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005600 * TrioReadWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005601 */
5602#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005603TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005604TrioReadWideString
5605TRIO_ARGS4((self, target, flags, width),
5606 trio_class_t *self,
5607 trio_wchar_t *target,
5608 unsigned long flags,
5609 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005610{
5611 int i;
5612 int size;
5613
5614 assert(VALID(self));
5615 assert(VALID(self->InStream));
5616
5617 TrioSkipWhitespaces(self);
5618
5619#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005620 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005621#endif
5622
5623 /*
5624 * Continue until end of string is reached, a whitespace is encountered,
5625 * or width is exceeded
5626 */
5627 for (i = 0;
5628 ((width == NO_WIDTH) || (i < width)) &&
5629 (! ((self->current == EOF) || isspace(self->current)));
5630 )
5631 {
5632 size = TrioReadWideChar(self, &target[i], flags, 1);
5633 if (size == 0)
5634 break; /* for */
5635
5636 i += size;
5637 }
5638 if (target)
Bjorn Reese026d29f2002-01-19 15:40:18 +00005639 target[i] = WCONST('\0');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005640 return TRUE;
5641}
5642#endif /* TRIO_WIDECHAR */
5643
5644/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005645 * TrioReadGroup
Daniel Veillard92ad2102001-03-27 12:47:33 +00005646 *
5647 * FIXME: characterclass does not work with multibyte characters
5648 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005649TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005650TrioReadGroup
5651TRIO_ARGS5((self, target, characterclass, flags, width),
5652 trio_class_t *self,
5653 char *target,
5654 int *characterclass,
5655 unsigned long flags,
5656 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005657{
Bjorn Reese70a9da52001-04-21 16:57:29 +00005658 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005659 int i;
5660
5661 assert(VALID(self));
5662 assert(VALID(self->InStream));
5663
5664 ch = self->current;
5665 for (i = 0;
5666 ((width == NO_WIDTH) || (i < width)) &&
5667 (! ((ch == EOF) ||
5668 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5669 i++)
5670 {
5671 if (target)
5672 target[i] = (char)ch;
5673 self->InStream(self, &ch);
5674 }
5675
5676 if (target)
5677 target[i] = NIL;
5678 return TRUE;
5679}
5680
5681/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005682 * TrioReadDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +00005683 *
5684 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005685 * add long double
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005686 * handle base
Daniel Veillard92ad2102001-03-27 12:47:33 +00005687 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005688TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005689TrioReadDouble
5690TRIO_ARGS4((self, target, flags, width),
5691 trio_class_t *self,
5692 trio_pointer_t target,
5693 unsigned long flags,
5694 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005695{
5696 int ch;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005697 char doubleString[512];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005698 int index = 0;
5699 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005700 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005701 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005702
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005703 doubleString[0] = 0;
5704
Bjorn Reese70a9da52001-04-21 16:57:29 +00005705 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005706 width = sizeof(doubleString) - 1;
5707
5708 TrioSkipWhitespaces(self);
5709
Bjorn Reese70a9da52001-04-21 16:57:29 +00005710 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +00005711 * Read entire double number from stream. trio_to_double requires
5712 * a string as input, but InStream can be anything, so we have to
Daniel Veillard92ad2102001-03-27 12:47:33 +00005713 * collect all characters.
5714 */
5715 ch = self->current;
5716 if ((ch == '+') || (ch == '-'))
5717 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005718 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005719 self->InStream(self, &ch);
5720 width--;
5721 }
5722
5723 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005724 switch (ch)
5725 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00005726 case 'n':
5727 case 'N':
5728 /* Not-a-number */
5729 if (index != 0)
5730 break;
5731 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005732 case 'i':
5733 case 'I':
5734 /* Infinity */
5735 while (isalpha(ch) && (index - start < width))
5736 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005737 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005738 self->InStream(self, &ch);
5739 }
5740 doubleString[index] = NIL;
5741
Daniel Veillard92ad2102001-03-27 12:47:33 +00005742 /* Case insensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005743 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5744 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005745 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005746 if (flags & FLAGS_LONGDOUBLE)
5747 {
5748 if ((start == 1) && (doubleString[0] == '-'))
5749 {
5750 *((trio_long_double_t *)target) = trio_ninf();
5751 }
5752 else
5753 {
5754 *((trio_long_double_t *)target) = trio_pinf();
5755 }
5756 }
5757 else
5758 {
5759 if ((start == 1) && (doubleString[0] == '-'))
5760 {
5761 *((double *)target) = trio_ninf();
5762 }
5763 else
5764 {
5765 *((double *)target) = trio_pinf();
5766 }
5767 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005768 return TRUE;
5769 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005770 if (trio_equal(doubleString, NAN_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005771 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005772 /* NaN must not have a preceeding + nor - */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005773 if (flags & FLAGS_LONGDOUBLE)
5774 {
5775 *((trio_long_double_t *)target) = trio_nan();
5776 }
5777 else
5778 {
5779 *((double *)target) = trio_nan();
5780 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005781 return TRUE;
5782 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005783 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005784
5785 case '0':
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005786 doubleString[index++] = (char)ch;
5787 self->InStream(self, &ch);
5788 if (toupper(ch) == 'X')
5789 {
5790 isHex = TRUE;
5791 doubleString[index++] = (char)ch;
5792 self->InStream(self, &ch);
5793 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005794 break;
5795
5796 default:
5797 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005798 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005799
Bjorn Reese70a9da52001-04-21 16:57:29 +00005800 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005801 {
5802 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005803 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00005804 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005805 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005806 self->InStream(self, &ch);
5807 }
5808 else if (flags & FLAGS_QUOTE)
5809 {
5810 /* Compare with thousands separator */
5811 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5812 {
5813 if (internalThousandSeparator[j] != self->current)
5814 break;
5815
5816 self->InStream(self, &ch);
5817 }
5818 if (internalThousandSeparator[j])
5819 break; /* Mismatch */
5820 else
5821 continue; /* Match */
5822 }
5823 else
5824 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005825 }
5826 if (ch == '.')
5827 {
5828 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005829 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005830 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005831 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5832 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005833 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005834 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005835 self->InStream(self, &ch);
5836 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005837 if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005838 {
5839 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005840 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005841 self->InStream(self, &ch);
5842 if ((ch == '+') || (ch == '-'))
5843 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005844 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005845 self->InStream(self, &ch);
5846 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005847 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5848 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005849 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005850 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005851 self->InStream(self, &ch);
5852 }
5853 }
5854 }
5855
5856 if ((index == start) || (*doubleString == NIL))
5857 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005858
5859 doubleString[index] = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005860
5861 if (flags & FLAGS_LONGDOUBLE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005862 {
5863 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5864 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005865 else
5866 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005867 *((double *)target) = trio_to_double(doubleString, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005868 }
5869 return TRUE;
5870}
5871
5872/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005873 * TrioReadPointer
Daniel Veillard92ad2102001-03-27 12:47:33 +00005874 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005875TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005876TrioReadPointer
5877TRIO_ARGS3((self, target, flags),
5878 trio_class_t *self,
5879 trio_pointer_t *target,
5880 unsigned long flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005881{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005882 trio_uintmax_t number;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005883 char buffer[sizeof(internalNullString)];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005884
5885 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5886
5887 if (TrioReadNumber(self,
5888 &number,
5889 flags,
5890 POINTER_WIDTH,
5891 BASE_HEX))
5892 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005893 /*
5894 * The strange assignment of number is a workaround for a compiler
5895 * warning
5896 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005897 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005898 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005899 return TRUE;
5900 }
5901 else if (TrioReadString(self,
5902 (flags & FLAGS_IGNORE)
5903 ? NULL
5904 : buffer,
5905 0,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005906 sizeof(internalNullString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005907 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005908 if (trio_equal_case(buffer, internalNullString))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005909 {
5910 if (target)
5911 *target = NULL;
5912 return TRUE;
5913 }
5914 }
5915 return FALSE;
5916}
5917
5918/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005919 * TrioScanProcess
Daniel Veillard92ad2102001-03-27 12:47:33 +00005920 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005921TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005922TrioScanProcess
5923TRIO_ARGS3((data, format, parameters),
5924 trio_class_t *data,
5925 TRIO_CONST char *format,
5926 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005927{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005928#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005929 int charlen;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005930 int cnt;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005931#endif
5932 int assignment;
5933 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005934 int index; /* Index of format string */
5935 int i; /* Index of current parameter */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005936 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005937 int width;
5938 int base;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005939 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005940
Daniel Veillard92ad2102001-03-27 12:47:33 +00005941 assignment = 0;
5942 i = 0;
5943 index = 0;
5944 data->InStream(data, &ch);
5945
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005946#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005947 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005948#endif
5949
5950 while (format[index])
5951 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005952#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005953 if (! isascii(format[index]))
5954 {
5955 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005956 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005957 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005958 /* Compare multibyte characters in format string */
5959 for (cnt = 0; cnt < charlen - 1; cnt++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005960 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005961 if (ch != format[index + cnt])
5962 {
5963 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5964 }
5965 data->InStream(data, &ch);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005966 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005967 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005968 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005969 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005970#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005971
5972 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
5973 {
5974 return (assignment > 0) ? assignment : EOF;
5975 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005976
5977 if (CHAR_IDENTIFIER == format[index])
5978 {
5979 if (CHAR_IDENTIFIER == format[index + 1])
5980 {
5981 /* Two % in format matches one % in input stream */
5982 if (CHAR_IDENTIFIER == ch)
5983 {
5984 data->InStream(data, &ch);
5985 index += 2;
5986 continue; /* while format chars left */
5987 }
5988 else
5989 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5990 }
5991
5992 /* Skip the parameter entries */
5993 while (parameters[i].type == FORMAT_PARAMETER)
5994 i++;
5995
5996 flags = parameters[i].flags;
5997 /* Find width */
5998 width = parameters[i].width;
5999 if (flags & FLAGS_WIDTH_PARAMETER)
6000 {
6001 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006002 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006003 }
6004 /* Find base */
6005 base = parameters[i].base;
6006 if (flags & FLAGS_BASE_PARAMETER)
6007 {
6008 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006009 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006010 }
6011
6012 switch (parameters[i].type)
6013 {
6014 case FORMAT_INT:
6015 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006016 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006017
6018 if (0 == base)
6019 base = BASE_DECIMAL;
6020
6021 if (!TrioReadNumber(data,
6022 &number,
6023 flags,
6024 width,
6025 base))
6026 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006027
Daniel Veillard92ad2102001-03-27 12:47:33 +00006028 if (!(flags & FLAGS_IGNORE))
6029 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006030 assignment++;
6031
Daniel Veillard92ad2102001-03-27 12:47:33 +00006032 pointer = parameters[i].data.pointer;
6033#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6034 if (flags & FLAGS_SIZE_T)
6035 *(size_t *)pointer = (size_t)number;
6036 else
6037#endif
6038#if defined(QUALIFIER_PTRDIFF_T)
6039 if (flags & FLAGS_PTRDIFF_T)
6040 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6041 else
6042#endif
6043#if defined(QUALIFIER_INTMAX_T)
6044 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006045 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006046 else
6047#endif
6048 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006049 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006050 else if (flags & FLAGS_LONG)
6051 *(long int *)pointer = (long int)number;
6052 else if (flags & FLAGS_SHORT)
6053 *(short int *)pointer = (short int)number;
6054 else
6055 *(int *)pointer = (int)number;
6056 }
6057 }
6058 break; /* FORMAT_INT */
6059
6060 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006061#if TRIO_WIDECHAR
6062 if (flags & FLAGS_WIDECHAR)
6063 {
6064 if (!TrioReadWideString(data,
6065 (flags & FLAGS_IGNORE)
6066 ? NULL
6067 : parameters[i].data.wstring,
6068 flags,
6069 width))
6070 return assignment;
6071 }
6072 else
6073#endif
6074 {
6075 if (!TrioReadString(data,
6076 (flags & FLAGS_IGNORE)
6077 ? NULL
6078 : parameters[i].data.string,
6079 flags,
6080 width))
6081 return assignment;
6082 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006083 if (!(flags & FLAGS_IGNORE))
6084 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006085 break; /* FORMAT_STRING */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006086
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006087 case FORMAT_DOUBLE:
6088 {
6089 trio_pointer_t pointer;
6090
6091 if (flags & FLAGS_IGNORE)
6092 {
6093 pointer = NULL;
6094 }
6095 else
6096 {
6097 pointer = (flags & FLAGS_LONGDOUBLE)
6098 ? (trio_pointer_t)parameters[i].data.longdoublePointer
6099 : (trio_pointer_t)parameters[i].data.doublePointer;
6100 }
6101 if (!TrioReadDouble(data, pointer, flags, width))
6102 {
6103 return assignment;
6104 }
6105 if (!(flags & FLAGS_IGNORE))
6106 {
6107 assignment++;
6108 }
6109 break; /* FORMAT_DOUBLE */
6110 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006111 case FORMAT_GROUP:
6112 {
6113 int characterclass[MAX_CHARACTER_CLASS + 1];
6114 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006115
6116 /* Skip over modifiers */
6117 while (format[index] != SPECIFIER_GROUP)
6118 {
6119 index++;
6120 }
6121 /* Skip over group specifier */
6122 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006123
Daniel Veillard92ad2102001-03-27 12:47:33 +00006124 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006125 rc = TrioGetCharacterClass(format,
6126 &index,
6127 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006128 characterclass);
6129 if (rc < 0)
6130 return rc;
6131
6132 if (!TrioReadGroup(data,
6133 (flags & FLAGS_IGNORE)
6134 ? NULL
6135 : parameters[i].data.string,
6136 characterclass,
6137 flags,
6138 parameters[i].width))
6139 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006140 if (!(flags & FLAGS_IGNORE))
6141 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006142 }
6143 break; /* FORMAT_GROUP */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006144
Daniel Veillard92ad2102001-03-27 12:47:33 +00006145 case FORMAT_COUNT:
6146 pointer = parameters[i].data.pointer;
6147 if (NULL != pointer)
6148 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006149 int count = data->committed;
6150 if (ch != EOF)
6151 count--; /* a character is read, but is not consumed yet */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006152#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6153 if (flags & FLAGS_SIZE_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006154 *(size_t *)pointer = (size_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006155 else
6156#endif
6157#if defined(QUALIFIER_PTRDIFF_T)
6158 if (flags & FLAGS_PTRDIFF_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006159 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006160 else
6161#endif
6162#if defined(QUALIFIER_INTMAX_T)
6163 if (flags & FLAGS_INTMAX_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006164 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006165 else
6166#endif
6167 if (flags & FLAGS_QUAD)
6168 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006169 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006170 }
6171 else if (flags & FLAGS_LONG)
6172 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006173 *(long int *)pointer = (long int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006174 }
6175 else if (flags & FLAGS_SHORT)
6176 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006177 *(short int *)pointer = (short int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006178 }
6179 else
6180 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006181 *(int *)pointer = (int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006182 }
6183 }
6184 break; /* FORMAT_COUNT */
6185
6186 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006187#if TRIO_WIDECHAR
6188 if (flags & FLAGS_WIDECHAR)
6189 {
6190 if (TrioReadWideChar(data,
6191 (flags & FLAGS_IGNORE)
6192 ? NULL
6193 : parameters[i].data.wstring,
6194 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006195 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006196 return assignment;
6197 }
6198 else
6199#endif
6200 {
6201 if (TrioReadChar(data,
6202 (flags & FLAGS_IGNORE)
6203 ? NULL
6204 : parameters[i].data.string,
6205 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006206 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006207 return assignment;
6208 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006209 if (!(flags & FLAGS_IGNORE))
6210 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006211 break; /* FORMAT_CHAR */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006212
Daniel Veillard92ad2102001-03-27 12:47:33 +00006213 case FORMAT_POINTER:
6214 if (!TrioReadPointer(data,
6215 (flags & FLAGS_IGNORE)
6216 ? NULL
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006217 : (trio_pointer_t *)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006218 flags))
6219 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006220 if (!(flags & FLAGS_IGNORE))
6221 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006222 break; /* FORMAT_POINTER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006223
Daniel Veillard92ad2102001-03-27 12:47:33 +00006224 case FORMAT_PARAMETER:
6225 break; /* FORMAT_PARAMETER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006226
Daniel Veillard92ad2102001-03-27 12:47:33 +00006227 default:
6228 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6229 }
6230 ch = data->current;
6231 index = parameters[i].indexAfterSpecifier;
6232 i++;
6233 }
6234 else /* Not an % identifier */
6235 {
6236 if (isspace((int)format[index]))
6237 {
6238 /* Whitespaces may match any amount of whitespaces */
6239 ch = TrioSkipWhitespaces(data);
6240 }
6241 else if (ch == format[index])
6242 {
6243 data->InStream(data, &ch);
6244 }
6245 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00006246 return assignment;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006247
6248 index++;
6249 }
6250 }
6251 return assignment;
6252}
6253
6254/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006255 * TrioScan
Daniel Veillard92ad2102001-03-27 12:47:33 +00006256 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006257TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006258TrioScan
6259TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6260 trio_pointer_t source,
6261 size_t sourceSize,
6262 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6263 TRIO_CONST char *format,
6264 va_list *arglist,
6265 trio_pointer_t *argarray)
Bjorn Reese026d29f2002-01-19 15:40:18 +00006266{
6267 int status;
6268 trio_parameter_t parameters[MAX_PARAMETERS];
6269 trio_class_t data;
6270
6271 assert(VALID(InStream));
6272 assert(VALID(format));
6273
6274 memset(&data, 0, sizeof(data));
6275 data.InStream = InStream;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006276 data.location = (trio_pointer_t)source;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006277 data.max = sourceSize;
6278 data.error = 0;
6279
6280#if defined(USE_LOCALE)
6281 if (NULL == internalLocaleValues)
6282 {
6283 TrioSetLocale();
6284 }
6285#endif
6286
6287 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6288 if (status < 0)
6289 return status;
6290
6291 status = TrioScanProcess(&data, format, parameters);
6292 if (data.error != 0)
6293 {
6294 status = data.error;
6295 }
6296 return status;
6297}
6298
6299/*************************************************************************
6300 * TrioInStreamFile
6301 */
6302TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006303TrioInStreamFile
6304TRIO_ARGS2((self, intPointer),
6305 trio_class_t *self,
6306 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006307{
6308 FILE *file = (FILE *)self->location;
6309
6310 assert(VALID(self));
6311 assert(VALID(file));
6312
6313 self->current = fgetc(file);
Bjorn Reese026d29f2002-01-19 15:40:18 +00006314 if (self->current == EOF)
6315 {
6316 self->error = (ferror(file))
6317 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6318 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
6319 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006320 else
6321 {
6322 self->processed++;
6323 self->committed++;
6324 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006325
6326 if (VALID(intPointer))
6327 {
6328 *intPointer = self->current;
6329 }
6330}
6331
6332/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006333 * TrioInStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00006334 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006335TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006336TrioInStreamFileDescriptor
6337TRIO_ARGS2((self, intPointer),
6338 trio_class_t *self,
6339 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006340{
6341 int fd = *((int *)self->location);
6342 int size;
6343 unsigned char input;
6344
6345 assert(VALID(self));
6346
6347 size = read(fd, &input, sizeof(char));
Bjorn Reese026d29f2002-01-19 15:40:18 +00006348 if (size == -1)
6349 {
6350 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6351 self->current = EOF;
6352 }
6353 else
6354 {
6355 self->current = (size == 0) ? EOF : input;
6356 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006357 if (self->current != EOF)
6358 {
6359 self->committed++;
6360 self->processed++;
6361 }
6362
6363 if (VALID(intPointer))
6364 {
6365 *intPointer = self->current;
6366 }
6367}
6368
6369/*************************************************************************
6370 * TrioInStreamCustom
6371 */
6372TRIO_PRIVATE void
6373TrioInStreamCustom
6374TRIO_ARGS2((self, intPointer),
6375 trio_class_t *self,
6376 int *intPointer)
6377{
6378 trio_custom_t *data;
6379
6380 assert(VALID(self));
6381 assert(VALID(self->location));
6382
6383 data = (trio_custom_t *)self->location;
6384
6385 self->current = (data->stream.in == NULL)
6386 ? NIL
6387 : (data->stream.in)(data->closure);
6388
6389 if (self->current == NIL)
6390 {
6391 self->current = EOF;
6392 }
6393 else
6394 {
6395 self->processed++;
6396 self->committed++;
6397 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006398
6399 if (VALID(intPointer))
6400 {
6401 *intPointer = self->current;
6402 }
6403}
6404
6405/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006406 * TrioInStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00006407 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006408TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006409TrioInStreamString
6410TRIO_ARGS2((self, intPointer),
6411 trio_class_t *self,
6412 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006413{
6414 unsigned char **buffer;
6415
6416 assert(VALID(self));
Daniel Veillard92ad2102001-03-27 12:47:33 +00006417 assert(VALID(self->location));
6418
6419 buffer = (unsigned char **)self->location;
6420 self->current = (*buffer)[0];
6421 if (self->current == NIL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006422 {
6423 self->current = EOF;
6424 }
6425 else
6426 {
6427 (*buffer)++;
6428 self->processed++;
6429 self->committed++;
6430 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006431
6432 if (VALID(intPointer))
6433 {
6434 *intPointer = self->current;
6435 }
6436}
6437
6438/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006439 *
6440 * Formatted scanning functions
6441 *
6442 ************************************************************************/
6443
6444#if defined(TRIO_DOCUMENTATION)
6445# include "doc/doc_scanf.h"
6446#endif
6447/** @addtogroup Scanf
6448 @{
6449*/
6450
6451/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00006452 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00006453 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006454
6455/**
6456 Scan characters from standard input stream.
6457
6458 @param format Formatting string.
6459 @param ... Arguments.
6460 @return Number of scanned characters.
6461 */
6462TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006463trio_scanf
6464TRIO_VARGS2((format, va_alist),
6465 TRIO_CONST char *format,
6466 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006467{
6468 int status;
6469 va_list args;
6470
6471 assert(VALID(format));
6472
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006473 TRIO_VA_START(args, format);
6474 status = TrioScan((trio_pointer_t)stdin, 0,
6475 TrioInStreamFile,
6476 format, &args, NULL);
6477 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006478 return status;
6479}
6480
Bjorn Reese026d29f2002-01-19 15:40:18 +00006481TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006482trio_vscanf
6483TRIO_ARGS2((format, args),
6484 TRIO_CONST char *format,
6485 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006486{
6487 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006488
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006489 return TrioScan((trio_pointer_t)stdin, 0,
6490 TrioInStreamFile,
6491 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006492}
6493
Bjorn Reese026d29f2002-01-19 15:40:18 +00006494TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006495trio_scanfv
6496TRIO_ARGS2((format, args),
6497 TRIO_CONST char *format,
6498 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006499{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006500 assert(VALID(format));
6501
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006502 return TrioScan((trio_pointer_t)stdin, 0,
6503 TrioInStreamFile,
6504 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006505}
6506
6507/*************************************************************************
6508 * fscanf
6509 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006510TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006511trio_fscanf
6512TRIO_VARGS3((file, format, va_alist),
6513 FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006514 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006515 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006516{
6517 int status;
6518 va_list args;
6519
6520 assert(VALID(file));
6521 assert(VALID(format));
6522
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006523 TRIO_VA_START(args, format);
6524 status = TrioScan((trio_pointer_t)file, 0,
6525 TrioInStreamFile,
6526 format, &args, NULL);
6527 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006528 return status;
6529}
6530
Bjorn Reese026d29f2002-01-19 15:40:18 +00006531TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006532trio_vfscanf
6533TRIO_ARGS3((file, format, args),
6534 FILE *file,
6535 TRIO_CONST char *format,
6536 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006537{
6538 assert(VALID(file));
6539 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006540
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006541 return TrioScan((trio_pointer_t)file, 0,
6542 TrioInStreamFile,
6543 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006544}
6545
Bjorn Reese026d29f2002-01-19 15:40:18 +00006546TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006547trio_fscanfv
6548TRIO_ARGS3((file, format, args),
6549 FILE *file,
6550 TRIO_CONST char *format,
6551 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006552{
6553 assert(VALID(file));
6554 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006555
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006556 return TrioScan((trio_pointer_t)file, 0,
6557 TrioInStreamFile,
6558 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006559}
6560
6561/*************************************************************************
6562 * dscanf
6563 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006564TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006565trio_dscanf
6566TRIO_VARGS3((fd, format, va_alist),
6567 int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006568 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006569 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006570{
6571 int status;
6572 va_list args;
6573
6574 assert(VALID(format));
6575
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006576 TRIO_VA_START(args, format);
6577 status = TrioScan((trio_pointer_t)&fd, 0,
6578 TrioInStreamFileDescriptor,
6579 format, &args, NULL);
6580 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006581 return status;
6582}
6583
Bjorn Reese026d29f2002-01-19 15:40:18 +00006584TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006585trio_vdscanf
6586TRIO_ARGS3((fd, format, args),
6587 int fd,
6588 TRIO_CONST char *format,
6589 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006590{
6591 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006592
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006593 return TrioScan((trio_pointer_t)&fd, 0,
6594 TrioInStreamFileDescriptor,
6595 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006596}
6597
Bjorn Reese026d29f2002-01-19 15:40:18 +00006598TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006599trio_dscanfv
6600TRIO_ARGS3((fd, format, args),
6601 int fd,
6602 TRIO_CONST char *format,
6603 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006604{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006605 assert(VALID(format));
6606
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006607 return TrioScan((trio_pointer_t)&fd, 0,
6608 TrioInStreamFileDescriptor,
6609 format, NULL, args);
6610}
6611
6612/*************************************************************************
6613 * cscanf
6614 */
6615TRIO_PUBLIC int
6616trio_cscanf
6617TRIO_VARGS4((stream, closure, format, va_alist),
6618 trio_instream_t stream,
6619 trio_pointer_t closure,
6620 TRIO_CONST char *format,
6621 TRIO_VA_DECL)
6622{
6623 int status;
6624 va_list args;
6625 trio_custom_t data;
6626
6627 assert(VALID(stream));
6628 assert(VALID(format));
6629
6630 TRIO_VA_START(args, format);
6631 data.stream.in = stream;
6632 data.closure = closure;
6633 status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6634 TRIO_VA_END(args);
6635 return status;
6636}
6637
6638TRIO_PUBLIC int
6639trio_vcscanf
6640TRIO_ARGS4((stream, closure, format, args),
6641 trio_instream_t stream,
6642 trio_pointer_t closure,
6643 TRIO_CONST char *format,
6644 va_list args)
6645{
6646 trio_custom_t data;
6647
6648 assert(VALID(stream));
6649 assert(VALID(format));
6650
6651 data.stream.in = stream;
6652 data.closure = closure;
6653 return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6654}
6655
6656TRIO_PUBLIC int
6657trio_cscanfv
6658TRIO_ARGS4((stream, closure, format, args),
6659 trio_instream_t stream,
6660 trio_pointer_t closure,
6661 TRIO_CONST char *format,
6662 trio_pointer_t *args)
6663{
6664 trio_custom_t data;
6665
6666 assert(VALID(stream));
6667 assert(VALID(format));
6668
6669 data.stream.in = stream;
6670 data.closure = closure;
6671 return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006672}
6673
6674/*************************************************************************
6675 * sscanf
6676 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006677TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006678trio_sscanf
6679TRIO_VARGS3((buffer, format, va_alist),
6680 TRIO_CONST char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006681 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006682 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006683{
6684 int status;
6685 va_list args;
6686
6687 assert(VALID(buffer));
6688 assert(VALID(format));
6689
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006690 TRIO_VA_START(args, format);
6691 status = TrioScan((trio_pointer_t)&buffer, 0,
6692 TrioInStreamString,
6693 format, &args, NULL);
6694 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006695 return status;
6696}
6697
Bjorn Reese026d29f2002-01-19 15:40:18 +00006698TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006699trio_vsscanf
6700TRIO_ARGS3((buffer, format, args),
6701 TRIO_CONST char *buffer,
6702 TRIO_CONST char *format,
6703 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006704{
6705 assert(VALID(buffer));
6706 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006707
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006708 return TrioScan((trio_pointer_t)&buffer, 0,
6709 TrioInStreamString,
6710 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006711}
6712
Bjorn Reese026d29f2002-01-19 15:40:18 +00006713TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006714trio_sscanfv
6715TRIO_ARGS3((buffer, format, args),
6716 TRIO_CONST char *buffer,
6717 TRIO_CONST char *format,
6718 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006719{
6720 assert(VALID(buffer));
6721 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006722
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006723 return TrioScan((trio_pointer_t)&buffer, 0,
6724 TrioInStreamString,
6725 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006726}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006727
Bjorn Reese026d29f2002-01-19 15:40:18 +00006728/** @} End of Scanf documentation module */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006729
6730/*************************************************************************
6731 * trio_strerror
6732 */
6733TRIO_PUBLIC TRIO_CONST char *
6734trio_strerror
6735TRIO_ARGS1((errorcode),
6736 int errorcode)
6737{
6738 /* Textual versions of the error codes */
6739 switch (TRIO_ERROR_CODE(errorcode))
6740 {
6741 case TRIO_EOF:
6742 return "End of file";
6743 case TRIO_EINVAL:
6744 return "Invalid argument";
6745 case TRIO_ETOOMANY:
6746 return "Too many arguments";
6747 case TRIO_EDBLREF:
6748 return "Double reference";
6749 case TRIO_EGAP:
6750 return "Reference gap";
6751 case TRIO_ENOMEM:
6752 return "Out of memory";
6753 case TRIO_ERANGE:
6754 return "Invalid range";
6755 case TRIO_ECUSTOM:
6756 return "Custom error";
6757 default:
6758 return "Unknown";
6759 }
6760}