blob: fc0ae620776d7c2aecbc9139f143704accc4054f [file] [log] [blame]
Daniel Veillard92ad2102001-03-27 12:47:33 +00001/*************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 *************************************************************************
17 *
Bjorn Reese70a9da52001-04-21 16:57:29 +000018 * A note to trio contributors:
19 *
Daniel Veillard92ad2102001-03-27 12:47:33 +000020 * Avoid heap allocation at all costs to ensure that the trio functions
21 * are async-safe. The exceptions are the printf/fprintf functions, which
22 * uses fputc, and the asprintf functions and the <alloc> modifier, which
23 * by design are required to allocate form the heap.
24 *
25 ************************************************************************/
26
Daniel Veillard92ad2102001-03-27 12:47:33 +000027/*
Bjorn Reese70a9da52001-04-21 16:57:29 +000028 * TODO:
Daniel Veillard92ad2102001-03-27 12:47:33 +000029 * - Scan is probably too permissive about its modifiers.
Daniel Veillard92ad2102001-03-27 12:47:33 +000030 * - C escapes in %#[] ?
31 * - Multibyte characters (done for format parsing, except scan groups)
Daniel Veillard92ad2102001-03-27 12:47:33 +000032 * - Complex numbers? (C99 _Complex)
33 * - Boolean values? (C99 _Bool)
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000034 * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
35 * to print the mantissa, e.g. NaN(0xc000000000000000)
Daniel Veillard92ad2102001-03-27 12:47:33 +000036 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
37 * for %a, because C99 used %a for other purposes. If specified as
38 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
39 * the C99 hex-float. This means that you cannot scan %as as a hex-float
40 * immediately followed by an 's'.
Bjorn Reese906ec8a2001-06-05 12:46:33 +000041 * - Scanning of collating symbols.
Daniel Veillard92ad2102001-03-27 12:47:33 +000042 */
43
Daniel Veillard92ad2102001-03-27 12:47:33 +000044/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +000045 * Trio include files
Daniel Veillard92ad2102001-03-27 12:47:33 +000046 */
Bjorn Reese45029602001-08-21 09:23:53 +000047#include "triodef.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000048#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000049#include "triop.h"
Bjorn Reese45029602001-08-21 09:23:53 +000050#include "trionan.h"
Daniel Veillardb7c29c32002-09-25 22:44:43 +000051#if !defined(TRIO_MINIMAL)
52# include "triostr.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000053#endif
54
Daniel Veillardb7c29c32002-09-25 22:44:43 +000055/**************************************************************************
56 *
57 * Definitions
58 *
59 *************************************************************************/
60
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000061#include <math.h>
62#include <limits.h>
63#include <float.h>
64
Bjorn Reese906ec8a2001-06-05 12:46:33 +000065#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
66# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
67# if !defined(MB_LEN_MAX)
68# define MB_LEN_MAX 6
69# endif
70#endif
71
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000072#if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
73# define TRIO_COMPILER_SUPPORTS_MSVC_INT
74#endif
75
Bjorn Reese906ec8a2001-06-05 12:46:33 +000076/*************************************************************************
77 * Generic definitions
78 */
79
80#if !(defined(DEBUG) || defined(NDEBUG))
81# define NDEBUG
82#endif
Daniel Veillarda48ed3d2003-04-03 15:28:28 +000083
Bjorn Reese906ec8a2001-06-05 12:46:33 +000084#include <assert.h>
85#include <ctype.h>
86#if !defined(TRIO_COMPILER_SUPPORTS_C99)
87# define isblank(x) (((x)==32) || ((x)==9))
88#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +000089#if defined(TRIO_COMPILER_ANCIENT)
90# include <varargs.h>
91#else
92# include <stdarg.h>
93#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +000094#include <stddef.h>
95#include <errno.h>
96
97#ifndef NULL
98# define NULL 0
99#endif
100#define NIL ((char)0)
101#ifndef FALSE
102# define FALSE (1 == 0)
103# define TRUE (! FALSE)
104#endif
105#define BOOLEAN_T int
106
107/* mincore() can be used for debugging purposes */
108#define VALID(x) (NULL != (x))
109
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000110#if TRIO_ERRORS
111 /*
112 * Encode the error code and the position. This is decoded
113 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
114 */
115# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
116#else
117# define TRIO_ERROR_RETURN(x,y) (-1)
118#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000119
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000120typedef unsigned long trio_flags_t;
121
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000122
123/*************************************************************************
124 * Platform specific definitions
125 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000126#if defined(TRIO_PLATFORM_UNIX)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000127# include <unistd.h>
128# include <signal.h>
129# include <locale.h>
130# define USE_LOCALE
Bjorn Reese026d29f2002-01-19 15:40:18 +0000131#endif /* TRIO_PLATFORM_UNIX */
132#if defined(TRIO_PLATFORM_VMS)
133# include <unistd.h>
134#endif
135#if defined(TRIO_PLATFORM_WIN32)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000136# include <io.h>
137# define read _read
138# define write _write
Bjorn Reese026d29f2002-01-19 15:40:18 +0000139#endif /* TRIO_PLATFORM_WIN32 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000140
141#if TRIO_WIDECHAR
142# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
143# include <wchar.h>
144# include <wctype.h>
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000145typedef wchar_t trio_wchar_t;
146typedef wint_t trio_wint_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000147# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000148typedef char trio_wchar_t;
149typedef int trio_wint_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000150# define WCONST(x) L ## x
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000151# define WEOF EOF
152# define iswalnum(x) isalnum(x)
153# define iswalpha(x) isalpha(x)
154# define iswblank(x) isblank(x)
155# define iswcntrl(x) iscntrl(x)
156# define iswdigit(x) isdigit(x)
157# define iswgraph(x) isgraph(x)
158# define iswlower(x) islower(x)
159# define iswprint(x) isprint(x)
160# define iswpunct(x) ispunct(x)
161# define iswspace(x) isspace(x)
162# define iswupper(x) isupper(x)
163# define iswxdigit(x) isxdigit(x)
164# endif
165#endif
166
167
168/*************************************************************************
169 * Compiler dependent definitions
170 */
171
172/* Support for long long */
173#ifndef __cplusplus
174# if !defined(USE_LONGLONG)
Bjorn Reese026d29f2002-01-19 15:40:18 +0000175# if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000176# define USE_LONGLONG
Bjorn Reese026d29f2002-01-19 15:40:18 +0000177# elif defined(TRIO_COMPILER_SUNPRO)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000178# define USE_LONGLONG
179# elif defined(_LONG_LONG) || defined(_LONGLONG)
180# define USE_LONGLONG
181# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000182# endif
183#endif
184
185/* The extra long numbers */
186#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000187typedef signed long long int trio_longlong_t;
188typedef unsigned long long int trio_ulonglong_t;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000189#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000190typedef signed __int64 trio_longlong_t;
191typedef unsigned __int64 trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000192#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000193typedef TRIO_SIGNED long int trio_longlong_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000194typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000195#endif
196
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000197/* Maximal and fixed integer types */
198#if defined(TRIO_COMPILER_SUPPORTS_C99)
199# include <stdint.h>
200typedef intmax_t trio_intmax_t;
201typedef uintmax_t trio_uintmax_t;
202typedef int8_t trio_int8_t;
203typedef int16_t trio_int16_t;
204typedef int32_t trio_int32_t;
205typedef int64_t trio_int64_t;
206#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
207# include <inttypes.h>
208typedef intmax_t trio_intmax_t;
209typedef uintmax_t trio_uintmax_t;
210typedef int8_t trio_int8_t;
211typedef int16_t trio_int16_t;
212typedef int32_t trio_int32_t;
213typedef int64_t trio_int64_t;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000214#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000215typedef trio_longlong_t trio_intmax_t;
216typedef trio_ulonglong_t trio_uintmax_t;
217typedef __int8 trio_int8_t;
218typedef __int16 trio_int16_t;
219typedef __int32 trio_int32_t;
220typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000221#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000222typedef trio_longlong_t trio_intmax_t;
223typedef trio_ulonglong_t trio_uintmax_t;
224# if defined(TRIO_INT8_T)
225typedef TRIO_INT8_T trio_int8_t;
226# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000227typedef TRIO_SIGNED char trio_int8_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000228# endif
229# if defined(TRIO_INT16_T)
230typedef TRIO_INT16_T trio_int16_t;
231# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000232typedef TRIO_SIGNED short trio_int16_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000233# endif
234# if defined(TRIO_INT32_T)
235typedef TRIO_INT32_T trio_int32_t;
236# else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000237typedef TRIO_SIGNED int trio_int32_t;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000238# endif
239# if defined(TRIO_INT64_T)
240typedef TRIO_INT64_T trio_int64_t;
241# else
242typedef trio_longlong_t trio_int64_t;
243# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000244#endif
245
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000246#if !(defined(TRIO_COMPILER_SUPPORTS_C99) \
247 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))
248# define floorl(x) floor((double)(x))
249# define fmodl(x,y) fmod((double)(x),(double)(y))
250# define powl(x,y) pow((double)(x),(double)(y))
251#endif
252
253#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000254
255/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000256 * Internal Definitions
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000257 */
258
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000259#ifndef DECIMAL_DIG
260# define DECIMAL_DIG DBL_DIG
261#endif
262
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000263/* Long double sizes */
264#ifdef LDBL_DIG
265# define MAX_MANTISSA_DIGITS LDBL_DIG
266# define MAX_EXPONENT_DIGITS 4
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000267# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000268#else
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000269# define MAX_MANTISSA_DIGITS DECIMAL_DIG
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000270# define MAX_EXPONENT_DIGITS 3
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000271# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
272#endif
273
274#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
275# undef LDBL_DIG
276# undef LDBL_MANT_DIG
277# undef LDBL_EPSILON
278# define LDBL_DIG DBL_DIG
279# define LDBL_MANT_DIG DBL_MANT_DIG
280# define LDBL_EPSILON DBL_EPSILON
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000281#endif
282
283/* The maximal number of digits is for base 2 */
284#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000285/* The width of a pointer. The number of bits in a hex digit is 4 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000286#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000287
288/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000289#define INFINITE_LOWER "inf"
290#define INFINITE_UPPER "INF"
291#define LONG_INFINITE_LOWER "infinite"
292#define LONG_INFINITE_UPPER "INFINITE"
293#define NAN_LOWER "nan"
294#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000295
296/* Various constants */
297enum {
298 TYPE_PRINT = 1,
299 TYPE_SCAN = 2,
300
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000301 /* Flags. FLAGS_LAST must be less than ULONG_MAX */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000302 FLAGS_NEW = 0,
303 FLAGS_STICKY = 1,
304 FLAGS_SPACE = 2 * FLAGS_STICKY,
305 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
306 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
307 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
308 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
309 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
310 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
311 FLAGS_QUAD = 2 * FLAGS_LONG,
312 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
313 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
314 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
315 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
316 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
317 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
318 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
319 FLAGS_WIDTH = 2 * FLAGS_UPPER,
320 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
321 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
322 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
323 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
324 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
325 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
326 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
327 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
328 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
329 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
330 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
331 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000332 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
333 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000334 FLAGS_LAST = FLAGS_FIXED_SIZE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000335 /* Reused flags */
336 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000337 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000338 FLAGS_ROUNDING = FLAGS_INTMAX_T,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000339 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000340 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000341 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000342
343 NO_POSITION = -1,
344 NO_WIDTH = 0,
345 NO_PRECISION = -1,
346 NO_SIZE = -1,
347
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000348 /* Do not change these */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000349 NO_BASE = -1,
350 MIN_BASE = 2,
351 MAX_BASE = 36,
352 BASE_BINARY = 2,
353 BASE_OCTAL = 8,
354 BASE_DECIMAL = 10,
355 BASE_HEX = 16,
356
357 /* Maximal number of allowed parameters */
358 MAX_PARAMETERS = 64,
359 /* Maximal number of characters in class */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000360 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000361
Bjorn Reese70a9da52001-04-21 16:57:29 +0000362 /* Maximal string lengths for user-defined specifiers */
363 MAX_USER_NAME = 64,
364 MAX_USER_DATA = 256,
365
Daniel Veillard92ad2102001-03-27 12:47:33 +0000366 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000367 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000368 /* Maximal number of integers in grouping */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000369 MAX_LOCALE_GROUPS = 64,
370
371 /* Initial size of asprintf buffer */
372 DYNAMIC_START_SIZE = 32
Daniel Veillard92ad2102001-03-27 12:47:33 +0000373};
374
375#define NO_GROUPING ((int)CHAR_MAX)
376
377/* Fundamental formatting parameter types */
378#define FORMAT_UNKNOWN 0
379#define FORMAT_INT 1
380#define FORMAT_DOUBLE 2
381#define FORMAT_CHAR 3
382#define FORMAT_STRING 4
383#define FORMAT_POINTER 5
384#define FORMAT_COUNT 6
385#define FORMAT_PARAMETER 7
386#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000387#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000388# define FORMAT_ERRNO 9
389#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000390#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000391# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000392#endif
393
394/* Character constants */
395#define CHAR_IDENTIFIER '%'
396#define CHAR_BACKSLASH '\\'
397#define CHAR_QUOTE '\"'
398#define CHAR_ADJUST ' '
399
400/* Character class expressions */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000401#define CLASS_ALNUM "[:alnum:]"
402#define CLASS_ALPHA "[:alpha:]"
403#define CLASS_BLANK "[:blank:]"
404#define CLASS_CNTRL "[:cntrl:]"
405#define CLASS_DIGIT "[:digit:]"
406#define CLASS_GRAPH "[:graph:]"
407#define CLASS_LOWER "[:lower:]"
408#define CLASS_PRINT "[:print:]"
409#define CLASS_PUNCT "[:punct:]"
410#define CLASS_SPACE "[:space:]"
411#define CLASS_UPPER "[:upper:]"
412#define CLASS_XDIGIT "[:xdigit:]"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000413
414/*
415 * SPECIFIERS:
416 *
417 *
418 * a Hex-float
419 * A Hex-float
420 * c Character
421 * C Widechar character (wint_t)
422 * d Decimal
423 * e Float
424 * E Float
425 * F Float
426 * F Float
427 * g Float
428 * G Float
429 * i Integer
430 * m Error message
431 * n Count
432 * o Octal
433 * p Pointer
434 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000435 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000436 * u Unsigned
437 * x Hex
438 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000439 * [] Group
440 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000441 *
442 * Reserved:
443 *
444 * D Binary Coded Decimal %D(length,precision) (OS/390)
445 */
446#define SPECIFIER_CHAR 'c'
447#define SPECIFIER_STRING 's'
448#define SPECIFIER_DECIMAL 'd'
449#define SPECIFIER_INTEGER 'i'
450#define SPECIFIER_UNSIGNED 'u'
451#define SPECIFIER_OCTAL 'o'
452#define SPECIFIER_HEX 'x'
453#define SPECIFIER_HEX_UPPER 'X'
454#define SPECIFIER_FLOAT_E 'e'
455#define SPECIFIER_FLOAT_E_UPPER 'E'
456#define SPECIFIER_FLOAT_F 'f'
457#define SPECIFIER_FLOAT_F_UPPER 'F'
458#define SPECIFIER_FLOAT_G 'g'
459#define SPECIFIER_FLOAT_G_UPPER 'G'
460#define SPECIFIER_POINTER 'p'
461#define SPECIFIER_GROUP '['
462#define SPECIFIER_UNGROUP ']'
463#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000464#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000465# define SPECIFIER_CHAR_UPPER 'C'
466# define SPECIFIER_STRING_UPPER 'S'
467#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000468#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000469# define SPECIFIER_HEXFLOAT 'a'
470# define SPECIFIER_HEXFLOAT_UPPER 'A'
471#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000472#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000473# define SPECIFIER_ERRNO 'm'
474#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000475#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000476# define SPECIFIER_BINARY 'b'
477# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000478# define SPECIFIER_USER_DEFINED_BEGIN '<'
479# define SPECIFIER_USER_DEFINED_END '>'
480# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000481#endif
482
483/*
484 * QUALIFIERS:
485 *
486 *
487 * Numbers = d,i,o,u,x,X
488 * Float = a,A,e,E,f,F,g,G
489 * String = s
490 * Char = c
491 *
492 *
493 * 9$ Position
494 * Use the 9th parameter. 9 can be any number between 1 and
495 * the maximal argument
496 *
497 * 9 Width
498 * Set width to 9. 9 can be any number, but must not be postfixed
499 * by '$'
500 *
501 * h Short
502 * Numbers:
503 * (unsigned) short int
504 *
505 * hh Short short
506 * Numbers:
507 * (unsigned) char
508 *
509 * l Long
510 * Numbers:
511 * (unsigned) long int
512 * String:
513 * as the S specifier
514 * Char:
515 * as the C specifier
516 *
517 * ll Long Long
518 * Numbers:
519 * (unsigned) long long int
520 *
521 * L Long Double
522 * Float
523 * long double
524 *
525 * # Alternative
526 * Float:
527 * Decimal-point is always present
528 * String:
529 * non-printable characters are handled as \number
530 *
531 * Spacing
532 *
533 * + Sign
534 *
535 * - Alignment
536 *
537 * . Precision
538 *
539 * * Parameter
540 * print: use parameter
541 * scan: no parameter (ignore)
542 *
543 * q Quad
544 *
545 * Z size_t
546 *
547 * w Widechar
548 *
549 * ' Thousands/quote
550 * Numbers:
551 * Integer part grouped in thousands
552 * Binary numbers:
553 * Number grouped in nibbles (4 bits)
554 * String:
555 * Quoted string
556 *
557 * j intmax_t
558 * t prtdiff_t
559 * z size_t
560 *
561 * ! Sticky
562 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000563 *
564 * I n-bit Integer
565 * Numbers:
566 * The following options exists
567 * I8 = 8-bit integer
568 * I16 = 16-bit integer
569 * I32 = 32-bit integer
570 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000571 */
572#define QUALIFIER_POSITION '$'
573#define QUALIFIER_SHORT 'h'
574#define QUALIFIER_LONG 'l'
575#define QUALIFIER_LONG_UPPER 'L'
576#define QUALIFIER_ALTERNATIVE '#'
577#define QUALIFIER_SPACE ' '
578#define QUALIFIER_PLUS '+'
579#define QUALIFIER_MINUS '-'
580#define QUALIFIER_DOT '.'
581#define QUALIFIER_STAR '*'
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000582#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000583#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000584# define QUALIFIER_SIZE_T 'z'
585# define QUALIFIER_PTRDIFF_T 't'
586# define QUALIFIER_INTMAX_T 'j'
587#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000588#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000589# define QUALIFIER_QUAD 'q'
590#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000591#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000592# define QUALIFIER_SIZE_T_UPPER 'Z'
593#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000594#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000595# define QUALIFIER_WIDECHAR 'w'
596#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000597#if TRIO_MICROSOFT
598# define QUALIFIER_FIXED_SIZE 'I'
599#endif
600#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000601# define QUALIFIER_QUOTE '\''
602# define QUALIFIER_STICKY '!'
603# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
604# define QUALIFIER_PARAM '@' /* Experimental */
605# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000606# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000607# define QUALIFIER_ROUNDING_UPPER 'R'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000608#endif
609
Bjorn Reese70a9da52001-04-21 16:57:29 +0000610
611/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000612 *
613 * Internal Structures
614 *
615 *************************************************************************/
Bjorn Reese70a9da52001-04-21 16:57:29 +0000616
617/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000618typedef struct {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000619 /* An indication of which entry in the data union is used */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000620 int type;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000621 /* The flags */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +0000622 trio_flags_t flags;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000623 /* The width qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000624 int width;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000625 /* The precision qualifier */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000626 int precision;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000627 /* The base qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000628 int base;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000629 /* The size for the variable size qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000630 int varsize;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000631 /* The marker of the end of the specifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000632 int indexAfterSpecifier;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000633 /* The data from the argument list */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000634 union {
635 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000636#if TRIO_WIDECHAR
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000637 trio_wchar_t *wstring;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000638#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000639 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000640 union {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000641 trio_intmax_t as_signed;
642 trio_uintmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000643 } number;
644 double doubleNumber;
645 double *doublePointer;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000646 trio_long_double_t longdoubleNumber;
647 trio_long_double_t *longdoublePointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000648 int errorNumber;
649 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000650 /* For the user-defined specifier */
651 char user_name[MAX_USER_NAME];
652 char user_data[MAX_USER_DATA];
Bjorn Reese026d29f2002-01-19 15:40:18 +0000653} trio_parameter_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000654
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000655/* Container for customized functions */
656typedef struct {
657 union {
658 trio_outstream_t out;
659 trio_instream_t in;
660 } stream;
661 trio_pointer_t closure;
662} trio_custom_t;
663
Bjorn Reese70a9da52001-04-21 16:57:29 +0000664/* General trio "class" */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000665typedef struct _trio_class_t {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000666 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +0000667 * The function to write characters to a stream.
668 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000669 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000670 /*
671 * The function to read characters from a stream.
672 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000673 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
Bjorn Reese026d29f2002-01-19 15:40:18 +0000674 /*
675 * The current location in the stream.
676 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000677 trio_pointer_t location;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000678 /*
679 * The character currently being processed.
680 */
681 int current;
682 /*
683 * The number of characters that would have been written/read
684 * if there had been sufficient space.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000685 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000686 int processed;
687 /*
688 * The number of characters that are actually written/read.
Bjorn Reese026d29f2002-01-19 15:40:18 +0000689 * Processed and committed will only differ for the *nprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +0000690 * and *nscanf functions.
691 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000692 int committed;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000693 /*
694 * The upper limit of characters that may be written/read.
695 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000696 int max;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000697 /*
698 * The last output error that was detected.
699 */
700 int error;
701} trio_class_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000702
Bjorn Reese70a9da52001-04-21 16:57:29 +0000703/* References (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000704typedef struct _trio_reference_t {
705 trio_class_t *data;
706 trio_parameter_t *parameter;
707} trio_reference_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000708
709/* Registered entries (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000710typedef struct _trio_userdef_t {
711 struct _trio_userdef_t *next;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000712 trio_callback_t callback;
713 char *name;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000714} trio_userdef_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000715
Daniel Veillard92ad2102001-03-27 12:47:33 +0000716/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000717 *
718 * Internal Variables
719 *
720 *************************************************************************/
Daniel Veillard92ad2102001-03-27 12:47:33 +0000721
Bjorn Reese026d29f2002-01-19 15:40:18 +0000722static TRIO_CONST char rcsid[] = "@(#)$Id$";
723
724/*
725 * Need this to workaround a parser bug in HP C/iX compiler that fails
726 * to resolves macro definitions that includes type 'long double',
727 * e.g: va_arg(arg_ptr, long double)
728 */
729#if defined(TRIO_PLATFORM_MPEIX)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000730static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000731#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +0000732
733static TRIO_CONST char internalNullString[] = "(nil)";
Daniel Veillard92ad2102001-03-27 12:47:33 +0000734
Bjorn Reese70a9da52001-04-21 16:57:29 +0000735#if defined(USE_LOCALE)
736static struct lconv *internalLocaleValues = NULL;
737#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000738
Bjorn Reese70a9da52001-04-21 16:57:29 +0000739/*
740 * UNIX98 says "in a locale where the radix character is not defined,
741 * the radix character defaults to a period (.)"
742 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000743static int internalDecimalPointLength = 1;
744static int internalThousandSeparatorLength = 1;
745static char internalDecimalPoint = '.';
746static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000747static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000748static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
749
Bjorn Reese026d29f2002-01-19 15:40:18 +0000750static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
751static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000752static BOOLEAN_T internalDigitsUnconverted = TRUE;
753static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000754#if TRIO_EXTENSION
755static BOOLEAN_T internalCollationUnconverted = TRUE;
756static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
757#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000758
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000759#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +0000760static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
761static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
762static trio_userdef_t *internalUserDef = NULL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000763#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000764
765
766/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000767 *
768 * Internal Functions
769 *
770 ************************************************************************/
771
772#if defined(TRIO_MINIMAL)
773# define TRIO_STRING_PUBLIC static
774# include "triostr.c"
775#endif /* defined(TRIO_MINIMAL) */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000776
777/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000778 * TrioIsQualifier
Daniel Veillard92ad2102001-03-27 12:47:33 +0000779 *
780 * Description:
781 * Remember to add all new qualifiers to this function.
782 * QUALIFIER_POSITION must not be added.
783 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000784TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000785TrioIsQualifier
786TRIO_ARGS1((character),
787 TRIO_CONST char character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000788{
789 /* QUALIFIER_POSITION is not included */
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000790 switch (character)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000791 {
792 case '0': case '1': case '2': case '3': case '4':
793 case '5': case '6': case '7': case '8': case '9':
794 case QUALIFIER_PLUS:
795 case QUALIFIER_MINUS:
796 case QUALIFIER_SPACE:
797 case QUALIFIER_DOT:
798 case QUALIFIER_STAR:
799 case QUALIFIER_ALTERNATIVE:
800 case QUALIFIER_SHORT:
801 case QUALIFIER_LONG:
802 case QUALIFIER_LONG_UPPER:
803 case QUALIFIER_CIRCUMFLEX:
804#if defined(QUALIFIER_SIZE_T)
805 case QUALIFIER_SIZE_T:
806#endif
807#if defined(QUALIFIER_PTRDIFF_T)
808 case QUALIFIER_PTRDIFF_T:
809#endif
810#if defined(QUALIFIER_INTMAX_T)
811 case QUALIFIER_INTMAX_T:
812#endif
813#if defined(QUALIFIER_QUAD)
814 case QUALIFIER_QUAD:
815#endif
816#if defined(QUALIFIER_SIZE_T_UPPER)
817 case QUALIFIER_SIZE_T_UPPER:
818#endif
819#if defined(QUALIFIER_WIDECHAR)
820 case QUALIFIER_WIDECHAR:
821#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000822#if defined(QUALIFIER_QUOTE)
823 case QUALIFIER_QUOTE:
824#endif
825#if defined(QUALIFIER_STICKY)
826 case QUALIFIER_STICKY:
827#endif
828#if defined(QUALIFIER_VARSIZE)
829 case QUALIFIER_VARSIZE:
830#endif
831#if defined(QUALIFIER_PARAM)
832 case QUALIFIER_PARAM:
833#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000834#if defined(QUALIFIER_FIXED_SIZE)
835 case QUALIFIER_FIXED_SIZE:
836#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000837#if defined(QUALIFIER_ROUNDING_UPPER)
838 case QUALIFIER_ROUNDING_UPPER:
839#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000840 return TRUE;
841 default:
842 return FALSE;
843 }
844}
845
846/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000847 * TrioSetLocale
Bjorn Reese70a9da52001-04-21 16:57:29 +0000848 */
849#if defined(USE_LOCALE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000850TRIO_PRIVATE void
851TrioSetLocale(TRIO_NOARGS)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000852{
853 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000854 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000855 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000856 if ((internalLocaleValues->decimal_point) &&
857 (internalLocaleValues->decimal_point[0] != NIL))
858 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000859 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
860 if (internalDecimalPointLength == 1)
861 {
862 internalDecimalPoint = internalLocaleValues->decimal_point[0];
863 }
864 else
865 {
866 internalDecimalPoint = NIL;
867 trio_copy_max(internalDecimalPointString,
868 sizeof(internalDecimalPointString),
869 internalLocaleValues->decimal_point);
870 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000871 }
872 if ((internalLocaleValues->thousands_sep) &&
873 (internalLocaleValues->thousands_sep[0] != NIL))
874 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000875 trio_copy_max(internalThousandSeparator,
876 sizeof(internalThousandSeparator),
877 internalLocaleValues->thousands_sep);
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000878 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000879 }
880 if ((internalLocaleValues->grouping) &&
881 (internalLocaleValues->grouping[0] != NIL))
882 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000883 trio_copy_max(internalGrouping,
884 sizeof(internalGrouping),
885 internalLocaleValues->grouping);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000886 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000887 }
888}
889#endif /* defined(USE_LOCALE) */
890
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000891TRIO_PRIVATE int
892TrioCalcThousandSeparatorLength
893TRIO_ARGS1((digits),
894 int digits)
895{
896#if TRIO_EXTENSION
897 int count = 0;
898 int step = NO_GROUPING;
899 char *groupingPointer = internalGrouping;
900
901 while (digits > 0)
902 {
903 if (*groupingPointer == CHAR_MAX)
904 {
905 /* Disable grouping */
906 break; /* while */
907 }
908 else if (*groupingPointer == 0)
909 {
910 /* Repeat last group */
911 if (step == NO_GROUPING)
912 {
913 /* Error in locale */
914 break; /* while */
915 }
916 }
917 else
918 {
919 step = *groupingPointer++;
920 }
921 if (digits > step)
922 count += internalThousandSeparatorLength;
923 digits -= step;
924 }
925 return count;
926#else
927 return 0;
928#endif
929}
930
931TRIO_PRIVATE BOOLEAN_T
932TrioFollowedBySeparator
933TRIO_ARGS1((position),
934 int position)
935{
936#if TRIO_EXTENSION
937 int step = 0;
938 char *groupingPointer = internalGrouping;
939
940 position--;
941 if (position == 0)
942 return FALSE;
943 while (position > 0)
944 {
945 if (*groupingPointer == CHAR_MAX)
946 {
947 /* Disable grouping */
948 break; /* while */
949 }
950 else if (*groupingPointer != 0)
951 {
952 step = *groupingPointer++;
953 }
954 if (step == 0)
955 break;
956 position -= step;
957 }
958 return (position == 0);
959#else
960 return FALSE;
961#endif
962}
963
Bjorn Reese70a9da52001-04-21 16:57:29 +0000964/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000965 * TrioGetPosition
Daniel Veillard92ad2102001-03-27 12:47:33 +0000966 *
967 * Get the %n$ position.
968 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000969TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000970TrioGetPosition
971TRIO_ARGS2((format, indexPointer),
972 TRIO_CONST char *format,
973 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000974{
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000975#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000976 char *tmpformat;
977 int number = 0;
978 int index = *indexPointer;
979
Bjorn Reese026d29f2002-01-19 15:40:18 +0000980 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +0000981 index = (int)(tmpformat - format);
982 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
983 {
984 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000985 /*
986 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000987 * the array it is indexing starts from 0.
988 */
989 return number - 1;
990 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000991#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000992 return NO_POSITION;
993}
994
Daniel Veillardb7c29c32002-09-25 22:44:43 +0000995#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000996/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000997 * TrioFindNamespace
Bjorn Reese70a9da52001-04-21 16:57:29 +0000998 *
999 * Find registered user-defined specifier.
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001000 * The prev argument is used for optimization only.
Bjorn Reese70a9da52001-04-21 16:57:29 +00001001 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001002TRIO_PRIVATE trio_userdef_t *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001003TrioFindNamespace
1004TRIO_ARGS2((name, prev),
1005 TRIO_CONST char *name,
1006 trio_userdef_t **prev)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001007{
Bjorn Reese026d29f2002-01-19 15:40:18 +00001008 trio_userdef_t *def;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001009
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001010 if (internalEnterCriticalRegion)
1011 (void)internalEnterCriticalRegion(NULL);
1012
Bjorn Reese70a9da52001-04-21 16:57:29 +00001013 for (def = internalUserDef; def; def = def->next)
1014 {
1015 /* Case-sensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001016 if (trio_equal_case(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001017 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001018
1019 if (prev)
1020 *prev = def;
1021 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001022
1023 if (internalLeaveCriticalRegion)
1024 (void)internalLeaveCriticalRegion(NULL);
1025
Bjorn Reese70a9da52001-04-21 16:57:29 +00001026 return def;
1027}
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001028#endif
1029
1030/*************************************************************************
1031 * TrioPower
1032 *
1033 * Description:
1034 * Calculate pow(base, exponent), where number and exponent are integers.
1035 */
1036TRIO_PRIVATE trio_long_double_t
1037TrioPower
1038TRIO_ARGS2((number, exponent),
1039 int number,
1040 int exponent)
1041{
1042 trio_long_double_t result;
1043
1044 if (number == 10)
1045 {
1046 switch (exponent)
1047 {
1048 /* Speed up calculation of common cases */
1049 case 0:
1050 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1051 break;
1052 case 1:
1053 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1054 break;
1055 case 2:
1056 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1057 break;
1058 case 3:
1059 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1060 break;
1061 case 4:
1062 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1063 break;
1064 case 5:
1065 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1066 break;
1067 case 6:
1068 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1069 break;
1070 case 7:
1071 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1072 break;
1073 case 8:
1074 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1075 break;
1076 case 9:
1077 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1078 break;
1079 default:
1080 result = powl((trio_long_double_t)number,
1081 (trio_long_double_t)exponent);
1082 break;
1083 }
1084 }
1085 else
1086 {
1087 return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1088 }
1089 return result;
1090}
1091
1092/*************************************************************************
1093 * TrioLogarithm
1094 */
1095TRIO_PRIVATE double
1096TrioLogarithm
1097TRIO_ARGS2((number, base),
1098 double number,
1099 int base)
1100{
1101 double result;
1102
1103 if (number <= 0.0)
1104 {
1105 /* xlC crashes on log(0) */
1106 result = (number == 0.0) ? trio_ninf() : trio_nan();
1107 }
1108 else
1109 {
1110 if (base == 10)
1111 {
1112 result = log10(number);
1113 }
1114 else
1115 {
1116 result = log10(number) / log10((double)base);
1117 }
1118 }
1119 return result;
1120}
1121
1122/*************************************************************************
1123 * TrioLogarithmBase
1124 */
1125TRIO_PRIVATE double
1126TrioLogarithmBase
1127TRIO_ARGS1((base),
1128 int base)
1129{
1130 switch (base)
1131 {
1132 case BASE_BINARY : return 1.0;
1133 case BASE_OCTAL : return 3.0;
1134 case BASE_DECIMAL: return 3.321928094887362345;
1135 case BASE_HEX : return 4.0;
1136 default : return TrioLogarithm((double)base, 2);
1137 }
1138}
Bjorn Reese70a9da52001-04-21 16:57:29 +00001139
1140/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00001141 * TrioParse
Daniel Veillard92ad2102001-03-27 12:47:33 +00001142 *
1143 * Description:
1144 * Parse the format string
1145 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001146TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001147TrioParse
1148TRIO_ARGS5((type, format, parameters, arglist, argarray),
1149 int type,
1150 TRIO_CONST char *format,
1151 trio_parameter_t *parameters,
1152 va_list *arglist,
1153 trio_pointer_t *argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001154{
Daniel Veillard92ad2102001-03-27 12:47:33 +00001155 /* Count the number of times a parameter is referenced */
1156 unsigned short usedEntries[MAX_PARAMETERS];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001157 /* Parameter counters */
1158 int parameterPosition;
1159 int currentParam;
1160 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001161 /* Utility variables */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00001162 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001163 int width;
1164 int precision;
1165 int varsize;
1166 int base;
1167 int index; /* Index into formatting string */
1168 int dots; /* Count number of dots in modifier part */
1169 BOOLEAN_T positional; /* Does the specifier have a positional? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001170 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001171 /*
1172 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +00001173 * read from the va_args (this is necessary to handle positionals)
1174 */
1175 int indices[MAX_PARAMETERS];
1176 int pos = 0;
1177 /* Various variables */
1178 char ch;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001179#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001180 int charlen;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001181#endif
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001182 int save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001183 int i = -1;
1184 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001185 char *tmpformat;
1186
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001187 /* One and only one of arglist and argarray must be used */
1188 assert((arglist != NULL) ^ (argarray != NULL));
1189
Bjorn Reese70a9da52001-04-21 16:57:29 +00001190 /*
1191 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +00001192 * know which entries we have used.
1193 */
1194 memset(usedEntries, 0, sizeof(usedEntries));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001195
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001196 save_errno = errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001197 index = 0;
1198 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001199#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001200 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001201#endif
1202
1203 while (format[index])
1204 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001205#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001206 if (! isascii(format[index]))
1207 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001208 /*
1209 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001210 * modifiers, so we skip over them.
1211 */
1212 charlen = mblen(&format[index], MB_LEN_MAX);
1213 index += (charlen > 0) ? charlen : 1;
1214 continue; /* while */
1215 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001216#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001217 if (CHAR_IDENTIFIER == format[index++])
1218 {
1219 if (CHAR_IDENTIFIER == format[index])
1220 {
1221 index++;
1222 continue; /* while */
1223 }
1224
1225 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001226 dots = 0;
1227 currentParam = TrioGetPosition(format, &index);
1228 positional = (NO_POSITION != currentParam);
1229 if (!positional)
1230 {
1231 /* We have no positional, get the next counter */
1232 currentParam = parameterPosition;
1233 }
1234 if(currentParam >= MAX_PARAMETERS)
1235 {
1236 /* Bail out completely to make the error more obvious */
1237 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1238 }
1239
1240 if (currentParam > maxParam)
1241 maxParam = currentParam;
1242
1243 /* Default values */
1244 width = NO_WIDTH;
1245 precision = NO_PRECISION;
1246 base = NO_BASE;
1247 varsize = NO_SIZE;
1248
Bjorn Reese70a9da52001-04-21 16:57:29 +00001249 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001250 {
1251 ch = format[index++];
1252
Daniel Veillard92ad2102001-03-27 12:47:33 +00001253 switch (ch)
1254 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001255 case QUALIFIER_SPACE:
1256 flags |= FLAGS_SPACE;
1257 break;
1258
1259 case QUALIFIER_PLUS:
1260 flags |= FLAGS_SHOWSIGN;
1261 break;
1262
1263 case QUALIFIER_MINUS:
1264 flags |= FLAGS_LEFTADJUST;
1265 flags &= ~FLAGS_NILPADDING;
1266 break;
1267
1268 case QUALIFIER_ALTERNATIVE:
1269 flags |= FLAGS_ALTERNATIVE;
1270 break;
1271
1272 case QUALIFIER_DOT:
1273 if (dots == 0) /* Precision */
1274 {
1275 dots++;
1276
1277 /* Skip if no precision */
1278 if (QUALIFIER_DOT == format[index])
1279 break;
1280
1281 /* After the first dot we have the precision */
1282 flags |= FLAGS_PRECISION;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001283 if ((QUALIFIER_STAR == format[index])
1284#if defined(QUALIFIER_PARAM)
1285 || (QUALIFIER_PARAM == format[index])
1286#endif
1287 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001288 {
1289 index++;
1290 flags |= FLAGS_PRECISION_PARAMETER;
1291
1292 precision = TrioGetPosition(format, &index);
1293 if (precision == NO_POSITION)
1294 {
1295 parameterPosition++;
1296 if (positional)
1297 precision = parameterPosition;
1298 else
1299 {
1300 precision = currentParam;
1301 currentParam = precision + 1;
1302 }
1303 }
1304 else
1305 {
1306 if (! positional)
1307 currentParam = precision + 1;
1308 if (width > maxParam)
1309 maxParam = precision;
1310 }
1311 if (currentParam > maxParam)
1312 maxParam = currentParam;
1313 }
1314 else
1315 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001316 precision = trio_to_long(&format[index],
1317 &tmpformat,
1318 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001319 index = (int)(tmpformat - format);
1320 }
1321 }
1322 else if (dots == 1) /* Base */
1323 {
1324 dots++;
1325
1326 /* After the second dot we have the base */
1327 flags |= FLAGS_BASE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001328 if ((QUALIFIER_STAR == format[index])
1329#if defined(QUALIFIER_PARAM)
1330 || (QUALIFIER_PARAM == format[index])
1331#endif
1332 )
Daniel Veillard92ad2102001-03-27 12:47:33 +00001333 {
1334 index++;
1335 flags |= FLAGS_BASE_PARAMETER;
1336 base = TrioGetPosition(format, &index);
1337 if (base == NO_POSITION)
1338 {
1339 parameterPosition++;
1340 if (positional)
1341 base = parameterPosition;
1342 else
1343 {
1344 base = currentParam;
1345 currentParam = base + 1;
1346 }
1347 }
1348 else
1349 {
1350 if (! positional)
1351 currentParam = base + 1;
1352 if (base > maxParam)
1353 maxParam = base;
1354 }
1355 if (currentParam > maxParam)
1356 maxParam = currentParam;
1357 }
1358 else
1359 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001360 base = trio_to_long(&format[index],
1361 &tmpformat,
1362 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001363 if (base > MAX_BASE)
1364 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1365 index = (int)(tmpformat - format);
1366 }
1367 }
1368 else
1369 {
1370 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1371 }
1372 break; /* QUALIFIER_DOT */
1373
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001374#if defined(QUALIFIER_PARAM)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001375 case QUALIFIER_PARAM:
1376 type = TYPE_PRINT;
1377 /* FALLTHROUGH */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001378#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001379 case QUALIFIER_STAR:
1380 /* This has different meanings for print and scan */
1381 if (TYPE_PRINT == type)
1382 {
1383 /* Read with from parameter */
1384 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1385 width = TrioGetPosition(format, &index);
1386 if (width == NO_POSITION)
1387 {
1388 parameterPosition++;
1389 if (positional)
1390 width = parameterPosition;
1391 else
1392 {
1393 width = currentParam;
1394 currentParam = width + 1;
1395 }
1396 }
1397 else
1398 {
1399 if (! positional)
1400 currentParam = width + 1;
1401 if (width > maxParam)
1402 maxParam = width;
1403 }
1404 if (currentParam > maxParam)
1405 maxParam = currentParam;
1406 }
1407 else
1408 {
1409 /* Scan, but do not store result */
1410 flags |= FLAGS_IGNORE;
1411 }
1412
1413 break; /* QUALIFIER_STAR */
1414
1415 case '0':
1416 if (! (flags & FLAGS_LEFTADJUST))
1417 flags |= FLAGS_NILPADDING;
1418 /* FALLTHROUGH */
1419 case '1': case '2': case '3': case '4':
1420 case '5': case '6': case '7': case '8': case '9':
1421 flags |= FLAGS_WIDTH;
1422 /* &format[index - 1] is used to "rewind" the read
1423 * character from format
1424 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001425 width = trio_to_long(&format[index - 1],
1426 &tmpformat,
1427 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001428 index = (int)(tmpformat - format);
1429 break;
1430
1431 case QUALIFIER_SHORT:
1432 if (flags & FLAGS_SHORTSHORT)
1433 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1434 else if (flags & FLAGS_SHORT)
1435 flags |= FLAGS_SHORTSHORT;
1436 else
1437 flags |= FLAGS_SHORT;
1438 break;
1439
1440 case QUALIFIER_LONG:
1441 if (flags & FLAGS_QUAD)
1442 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1443 else if (flags & FLAGS_LONG)
1444 flags |= FLAGS_QUAD;
1445 else
1446 flags |= FLAGS_LONG;
1447 break;
1448
1449 case QUALIFIER_LONG_UPPER:
1450 flags |= FLAGS_LONGDOUBLE;
1451 break;
1452
1453#if defined(QUALIFIER_SIZE_T)
1454 case QUALIFIER_SIZE_T:
1455 flags |= FLAGS_SIZE_T;
1456 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001457 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001458 flags |= FLAGS_QUAD;
1459 else if (sizeof(size_t) == sizeof(long))
1460 flags |= FLAGS_LONG;
1461 break;
1462#endif
1463
1464#if defined(QUALIFIER_PTRDIFF_T)
1465 case QUALIFIER_PTRDIFF_T:
1466 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001467 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001468 flags |= FLAGS_QUAD;
1469 else if (sizeof(ptrdiff_t) == sizeof(long))
1470 flags |= FLAGS_LONG;
1471 break;
1472#endif
1473
1474#if defined(QUALIFIER_INTMAX_T)
1475 case QUALIFIER_INTMAX_T:
1476 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001477 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001478 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001479 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001480 flags |= FLAGS_LONG;
1481 break;
1482#endif
1483
1484#if defined(QUALIFIER_QUAD)
1485 case QUALIFIER_QUAD:
1486 flags |= FLAGS_QUAD;
1487 break;
1488#endif
1489
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001490#if defined(QUALIFIER_FIXED_SIZE)
1491 case QUALIFIER_FIXED_SIZE:
1492 if (flags & FLAGS_FIXED_SIZE)
1493 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1494
1495 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1496 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1497 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1498
1499 if ((format[index] == '6') &&
1500 (format[index + 1] == '4'))
1501 {
1502 varsize = sizeof(trio_int64_t);
1503 index += 2;
1504 }
1505 else if ((format[index] == '3') &&
1506 (format[index + 1] == '2'))
1507 {
1508 varsize = sizeof(trio_int32_t);
1509 index += 2;
1510 }
1511 else if ((format[index] == '1') &&
1512 (format[index + 1] == '6'))
1513 {
1514 varsize = sizeof(trio_int16_t);
1515 index += 2;
1516 }
1517 else if (format[index] == '8')
1518 {
1519 varsize = sizeof(trio_int8_t);
1520 index++;
1521 }
1522 else
1523 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1524
1525 flags |= FLAGS_FIXED_SIZE;
1526 break;
1527#endif
1528
Daniel Veillard92ad2102001-03-27 12:47:33 +00001529#if defined(QUALIFIER_WIDECHAR)
1530 case QUALIFIER_WIDECHAR:
1531 flags |= FLAGS_WIDECHAR;
1532 break;
1533#endif
1534
1535#if defined(QUALIFIER_SIZE_T_UPPER)
1536 case QUALIFIER_SIZE_T_UPPER:
1537 break;
1538#endif
1539
1540#if defined(QUALIFIER_QUOTE)
1541 case QUALIFIER_QUOTE:
1542 flags |= FLAGS_QUOTE;
1543 break;
1544#endif
1545
1546#if defined(QUALIFIER_STICKY)
1547 case QUALIFIER_STICKY:
1548 flags |= FLAGS_STICKY;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001549 gotSticky = TRUE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001550 break;
1551#endif
1552
1553#if defined(QUALIFIER_VARSIZE)
1554 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001555 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001556 parameterPosition++;
1557 if (positional)
1558 varsize = parameterPosition;
1559 else
1560 {
1561 varsize = currentParam;
1562 currentParam = varsize + 1;
1563 }
1564 if (currentParam > maxParam)
1565 maxParam = currentParam;
1566 break;
1567#endif
1568
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001569#if defined(QUALIFIER_ROUNDING_UPPER)
1570 case QUALIFIER_ROUNDING_UPPER:
1571 flags |= FLAGS_ROUNDING;
1572 break;
1573#endif
1574
Daniel Veillard92ad2102001-03-27 12:47:33 +00001575 default:
1576 /* Bail out completely to make the error more obvious */
1577 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1578 }
1579 } /* while qualifier */
1580
Bjorn Reese70a9da52001-04-21 16:57:29 +00001581 /*
1582 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001583 * read later.
1584 */
1585 if (flags & FLAGS_WIDTH_PARAMETER)
1586 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001587 usedEntries[width] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001588 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001589 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001590 indices[width] = pos;
1591 width = pos++;
1592 }
1593 if (flags & FLAGS_PRECISION_PARAMETER)
1594 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001595 usedEntries[precision] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001596 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001597 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001598 indices[precision] = pos;
1599 precision = pos++;
1600 }
1601 if (flags & FLAGS_BASE_PARAMETER)
1602 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001603 usedEntries[base] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001604 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001605 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001606 indices[base] = pos;
1607 base = pos++;
1608 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001609 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001610 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001611 usedEntries[varsize] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001612 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001613 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001614 indices[varsize] = pos;
1615 varsize = pos++;
1616 }
1617
1618 indices[currentParam] = pos;
1619
1620 switch (format[index++])
1621 {
1622#if defined(SPECIFIER_CHAR_UPPER)
1623 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001624 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001625 /* FALLTHROUGH */
1626#endif
1627 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001628 if (flags & FLAGS_LONG)
1629 flags |= FLAGS_WIDECHAR;
1630 else if (flags & FLAGS_SHORT)
1631 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001632 parameters[pos].type = FORMAT_CHAR;
1633 break;
1634
1635#if defined(SPECIFIER_STRING_UPPER)
1636 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001637 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001638 /* FALLTHROUGH */
1639#endif
1640 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001641 if (flags & FLAGS_LONG)
1642 flags |= FLAGS_WIDECHAR;
1643 else if (flags & FLAGS_SHORT)
1644 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001645 parameters[pos].type = FORMAT_STRING;
1646 break;
1647
1648 case SPECIFIER_GROUP:
1649 if (TYPE_SCAN == type)
1650 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001651 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001652 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001653 if (format[index] == QUALIFIER_CIRCUMFLEX)
1654 index++;
1655 if (format[index] == SPECIFIER_UNGROUP)
1656 index++;
1657 if (format[index] == QUALIFIER_MINUS)
1658 index++;
1659 /* Skip nested brackets */
1660 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001661 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001662 if (format[index] == SPECIFIER_GROUP)
1663 {
1664 depth++;
1665 }
1666 else if (format[index] == SPECIFIER_UNGROUP)
1667 {
1668 if (--depth <= 0)
1669 {
1670 index++;
1671 break;
1672 }
1673 }
1674 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001675 }
1676 }
1677 break;
1678
1679 case SPECIFIER_INTEGER:
1680 parameters[pos].type = FORMAT_INT;
1681 break;
1682
1683 case SPECIFIER_UNSIGNED:
1684 flags |= FLAGS_UNSIGNED;
1685 parameters[pos].type = FORMAT_INT;
1686 break;
1687
1688 case SPECIFIER_DECIMAL:
1689 /* Disable base modifier */
1690 flags &= ~FLAGS_BASE_PARAMETER;
1691 base = BASE_DECIMAL;
1692 parameters[pos].type = FORMAT_INT;
1693 break;
1694
1695 case SPECIFIER_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00001696 flags |= FLAGS_UNSIGNED;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001697 flags &= ~FLAGS_BASE_PARAMETER;
1698 base = BASE_OCTAL;
1699 parameters[pos].type = FORMAT_INT;
1700 break;
1701
1702#if defined(SPECIFIER_BINARY)
1703 case SPECIFIER_BINARY_UPPER:
1704 flags |= FLAGS_UPPER;
1705 /* FALLTHROUGH */
1706 case SPECIFIER_BINARY:
1707 flags |= FLAGS_NILPADDING;
1708 flags &= ~FLAGS_BASE_PARAMETER;
1709 base = BASE_BINARY;
1710 parameters[pos].type = FORMAT_INT;
1711 break;
1712#endif
1713
1714 case SPECIFIER_HEX_UPPER:
1715 flags |= FLAGS_UPPER;
1716 /* FALLTHROUGH */
1717 case SPECIFIER_HEX:
1718 flags |= FLAGS_UNSIGNED;
1719 flags &= ~FLAGS_BASE_PARAMETER;
1720 base = BASE_HEX;
1721 parameters[pos].type = FORMAT_INT;
1722 break;
1723
1724 case SPECIFIER_FLOAT_E_UPPER:
1725 flags |= FLAGS_UPPER;
1726 /* FALLTHROUGH */
1727 case SPECIFIER_FLOAT_E:
1728 flags |= FLAGS_FLOAT_E;
1729 parameters[pos].type = FORMAT_DOUBLE;
1730 break;
1731
1732 case SPECIFIER_FLOAT_G_UPPER:
1733 flags |= FLAGS_UPPER;
1734 /* FALLTHROUGH */
1735 case SPECIFIER_FLOAT_G:
1736 flags |= FLAGS_FLOAT_G;
1737 parameters[pos].type = FORMAT_DOUBLE;
1738 break;
1739
1740 case SPECIFIER_FLOAT_F_UPPER:
1741 flags |= FLAGS_UPPER;
1742 /* FALLTHROUGH */
1743 case SPECIFIER_FLOAT_F:
1744 parameters[pos].type = FORMAT_DOUBLE;
1745 break;
1746
1747 case SPECIFIER_POINTER:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001748 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1749 flags |= FLAGS_QUAD;
1750 else if (sizeof(trio_pointer_t) == sizeof(long))
1751 flags |= FLAGS_LONG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001752 parameters[pos].type = FORMAT_POINTER;
1753 break;
1754
1755 case SPECIFIER_COUNT:
1756 parameters[pos].type = FORMAT_COUNT;
1757 break;
1758
1759#if defined(SPECIFIER_HEXFLOAT)
1760# if defined(SPECIFIER_HEXFLOAT_UPPER)
1761 case SPECIFIER_HEXFLOAT_UPPER:
1762 flags |= FLAGS_UPPER;
1763 /* FALLTHROUGH */
1764# endif
1765 case SPECIFIER_HEXFLOAT:
1766 base = BASE_HEX;
1767 parameters[pos].type = FORMAT_DOUBLE;
1768 break;
1769#endif
1770
1771#if defined(FORMAT_ERRNO)
1772 case SPECIFIER_ERRNO:
1773 parameters[pos].type = FORMAT_ERRNO;
1774 break;
1775#endif
1776
Bjorn Reese70a9da52001-04-21 16:57:29 +00001777#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1778 case SPECIFIER_USER_DEFINED_BEGIN:
1779 {
1780 unsigned int max;
1781 int without_namespace = TRUE;
1782
1783 parameters[pos].type = FORMAT_USER_DEFINED;
1784 parameters[pos].user_name[0] = NIL;
1785 tmpformat = (char *)&format[index];
1786
1787 while ((ch = format[index]))
1788 {
1789 index++;
1790 if (ch == SPECIFIER_USER_DEFINED_END)
1791 {
1792 if (without_namespace)
1793 {
1794 /* We must get the handle first */
1795 parameters[pos].type = FORMAT_PARAMETER;
1796 parameters[pos].indexAfterSpecifier = index;
1797 parameters[pos].flags = FLAGS_USER_DEFINED;
1798 /* Adjust parameters for insertion of new one */
1799 pos++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001800 usedEntries[currentParam] += 1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001801 parameters[pos].type = FORMAT_USER_DEFINED;
1802 currentParam++;
1803 indices[currentParam] = pos;
1804 if (currentParam > maxParam)
1805 maxParam = currentParam;
1806 }
1807 /* Copy the user data */
1808 max = (unsigned int)(&format[index] - tmpformat);
1809 if (max > MAX_USER_DATA)
1810 max = MAX_USER_DATA;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001811 trio_copy_max(parameters[pos].user_data,
1812 max,
1813 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001814 break; /* while */
1815 }
1816 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1817 {
1818 without_namespace = FALSE;
1819 /* Copy the namespace for later looking-up */
1820 max = (int)(&format[index] - tmpformat);
1821 if (max > MAX_USER_NAME)
1822 max = MAX_USER_NAME;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001823 trio_copy_max(parameters[pos].user_name,
1824 max,
1825 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001826 tmpformat = (char *)&format[index];
1827 }
1828 }
1829 if (ch != SPECIFIER_USER_DEFINED_END)
1830 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1831 }
1832 break;
1833#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1834
Daniel Veillard92ad2102001-03-27 12:47:33 +00001835 default:
1836 /* Bail out completely to make the error more obvious */
1837 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1838 }
1839
Daniel Veillard92ad2102001-03-27 12:47:33 +00001840 /* Count the number of times this entry has been used */
1841 usedEntries[currentParam] += 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001842
1843 /* Find last sticky parameters */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001844 if (gotSticky && !(flags & FLAGS_STICKY))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001845 {
1846 for (i = pos - 1; i >= 0; i--)
1847 {
1848 if (parameters[i].type == FORMAT_PARAMETER)
1849 continue;
1850 if ((parameters[i].flags & FLAGS_STICKY) &&
1851 (parameters[i].type == parameters[pos].type))
1852 {
1853 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001854 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001855 if (width == NO_WIDTH)
1856 width = parameters[i].width;
1857 if (precision == NO_PRECISION)
1858 precision = parameters[i].precision;
1859 if (base == NO_BASE)
1860 base = parameters[i].base;
1861 break;
1862 }
1863 }
1864 }
1865
1866 parameters[pos].indexAfterSpecifier = index;
1867 parameters[pos].flags = flags;
1868 parameters[pos].width = width;
1869 parameters[pos].precision = precision;
1870 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1871 parameters[pos].varsize = varsize;
1872 pos++;
1873
Bjorn Reese70a9da52001-04-21 16:57:29 +00001874 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001875 parameterPosition++;
1876
1877 } /* if identifier */
1878
1879 } /* while format characters left */
1880
1881 for (num = 0; num <= maxParam; num++)
1882 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001883 if (usedEntries[num] != 1)
1884 {
1885 if (usedEntries[num] == 0) /* gap detected */
1886 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1887 else /* double references detected */
1888 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1889 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001890
1891 i = indices[num];
1892
Bjorn Reese70a9da52001-04-21 16:57:29 +00001893 /*
1894 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001895 * so it makes no sense to check the ignore flag (besides,
1896 * the flags variable is not set for that particular type)
1897 */
1898 if ((parameters[i].type != FORMAT_PARAMETER) &&
1899 (parameters[i].flags & FLAGS_IGNORE))
1900 continue; /* for all arguments */
1901
Bjorn Reese70a9da52001-04-21 16:57:29 +00001902 /*
1903 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001904 * default argument promotions:
1905 *
1906 * char = int
1907 * short = int
1908 * unsigned char = unsigned int
1909 * unsigned short = unsigned int
1910 * float = double
1911 *
1912 * In addition to the ANSI C89 these types are read (the
1913 * default argument promotions of C99 has not been
1914 * considered yet)
1915 *
1916 * long long
1917 * long double
1918 * size_t
1919 * ptrdiff_t
1920 * intmax_t
1921 */
1922 switch (parameters[i].type)
1923 {
1924 case FORMAT_GROUP:
1925 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001926#if TRIO_WIDECHAR
1927 if (flags & FLAGS_WIDECHAR)
1928 {
1929 parameters[i].data.wstring = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001930 ? va_arg(*arglist, trio_wchar_t *)
1931 : (trio_wchar_t *)(argarray[num]);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001932 }
1933 else
1934#endif
1935 {
1936 parameters[i].data.string = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001937 ? va_arg(*arglist, char *)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001938 : (char *)(argarray[num]);
1939 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001940 break;
1941
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001942#if defined(FORMAT_USER_DEFINED)
1943 case FORMAT_USER_DEFINED:
1944#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00001945 case FORMAT_POINTER:
1946 case FORMAT_COUNT:
1947 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001948 parameters[i].data.pointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001949 ? va_arg(*arglist, trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00001950 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001951 break;
1952
1953 case FORMAT_CHAR:
1954 case FORMAT_INT:
1955 if (TYPE_SCAN == type)
1956 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001957 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001958 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001959 (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001960 else
1961 {
1962 if (parameters[i].type == FORMAT_CHAR)
1963 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001964 (trio_pointer_t)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001965 else if (parameters[i].flags & FLAGS_SHORT)
1966 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001967 (trio_pointer_t)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001968 else
1969 parameters[i].data.pointer =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00001970 (trio_pointer_t)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001971 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001972 }
1973 else
1974 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001975#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
Bjorn Reese026d29f2002-01-19 15:40:18 +00001976 if (parameters[i].flags
1977 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001978 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001979 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1980 {
1981 /*
1982 * Variable sizes are mapped onto the fixed sizes, in
1983 * accordance with integer promotion.
1984 *
1985 * Please note that this may not be portable, as we
1986 * only guess the size, not the layout of the numbers.
1987 * For example, if int is little-endian, and long is
1988 * big-endian, then this will fail.
1989 */
1990 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1991 }
1992 else
1993 {
1994 /* Used for the I<bits> modifiers */
1995 varsize = parameters[i].varsize;
1996 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001997 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001998
Daniel Veillard92ad2102001-03-27 12:47:33 +00001999 if (varsize <= (int)sizeof(int))
2000 ;
2001 else if (varsize <= (int)sizeof(long))
2002 parameters[i].flags |= FLAGS_LONG;
2003#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002004 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002005 parameters[i].flags |= FLAGS_QUAD;
2006 else
2007 parameters[i].flags |= FLAGS_INTMAX_T;
2008#else
2009 else
2010 parameters[i].flags |= FLAGS_QUAD;
2011#endif
2012 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002013#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002014#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2015 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002016 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002017 ? (trio_uintmax_t)va_arg(*arglist, size_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002018 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002019 else
2020#endif
2021#if defined(QUALIFIER_PTRDIFF_T)
2022 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002023 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002024 ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002025 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002026 else
2027#endif
2028#if defined(QUALIFIER_INTMAX_T)
2029 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002030 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002031 ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002032 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002033 else
2034#endif
2035 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002036 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002037 ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002038 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002039 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002040 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002041 ? (trio_uintmax_t)va_arg(*arglist, long)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002042 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002043 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002044 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002045 if (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002046 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002047 else
2048 {
2049 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002050 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002051 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002052 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002053 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002054 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002055 }
2056 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002057 }
2058 break;
2059
2060 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002061 /*
2062 * The parameter for the user-defined specifier is a pointer,
2063 * whereas the rest (width, precision, base) uses an integer.
2064 */
2065 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002066 parameters[i].data.pointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002067 ? va_arg(*arglist, trio_pointer_t )
Bjorn Reese70a9da52001-04-21 16:57:29 +00002068 : argarray[num];
2069 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002070 parameters[i].data.number.as_unsigned = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002071 ? (trio_uintmax_t)va_arg(*arglist, int)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002072 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002073 break;
2074
2075 case FORMAT_DOUBLE:
2076 if (TYPE_SCAN == type)
2077 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002078 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002079 parameters[i].data.longdoublePointer = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002080 ? va_arg(*arglist, trio_long_double_t *)
2081 : (trio_long_double_t *)argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002082 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002083 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002084 if (parameters[i].flags & FLAGS_LONG)
2085 parameters[i].data.doublePointer = (argarray == NULL)
2086 ? va_arg(*arglist, double *)
2087 : (double *)argarray[num];
2088 else
2089 parameters[i].data.doublePointer = (argarray == NULL)
2090 ? (double *)va_arg(*arglist, float *)
2091 : (double *)((float *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002092 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002093 }
2094 else
2095 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002096 if (parameters[i].flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002097 parameters[i].data.longdoubleNumber = (argarray == NULL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002098 ? va_arg(*arglist, trio_long_double_t)
2099 : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002100 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00002101 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002102 if (argarray == NULL)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002103 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002104 (trio_long_double_t)va_arg(*arglist, double);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002105 else
2106 {
2107 if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese026d29f2002-01-19 15:40:18 +00002108 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002109 (trio_long_double_t)(*((float *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002110 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00002111 parameters[i].data.longdoubleNumber =
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002112 (trio_long_double_t)(*((double *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002113 }
2114 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002115 }
2116 break;
2117
2118#if defined(FORMAT_ERRNO)
2119 case FORMAT_ERRNO:
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002120 parameters[i].data.errorNumber = save_errno;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002121 break;
2122#endif
2123
2124 default:
2125 break;
2126 }
2127 } /* for all specifiers */
2128 return num;
2129}
2130
2131
2132/*************************************************************************
2133 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00002134 * FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00002135 *
2136 ************************************************************************/
2137
2138
2139/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002140 * TrioWriteNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00002141 *
2142 * Description:
2143 * Output a number.
2144 * The complexity of this function is a result of the complexity
2145 * of the dependencies of the flags.
2146 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002147TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002148TrioWriteNumber
2149TRIO_ARGS6((self, number, flags, width, precision, base),
2150 trio_class_t *self,
2151 trio_uintmax_t number,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002152 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002153 int width,
2154 int precision,
2155 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002156{
2157 BOOLEAN_T isNegative;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002158 BOOLEAN_T isNumberZero;
2159 BOOLEAN_T isPrecisionZero;
2160 BOOLEAN_T ignoreNumber;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002161 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002162 char *bufferend;
2163 char *pointer;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002164 TRIO_CONST char *digits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002165 int i;
2166 int length;
2167 char *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002168 int count;
2169
2170 assert(VALID(self));
2171 assert(VALID(self->OutStream));
Bjorn Reese026d29f2002-01-19 15:40:18 +00002172 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002173
Bjorn Reese70a9da52001-04-21 16:57:29 +00002174 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002175 if (base == NO_BASE)
2176 base = BASE_DECIMAL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002177
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002178 isNumberZero = (number == 0);
2179 isPrecisionZero = (precision == 0);
2180 ignoreNumber = (isNumberZero
2181 && isPrecisionZero
2182 && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2183
2184 if (flags & FLAGS_UNSIGNED)
2185 {
2186 isNegative = FALSE;
2187 flags &= ~FLAGS_SHOWSIGN;
2188 }
2189 else
2190 {
2191 isNegative = ((trio_intmax_t)number < 0);
2192 if (isNegative)
2193 number = -((trio_intmax_t)number);
2194 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002195
2196 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002197 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002198 else if (flags & FLAGS_LONG)
2199 number &= (unsigned long)-1;
2200 else
2201 number &= (unsigned int)-1;
2202
2203 /* Build number */
2204 pointer = bufferend = &buffer[sizeof(buffer) - 1];
2205 *pointer-- = NIL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002206 for (i = 1; i < (int)sizeof(buffer); i++)
2207 {
2208 *pointer-- = digits[number % base];
2209 number /= base;
2210 if (number == 0)
2211 break;
2212
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002213 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002214 {
2215 /*
2216 * We are building the number from the least significant
2217 * to the most significant digit, so we have to copy the
2218 * thousand separator backwards
2219 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002220 length = internalThousandSeparatorLength;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002221 if (((int)(pointer - buffer) - length) > 0)
2222 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002223 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002224 while (length-- > 0)
2225 *pointer-- = *p--;
2226 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002227 }
2228 }
2229
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002230 if (! ignoreNumber)
2231 {
2232 /* Adjust width */
2233 width -= (bufferend - pointer) - 1;
2234 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002235
2236 /* Adjust precision */
2237 if (NO_PRECISION != precision)
2238 {
2239 precision -= (bufferend - pointer) - 1;
2240 if (precision < 0)
2241 precision = 0;
2242 flags |= FLAGS_NILPADDING;
2243 }
2244
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002245 /* Calculate padding */
2246 count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2247 ? precision
2248 : 0;
2249
Daniel Veillard92ad2102001-03-27 12:47:33 +00002250 /* Adjust width further */
2251 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2252 width--;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002253 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002254 {
2255 switch (base)
2256 {
2257 case BASE_BINARY:
2258 case BASE_HEX:
2259 width -= 2;
2260 break;
2261 case BASE_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002262 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2263 width--;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002264 break;
2265 default:
2266 break;
2267 }
2268 }
2269
2270 /* Output prefixes spaces if needed */
2271 if (! ((flags & FLAGS_LEFTADJUST) ||
2272 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2273 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002274 while (width-- > count)
2275 self->OutStream(self, CHAR_ADJUST);
2276 }
2277
2278 /* width has been adjusted for signs and alternatives */
2279 if (isNegative)
2280 self->OutStream(self, '-');
2281 else if (flags & FLAGS_SHOWSIGN)
2282 self->OutStream(self, '+');
2283 else if (flags & FLAGS_SPACE)
2284 self->OutStream(self, ' ');
2285
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002286 /* Prefix is not written when the value is zero */
2287 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002288 {
2289 switch (base)
2290 {
2291 case BASE_BINARY:
2292 self->OutStream(self, '0');
2293 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2294 break;
2295
2296 case BASE_OCTAL:
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002297 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2298 self->OutStream(self, '0');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002299 break;
2300
2301 case BASE_HEX:
2302 self->OutStream(self, '0');
2303 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2304 break;
2305
2306 default:
2307 break;
2308 } /* switch base */
2309 }
2310
2311 /* Output prefixed zero padding if needed */
2312 if (flags & FLAGS_NILPADDING)
2313 {
2314 if (precision == NO_PRECISION)
2315 precision = width;
2316 while (precision-- > 0)
2317 {
2318 self->OutStream(self, '0');
2319 width--;
2320 }
2321 }
2322
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002323 if (! ignoreNumber)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002324 {
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002325 /* Output the number itself */
2326 while (*(++pointer))
2327 {
2328 self->OutStream(self, *pointer);
2329 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002330 }
2331
2332 /* Output trailing spaces if needed */
2333 if (flags & FLAGS_LEFTADJUST)
2334 {
2335 while (width-- > 0)
2336 self->OutStream(self, CHAR_ADJUST);
2337 }
2338}
2339
2340/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002341 * TrioWriteStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002342 *
2343 * Description:
2344 * Output a single character of a string
2345 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002346TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002347TrioWriteStringCharacter
2348TRIO_ARGS3((self, ch, flags),
2349 trio_class_t *self,
2350 int ch,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002351 trio_flags_t flags)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002352{
2353 if (flags & FLAGS_ALTERNATIVE)
2354 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002355 if (! isprint(ch))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002356 {
2357 /*
2358 * Non-printable characters are converted to C escapes or
2359 * \number, if no C escape exists.
2360 */
2361 self->OutStream(self, CHAR_BACKSLASH);
2362 switch (ch)
2363 {
2364 case '\007': self->OutStream(self, 'a'); break;
2365 case '\b': self->OutStream(self, 'b'); break;
2366 case '\f': self->OutStream(self, 'f'); break;
2367 case '\n': self->OutStream(self, 'n'); break;
2368 case '\r': self->OutStream(self, 'r'); break;
2369 case '\t': self->OutStream(self, 't'); break;
2370 case '\v': self->OutStream(self, 'v'); break;
2371 case '\\': self->OutStream(self, '\\'); break;
2372 default:
2373 self->OutStream(self, 'x');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002374 TrioWriteNumber(self, (trio_uintmax_t)ch,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002375 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2376 2, 2, BASE_HEX);
2377 break;
2378 }
2379 }
2380 else if (ch == CHAR_BACKSLASH)
2381 {
2382 self->OutStream(self, CHAR_BACKSLASH);
2383 self->OutStream(self, CHAR_BACKSLASH);
2384 }
2385 else
2386 {
2387 self->OutStream(self, ch);
2388 }
2389 }
2390 else
2391 {
2392 self->OutStream(self, ch);
2393 }
2394}
2395
2396/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002397 * TrioWriteString
Daniel Veillard92ad2102001-03-27 12:47:33 +00002398 *
2399 * Description:
2400 * Output a string
2401 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002402TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002403TrioWriteString
2404TRIO_ARGS5((self, string, flags, width, precision),
2405 trio_class_t *self,
2406 TRIO_CONST char *string,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002407 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002408 int width,
2409 int precision)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002410{
2411 int length;
2412 int ch;
2413
2414 assert(VALID(self));
2415 assert(VALID(self->OutStream));
2416
2417 if (string == NULL)
2418 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002419 string = internalNullString;
2420 length = sizeof(internalNullString) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002421 /* Disable quoting for the null pointer */
2422 flags &= (~FLAGS_QUOTE);
2423 width = 0;
2424 }
2425 else
2426 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002427 length = trio_length(string);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002428 }
2429 if ((NO_PRECISION != precision) &&
2430 (precision < length))
2431 {
2432 length = precision;
2433 }
2434 width -= length;
2435
2436 if (flags & FLAGS_QUOTE)
2437 self->OutStream(self, CHAR_QUOTE);
2438
2439 if (! (flags & FLAGS_LEFTADJUST))
2440 {
2441 while (width-- > 0)
2442 self->OutStream(self, CHAR_ADJUST);
2443 }
2444
2445 while (length-- > 0)
2446 {
2447 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002448 ch = (int)((unsigned char)(*string++));
2449 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002450 }
2451
2452 if (flags & FLAGS_LEFTADJUST)
2453 {
2454 while (width-- > 0)
2455 self->OutStream(self, CHAR_ADJUST);
2456 }
2457 if (flags & FLAGS_QUOTE)
2458 self->OutStream(self, CHAR_QUOTE);
2459}
2460
2461/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002462 * TrioWriteWideStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002463 *
2464 * Description:
2465 * Output a wide string as a multi-byte sequence
2466 */
2467#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002468TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002469TrioWriteWideStringCharacter
2470TRIO_ARGS4((self, wch, flags, width),
2471 trio_class_t *self,
2472 trio_wchar_t wch,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002473 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002474 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002475{
2476 int size;
2477 int i;
2478 int ch;
2479 char *string;
2480 char buffer[MB_LEN_MAX + 1];
2481
2482 if (width == NO_WIDTH)
2483 width = sizeof(buffer);
2484
2485 size = wctomb(buffer, wch);
2486 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2487 return 0;
2488
2489 string = buffer;
2490 i = size;
2491 while ((width >= i) && (width-- > 0) && (i-- > 0))
2492 {
2493 /* The ctype parameters must be an unsigned char (or EOF) */
2494 ch = (int)((unsigned char)(*string++));
2495 TrioWriteStringCharacter(self, ch, flags);
2496 }
2497 return size;
2498}
2499#endif /* TRIO_WIDECHAR */
2500
2501/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002502 * TrioWriteWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002503 *
2504 * Description:
2505 * Output a wide character string as a multi-byte string
2506 */
2507#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002508TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002509TrioWriteWideString
2510TRIO_ARGS5((self, wstring, flags, width, precision),
2511 trio_class_t *self,
2512 TRIO_CONST trio_wchar_t *wstring,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002513 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002514 int width,
2515 int precision)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002516{
2517 int length;
2518 int size;
2519
2520 assert(VALID(self));
2521 assert(VALID(self->OutStream));
2522
2523#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002524 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002525#endif
2526
2527 if (wstring == NULL)
2528 {
2529 TrioWriteString(self, NULL, flags, width, precision);
2530 return;
2531 }
2532
2533 if (NO_PRECISION == precision)
2534 {
2535 length = INT_MAX;
2536 }
2537 else
2538 {
2539 length = precision;
2540 width -= length;
2541 }
2542
2543 if (flags & FLAGS_QUOTE)
2544 self->OutStream(self, CHAR_QUOTE);
2545
2546 if (! (flags & FLAGS_LEFTADJUST))
2547 {
2548 while (width-- > 0)
2549 self->OutStream(self, CHAR_ADJUST);
2550 }
2551
2552 while (length > 0)
2553 {
2554 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2555 if (size == 0)
2556 break; /* while */
2557 length -= size;
2558 }
2559
2560 if (flags & FLAGS_LEFTADJUST)
2561 {
2562 while (width-- > 0)
2563 self->OutStream(self, CHAR_ADJUST);
2564 }
2565 if (flags & FLAGS_QUOTE)
2566 self->OutStream(self, CHAR_QUOTE);
2567}
2568#endif /* TRIO_WIDECHAR */
2569
2570/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002571 * TrioWriteDouble
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002572 *
2573 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2574 *
2575 * "5.2.4.2.2 paragraph #4
2576 *
2577 * The accuracy [...] is implementation defined, as is the accuracy
2578 * of the conversion between floating-point internal representations
2579 * and string representations performed by the libray routine in
2580 * <stdio.h>"
2581 */
2582/* FIXME: handle all instances of constant long-double number (L)
2583 * and *l() math functions.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002584 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002585TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002586TrioWriteDouble
2587TRIO_ARGS6((self, number, flags, width, precision, base),
2588 trio_class_t *self,
2589 trio_long_double_t number,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002590 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002591 int width,
2592 int precision,
2593 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002594{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002595 trio_long_double_t integerNumber;
2596 trio_long_double_t fractionNumber;
2597 trio_long_double_t workNumber;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002598 int integerDigits;
2599 int fractionDigits;
2600 int exponentDigits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002601 int baseDigits;
2602 int integerThreshold;
2603 int fractionThreshold;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002604 int expectedWidth;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002605 int exponent = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002606 unsigned int uExponent = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002607 int exponentBase;
2608 trio_long_double_t dblBase;
2609 trio_long_double_t dblIntegerBase;
2610 trio_long_double_t dblFractionBase;
2611 trio_long_double_t integerAdjust;
2612 trio_long_double_t fractionAdjust;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002613 BOOLEAN_T isNegative;
2614 BOOLEAN_T isExponentNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002615 BOOLEAN_T requireTwoDigitExponent;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002616 BOOLEAN_T isHex;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002617 TRIO_CONST char *digits;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002618 char *groupingPointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002619 int i;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002620 int index;
2621 BOOLEAN_T hasOnlyZeroes;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002622 int zeroes = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002623 register int trailingZeroes;
2624 BOOLEAN_T keepTrailingZeroes;
2625 BOOLEAN_T keepDecimalPoint;
2626 trio_long_double_t epsilon;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002627
2628 assert(VALID(self));
2629 assert(VALID(self->OutStream));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002630 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00002631
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002632 /* Determine sign and look for special quantities */
2633 switch (trio_fpclassify_and_signbit(number, &isNegative))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002634 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002635 case TRIO_FP_NAN:
Daniel Veillard92ad2102001-03-27 12:47:33 +00002636 TrioWriteString(self,
2637 (flags & FLAGS_UPPER)
2638 ? NAN_UPPER
2639 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002640 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002641 return;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002642
2643 case TRIO_FP_INFINITE:
2644 if (isNegative)
2645 {
2646 /* Negative infinity */
2647 TrioWriteString(self,
2648 (flags & FLAGS_UPPER)
2649 ? "-" INFINITE_UPPER
2650 : "-" INFINITE_LOWER,
2651 flags, width, precision);
2652 return;
2653 }
2654 else
2655 {
2656 /* Positive infinity */
2657 TrioWriteString(self,
2658 (flags & FLAGS_UPPER)
2659 ? INFINITE_UPPER
2660 : INFINITE_LOWER,
2661 flags, width, precision);
2662 return;
2663 }
2664
2665 default:
2666 /* Finitude */
2667 break;
2668 }
2669
2670 /* Normal numbers */
2671 if (flags & FLAGS_LONGDOUBLE)
2672 {
2673 baseDigits = (base == 10)
2674 ? LDBL_DIG
2675 : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2676 epsilon = LDBL_EPSILON;
2677 }
2678 else if (flags & FLAGS_SHORT)
2679 {
2680 baseDigits = (base == BASE_DECIMAL)
2681 ? FLT_DIG
2682 : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2683 epsilon = FLT_EPSILON;
2684 }
2685 else
2686 {
2687 baseDigits = (base == BASE_DECIMAL)
2688 ? DBL_DIG
2689 : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2690 epsilon = DBL_EPSILON;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002691 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002692
Bjorn Reese70a9da52001-04-21 16:57:29 +00002693 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002694 isHex = (base == BASE_HEX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002695 if (base == NO_BASE)
2696 base = BASE_DECIMAL;
2697 dblBase = (trio_long_double_t)base;
2698 keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2699 ( (flags & FLAGS_FLOAT_G) &&
2700 !(flags & FLAGS_ALTERNATIVE) ) );
2701
2702 if (flags & FLAGS_ROUNDING)
2703 precision = baseDigits;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002704
Daniel Veillard92ad2102001-03-27 12:47:33 +00002705 if (precision == NO_PRECISION)
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002706 {
2707 if (isHex)
2708 {
2709 keepTrailingZeroes = FALSE;
2710 precision = FLT_MANT_DIG;
2711 }
2712 else
2713 {
2714 precision = FLT_DIG;
2715 }
2716 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002717
Daniel Veillard92ad2102001-03-27 12:47:33 +00002718 if (isNegative)
2719 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002720
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002721 if (isHex)
2722 flags |= FLAGS_FLOAT_E;
2723
2724 if (flags & FLAGS_FLOAT_G)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002725 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002726 if (precision == 0)
2727 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002728
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002729 if ((number < 1.0E-4) || (number > powl(base,
2730 (trio_long_double_t)precision)))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002731 {
2732 /* Use scientific notation */
2733 flags |= FLAGS_FLOAT_E;
2734 }
2735 else if (number < 1.0)
2736 {
2737 /*
2738 * Use normal notation. If the integer part of the number is
2739 * zero, then adjust the precision to include leading fractional
2740 * zeros.
2741 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002742 workNumber = TrioLogarithm(number, base);
2743 workNumber = TRIO_FABS(workNumber);
2744 if (workNumber - floorl(workNumber) < 0.001)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002745 workNumber--;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002746 zeroes = (int)floorl(workNumber);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002747 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002748 }
2749
2750 if (flags & FLAGS_FLOAT_E)
2751 {
2752 /* Scale the number */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002753 workNumber = TrioLogarithm(number, base);
Bjorn Reese45029602001-08-21 09:23:53 +00002754 if (trio_isinf(workNumber) == -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002755 {
2756 exponent = 0;
2757 /* Undo setting */
2758 if (flags & FLAGS_FLOAT_G)
2759 flags &= ~FLAGS_FLOAT_E;
2760 }
2761 else
2762 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002763 exponent = (int)floorl(workNumber);
2764 number /= powl(dblBase, (trio_long_double_t)exponent);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002765 isExponentNegative = (exponent < 0);
2766 uExponent = (isExponentNegative) ? -exponent : exponent;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002767 if (isHex)
2768 uExponent *= 4; /* log16(2) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002769 /* No thousand separators */
2770 flags &= ~FLAGS_QUOTE;
2771 }
2772 }
2773
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002774 integerNumber = floorl(number);
2775 fractionNumber = number - integerNumber;
2776
Daniel Veillard92ad2102001-03-27 12:47:33 +00002777 /*
2778 * Truncated number.
2779 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002780 * Precision is number of significant digits for FLOAT_G
2781 * and number of fractional digits for others.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002782 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002783 integerDigits = (integerNumber > epsilon)
2784 ? 1 + (int)TrioLogarithm(integerNumber, base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002785 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002786 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002787 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002788 : zeroes + precision;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002789
2790 dblFractionBase = TrioPower(base, fractionDigits);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002791
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002792 workNumber = number + 0.5 / dblFractionBase;
2793 if (floorl(number) != floorl(workNumber))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002794 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002795 if (flags & FLAGS_FLOAT_E)
2796 {
2797 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002798 exponent++;
2799 isExponentNegative = (exponent < 0);
2800 uExponent = (isExponentNegative) ? -exponent : exponent;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002801 if (isHex)
2802 uExponent *= 4; /* log16(2) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002803 workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2804 integerNumber = floorl(workNumber);
2805 fractionNumber = workNumber - integerNumber;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002806 }
2807 else
2808 {
2809 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002810 integerNumber = floorl(number + 0.5);
2811 fractionNumber = 0.0;
2812 integerDigits = (integerNumber > epsilon)
2813 ? 1 + (int)TrioLogarithm(integerNumber, base)
2814 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002815 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002816 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002817
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002818 /* Estimate accuracy */
2819 integerAdjust = fractionAdjust = 0.5;
2820 if (flags & FLAGS_ROUNDING)
2821 {
2822 if (integerDigits > baseDigits)
2823 {
2824 integerThreshold = baseDigits;
2825 fractionDigits = 0;
2826 dblFractionBase = 1.0;
2827 fractionThreshold = 0;
2828 precision = 0; /* Disable decimal-point */
2829 integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2830 fractionAdjust = 0.0;
2831 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002832 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002833 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002834 integerThreshold = integerDigits;
2835 fractionThreshold = fractionDigits - integerThreshold;
2836 fractionAdjust = 1.0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002837 }
2838 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002839 else
Daniel Veillard92ad2102001-03-27 12:47:33 +00002840 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002841 integerThreshold = INT_MAX;
2842 fractionThreshold = INT_MAX;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002843 }
2844
Bjorn Reese70a9da52001-04-21 16:57:29 +00002845 /*
2846 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002847 * sign + integer part + thousands separators + decimal point
2848 * + fraction + exponent
2849 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002850 fractionAdjust /= dblFractionBase;
2851 hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2852 keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2853 !((precision == 0) ||
2854 (!keepTrailingZeroes && hasOnlyZeroes)) );
2855 if (flags & FLAGS_FLOAT_E)
2856 {
2857 exponentDigits = (uExponent == 0)
2858 ? 1
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00002859 : (int)ceil(TrioLogarithm((double)(uExponent + 1),
2860 (isHex) ? 10.0 : base));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002861 }
2862 else
2863 exponentDigits = 0;
2864 requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2865
2866 expectedWidth = integerDigits + fractionDigits
2867 + (keepDecimalPoint
2868 ? internalDecimalPointLength
2869 : 0)
2870 + ((flags & FLAGS_QUOTE)
2871 ? TrioCalcThousandSeparatorLength(integerDigits)
2872 : 0);
2873 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 expectedWidth += sizeof("-") - 1;
2875 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002876 expectedWidth += exponentDigits +
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002877 ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002878 if (isHex)
2879 expectedWidth += sizeof("0X") - 1;
2880
2881 /* Output prefixing */
2882 if (flags & FLAGS_NILPADDING)
2883 {
2884 /* Leading zeros must be after sign */
2885 if (isNegative)
2886 self->OutStream(self, '-');
2887 else if (flags & FLAGS_SHOWSIGN)
2888 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002889 else if (flags & FLAGS_SPACE)
2890 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002891 if (isHex)
2892 {
2893 self->OutStream(self, '0');
2894 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2895 }
2896 if (!(flags & FLAGS_LEFTADJUST))
2897 {
2898 for (i = expectedWidth; i < width; i++)
2899 {
2900 self->OutStream(self, '0');
2901 }
2902 }
2903 }
2904 else
2905 {
2906 /* Leading spaces must be before sign */
2907 if (!(flags & FLAGS_LEFTADJUST))
2908 {
2909 for (i = expectedWidth; i < width; i++)
2910 {
2911 self->OutStream(self, CHAR_ADJUST);
2912 }
2913 }
2914 if (isNegative)
2915 self->OutStream(self, '-');
2916 else if (flags & FLAGS_SHOWSIGN)
2917 self->OutStream(self, '+');
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002918 else if (flags & FLAGS_SPACE)
2919 self->OutStream(self, ' ');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002920 if (isHex)
2921 {
2922 self->OutStream(self, '0');
2923 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2924 }
2925 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002926
2927 /* Output the integer part and thousand separators */
2928 dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2929 for (i = 0; i < integerDigits; i++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002930 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002931 workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2932 if (i > integerThreshold)
2933 {
2934 /* Beyond accuracy */
2935 self->OutStream(self, digits[0]);
2936 }
2937 else
2938 {
2939 self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2940 }
2941 dblIntegerBase *= dblBase;
2942
2943 if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2944 && TrioFollowedBySeparator(integerDigits - i))
2945 {
2946 for (groupingPointer = internalThousandSeparator;
2947 *groupingPointer != NIL;
2948 groupingPointer++)
2949 {
2950 self->OutStream(self, *groupingPointer);
2951 }
2952 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002953 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00002954
2955 /* Insert decimal point and build the fraction part */
2956 trailingZeroes = 0;
2957
2958 if (keepDecimalPoint)
2959 {
2960 if (internalDecimalPoint)
2961 {
2962 self->OutStream(self, internalDecimalPoint);
2963 }
2964 else
2965 {
2966 for (i = 0; i < internalDecimalPointLength; i++)
2967 {
2968 self->OutStream(self, internalDecimalPointString[i]);
2969 }
2970 }
2971 }
2972
2973 for (i = 0; i < fractionDigits; i++)
2974 {
2975 if ((integerDigits > integerThreshold) || (i > fractionThreshold))
2976 {
2977 /* Beyond accuracy */
2978 trailingZeroes++;
2979 }
2980 else
2981 {
2982 fractionNumber *= dblBase;
2983 fractionAdjust *= dblBase;
2984 workNumber = floorl(fractionNumber + fractionAdjust);
2985 fractionNumber -= workNumber;
2986 index = (int)fmodl(workNumber, dblBase);
2987 if (index == 0)
2988 {
2989 trailingZeroes++;
2990 }
2991 else
2992 {
2993 while (trailingZeroes > 0)
2994 {
2995 /* Not trailing zeroes after all */
2996 self->OutStream(self, digits[0]);
2997 trailingZeroes--;
2998 }
2999 self->OutStream(self, digits[index]);
3000 }
3001 }
3002 }
3003
3004 if (keepTrailingZeroes)
3005 {
3006 while (trailingZeroes > 0)
3007 {
3008 self->OutStream(self, digits[0]);
3009 trailingZeroes--;
3010 }
3011 }
3012
Daniel Veillard92ad2102001-03-27 12:47:33 +00003013 /* Output exponent */
3014 if (exponentDigits > 0)
3015 {
3016 self->OutStream(self,
3017 isHex
3018 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3019 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3020 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003021
3022 /* The exponent must contain at least two digits */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003023 if (requireTwoDigitExponent)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003024 self->OutStream(self, '0');
3025
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003026 if (isHex)
3027 base = 10.0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003028 exponentBase = (int)TrioPower(base, exponentDigits - 1);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003029 for (i = 0; i < exponentDigits; i++)
3030 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003031 self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3032 exponentBase /= base;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003033 }
3034 }
3035 /* Output trailing spaces */
3036 if (flags & FLAGS_LEFTADJUST)
3037 {
3038 for (i = expectedWidth; i < width; i++)
3039 {
3040 self->OutStream(self, CHAR_ADJUST);
3041 }
3042 }
3043}
3044
3045/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003046 * TrioFormatProcess
3047 *
3048 * Description:
3049 * This is the main engine for formatting output
Daniel Veillard92ad2102001-03-27 12:47:33 +00003050 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003051TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003052TrioFormatProcess
3053TRIO_ARGS3((data, format, parameters),
3054 trio_class_t *data,
3055 TRIO_CONST char *format,
3056 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003057{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003058#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003059 int charlen;
3060#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00003061 int i;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003062 TRIO_CONST char *string;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003063 trio_pointer_t pointer;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003064 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003065 int width;
3066 int precision;
3067 int base;
3068 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003069
Daniel Veillard92ad2102001-03-27 12:47:33 +00003070 index = 0;
3071 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003072#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003073 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003074#endif
3075
3076 while (format[index])
3077 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003078#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003079 if (! isascii(format[index]))
3080 {
3081 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003082 /*
3083 * Only valid multibyte characters are handled here. Invalid
3084 * multibyte characters (charlen == -1) are handled as normal
3085 * characters.
3086 */
3087 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003088 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003089 while (charlen-- > 0)
3090 {
3091 data->OutStream(data, format[index++]);
3092 }
3093 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003094 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003095 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003096#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003097 if (CHAR_IDENTIFIER == format[index])
3098 {
3099 if (CHAR_IDENTIFIER == format[index + 1])
3100 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003101 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003102 index += 2;
3103 }
3104 else
3105 {
3106 /* Skip the parameter entries */
3107 while (parameters[i].type == FORMAT_PARAMETER)
3108 i++;
3109
3110 flags = parameters[i].flags;
3111
3112 /* Find width */
3113 width = parameters[i].width;
3114 if (flags & FLAGS_WIDTH_PARAMETER)
3115 {
3116 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003117 width = (int)parameters[width].data.number.as_signed;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003118 if (width < 0)
3119 {
3120 /*
3121 * A negative width is the same as the - flag and
3122 * a positive width.
3123 */
3124 flags |= FLAGS_LEFTADJUST;
3125 flags &= ~FLAGS_NILPADDING;
3126 width = -width;
3127 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003128 }
3129
3130 /* Find precision */
3131 if (flags & FLAGS_PRECISION)
3132 {
3133 precision = parameters[i].precision;
3134 if (flags & FLAGS_PRECISION_PARAMETER)
3135 {
3136 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003137 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00003138 if (precision < 0)
3139 {
3140 /*
3141 * A negative precision is the same as no
3142 * precision
3143 */
3144 precision = NO_PRECISION;
3145 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003146 }
3147 }
3148 else
3149 {
3150 precision = NO_PRECISION;
3151 }
3152
3153 /* Find base */
3154 base = parameters[i].base;
3155 if (flags & FLAGS_BASE_PARAMETER)
3156 {
3157 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003158 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003159 }
3160
3161 switch (parameters[i].type)
3162 {
3163 case FORMAT_CHAR:
3164 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003165 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003166 if (! (flags & FLAGS_LEFTADJUST))
3167 {
3168 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003169 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003170 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003171#if TRIO_WIDECHAR
3172 if (flags & FLAGS_WIDECHAR)
3173 {
3174 TrioWriteWideStringCharacter(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003175 (trio_wchar_t)parameters[i].data.number.as_signed,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003176 flags,
3177 NO_WIDTH);
3178 }
3179 else
3180#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +00003181 {
3182 TrioWriteStringCharacter(data,
3183 (int)parameters[i].data.number.as_signed,
3184 flags);
3185 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003186
3187 if (flags & FLAGS_LEFTADJUST)
3188 {
3189 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003190 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003191 }
3192 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003193 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003194
3195 break; /* FORMAT_CHAR */
3196
3197 case FORMAT_INT:
Daniel Veillard92ad2102001-03-27 12:47:33 +00003198 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003199 parameters[i].data.number.as_unsigned,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003200 flags,
3201 width,
3202 precision,
3203 base);
3204
3205 break; /* FORMAT_INT */
3206
3207 case FORMAT_DOUBLE:
3208 TrioWriteDouble(data,
3209 parameters[i].data.longdoubleNumber,
3210 flags,
3211 width,
3212 precision,
3213 base);
3214 break; /* FORMAT_DOUBLE */
3215
3216 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003217#if TRIO_WIDECHAR
3218 if (flags & FLAGS_WIDECHAR)
3219 {
3220 TrioWriteWideString(data,
3221 parameters[i].data.wstring,
3222 flags,
3223 width,
3224 precision);
3225 }
3226 else
3227#endif
3228 {
3229 TrioWriteString(data,
3230 parameters[i].data.string,
3231 flags,
3232 width,
3233 precision);
3234 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003235 break; /* FORMAT_STRING */
3236
3237 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00003238 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003239 trio_reference_t reference;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003240
3241 reference.data = data;
3242 reference.parameter = &parameters[i];
3243 trio_print_pointer(&reference, parameters[i].data.pointer);
3244 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003245 break; /* FORMAT_POINTER */
3246
3247 case FORMAT_COUNT:
3248 pointer = parameters[i].data.pointer;
3249 if (NULL != pointer)
3250 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003251 /*
3252 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00003253 * characters written to the output stream so far by
3254 * this call", which is data->committed
3255 */
3256#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3257 if (flags & FLAGS_SIZE_T)
3258 *(size_t *)pointer = (size_t)data->committed;
3259 else
3260#endif
3261#if defined(QUALIFIER_PTRDIFF_T)
3262 if (flags & FLAGS_PTRDIFF_T)
3263 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3264 else
3265#endif
3266#if defined(QUALIFIER_INTMAX_T)
3267 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003268 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003269 else
3270#endif
3271 if (flags & FLAGS_QUAD)
3272 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003273 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003274 }
3275 else if (flags & FLAGS_LONG)
3276 {
3277 *(long int *)pointer = (long int)data->committed;
3278 }
3279 else if (flags & FLAGS_SHORT)
3280 {
3281 *(short int *)pointer = (short int)data->committed;
3282 }
3283 else
3284 {
3285 *(int *)pointer = (int)data->committed;
3286 }
3287 }
3288 break; /* FORMAT_COUNT */
3289
3290 case FORMAT_PARAMETER:
3291 break; /* FORMAT_PARAMETER */
3292
3293#if defined(FORMAT_ERRNO)
3294 case FORMAT_ERRNO:
Bjorn Reese026d29f2002-01-19 15:40:18 +00003295 string = trio_error(parameters[i].data.errorNumber);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003296 if (string)
3297 {
3298 TrioWriteString(data,
3299 string,
3300 flags,
3301 width,
3302 precision);
3303 }
3304 else
3305 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003306 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00003307 TrioWriteNumber(data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003308 (trio_uintmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003309 flags,
3310 width,
3311 precision,
3312 BASE_DECIMAL);
3313 }
3314 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003315#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003316
Bjorn Reese70a9da52001-04-21 16:57:29 +00003317#if defined(FORMAT_USER_DEFINED)
3318 case FORMAT_USER_DEFINED:
3319 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003320 trio_reference_t reference;
3321 trio_userdef_t *def = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003322
3323 if (parameters[i].user_name[0] == NIL)
3324 {
3325 /* Use handle */
3326 if ((i > 0) ||
3327 (parameters[i - 1].type == FORMAT_PARAMETER))
Bjorn Reese026d29f2002-01-19 15:40:18 +00003328 def = (trio_userdef_t *)parameters[i - 1].data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003329 }
3330 else
3331 {
3332 /* Look up namespace */
3333 def = TrioFindNamespace(parameters[i].user_name, NULL);
3334 }
3335 if (def) {
3336 reference.data = data;
3337 reference.parameter = &parameters[i];
3338 def->callback(&reference);
3339 }
3340 }
3341 break;
3342#endif /* defined(FORMAT_USER_DEFINED) */
3343
Daniel Veillard92ad2102001-03-27 12:47:33 +00003344 default:
3345 break;
3346 } /* switch parameter type */
3347
3348 /* Prepare for next */
3349 index = parameters[i].indexAfterSpecifier;
3350 i++;
3351 }
3352 }
3353 else /* not identifier */
3354 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00003355 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003356 }
3357 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003358 return data->processed;
3359}
3360
3361/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003362 * TrioFormatRef
Bjorn Reese70a9da52001-04-21 16:57:29 +00003363 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003364TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003365TrioFormatRef
3366TRIO_ARGS4((reference, format, arglist, argarray),
3367 trio_reference_t *reference,
3368 TRIO_CONST char *format,
3369 va_list *arglist,
3370 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003371{
3372 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003373 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003374
Bjorn Reese026d29f2002-01-19 15:40:18 +00003375 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003376 if (status < 0)
3377 return status;
3378
Bjorn Reese026d29f2002-01-19 15:40:18 +00003379 status = TrioFormatProcess(reference->data, format, parameters);
3380 if (reference->data->error != 0)
3381 {
3382 status = reference->data->error;
3383 }
3384 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003385}
3386
3387/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003388 * TrioFormat
Bjorn Reese70a9da52001-04-21 16:57:29 +00003389 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003390TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003391TrioFormat
3392TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3393 trio_pointer_t destination,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003394 size_t destinationSize,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003395 void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
Bjorn Reese026d29f2002-01-19 15:40:18 +00003396 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003397 va_list *arglist,
3398 trio_pointer_t *argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003399{
3400 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003401 trio_class_t data;
3402 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00003403
3404 assert(VALID(OutStream));
3405 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003406
3407 memset(&data, 0, sizeof(data));
3408 data.OutStream = OutStream;
3409 data.location = destination;
3410 data.max = destinationSize;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003411 data.error = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003412
3413#if defined(USE_LOCALE)
3414 if (NULL == internalLocaleValues)
3415 {
3416 TrioSetLocale();
3417 }
3418#endif
3419
Bjorn Reese026d29f2002-01-19 15:40:18 +00003420 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003421 if (status < 0)
3422 return status;
3423
Bjorn Reese026d29f2002-01-19 15:40:18 +00003424 status = TrioFormatProcess(&data, format, parameters);
3425 if (data.error != 0)
3426 {
3427 status = data.error;
3428 }
3429 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003430}
3431
3432/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003433 * TrioOutStreamFile
Daniel Veillard92ad2102001-03-27 12:47:33 +00003434 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003435TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003436TrioOutStreamFile
3437TRIO_ARGS2((self, output),
3438 trio_class_t *self,
3439 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003440{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003441 FILE *file;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003442
3443 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003444 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003445
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003446 file = (FILE *)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003447 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003448 if (fputc(output, file) == EOF)
3449 {
3450 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3451 }
3452 else
3453 {
3454 self->committed++;
3455 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003456}
3457
3458/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003459 * TrioOutStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00003460 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003461TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003462TrioOutStreamFileDescriptor
3463TRIO_ARGS2((self, output),
3464 trio_class_t *self,
3465 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003466{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003467 int fd;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003468 char ch;
3469
3470 assert(VALID(self));
3471
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003472 fd = *((int *)self->location);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003473 ch = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003474 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003475 if (write(fd, &ch, sizeof(char)) == -1)
3476 {
3477 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3478 }
3479 else
3480 {
3481 self->committed++;
3482 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003483}
3484
3485/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003486 * TrioOutStreamCustom
3487 */
3488TRIO_PRIVATE void
3489TrioOutStreamCustom
3490TRIO_ARGS2((self, output),
3491 trio_class_t *self,
3492 int output)
3493{
3494 int status;
3495 trio_custom_t *data;
3496
3497 assert(VALID(self));
3498 assert(VALID(self->location));
3499
3500 data = (trio_custom_t *)self->location;
3501 if (data->stream.out)
3502 {
3503 status = (data->stream.out)(data->closure, output);
3504 if (status >= 0)
3505 {
3506 self->committed++;
3507 }
3508 else
3509 {
3510 if (self->error == 0)
3511 {
3512 self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3513 }
3514 }
3515 }
3516 self->processed++;
3517}
3518
3519/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003520 * TrioOutStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00003521 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003522TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003523TrioOutStreamString
3524TRIO_ARGS2((self, output),
3525 trio_class_t *self,
3526 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003527{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003528 char **buffer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003529
3530 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003531 assert(VALID(self->location));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003532
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003533 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003534 **buffer = (char)output;
3535 (*buffer)++;
3536 self->processed++;
3537 self->committed++;
3538}
3539
3540/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003541 * TrioOutStreamStringMax
Daniel Veillard92ad2102001-03-27 12:47:33 +00003542 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003543TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003544TrioOutStreamStringMax
3545TRIO_ARGS2((self, output),
3546 trio_class_t *self,
3547 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003548{
3549 char **buffer;
3550
3551 assert(VALID(self));
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003552 assert(VALID(self->location));
3553
Daniel Veillard92ad2102001-03-27 12:47:33 +00003554 buffer = (char **)self->location;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003555
3556 if (self->processed < self->max)
3557 {
3558 **buffer = (char)output;
3559 (*buffer)++;
3560 self->committed++;
3561 }
3562 self->processed++;
3563}
3564
3565/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003566 * TrioOutStreamStringDynamic
Daniel Veillard92ad2102001-03-27 12:47:33 +00003567 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003568TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003569TrioOutStreamStringDynamic
3570TRIO_ARGS2((self, output),
3571 trio_class_t *self,
3572 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003573{
Daniel Veillard92ad2102001-03-27 12:47:33 +00003574 assert(VALID(self));
3575 assert(VALID(self->location));
3576
Bjorn Reese026d29f2002-01-19 15:40:18 +00003577 if (self->error == 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003578 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003579 trio_xstring_append_char((trio_string_t *)self->location,
3580 (char)output);
3581 self->committed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003582 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003583 /* The processed variable must always be increased */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003584 self->processed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003585}
3586
Daniel Veillard92ad2102001-03-27 12:47:33 +00003587/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003588 *
3589 * Formatted printing functions
3590 *
3591 ************************************************************************/
3592
3593#if defined(TRIO_DOCUMENTATION)
3594# include "doc/doc_printf.h"
3595#endif
3596/** @addtogroup Printf
3597 @{
3598*/
3599
3600/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003601 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003602 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003603
3604/**
3605 Print to standard output stream.
3606
3607 @param format Formatting string.
3608 @param ... Arguments.
3609 @return Number of printed characters.
3610 */
3611TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003612trio_printf
3613TRIO_VARGS2((format, va_alist),
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(format));
3621
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003622 TRIO_VA_START(args, format);
3623 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3624 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003625 return status;
3626}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003627
Bjorn Reese026d29f2002-01-19 15:40:18 +00003628/**
3629 Print to standard output stream.
3630
3631 @param format Formatting string.
3632 @param args Arguments.
3633 @return Number of printed characters.
3634 */
3635TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003636trio_vprintf
3637TRIO_ARGS2((format, args),
3638 TRIO_CONST char *format,
3639 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003640{
3641 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003642
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003643 return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003644}
3645
Bjorn Reese026d29f2002-01-19 15:40:18 +00003646/**
3647 Print to standard output stream.
3648
3649 @param format Formatting string.
3650 @param args Arguments.
3651 @return Number of printed characters.
3652 */
3653TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003654trio_printfv
3655TRIO_ARGS2((format, args),
3656 TRIO_CONST char *format,
3657 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003658{
3659 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003660
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003661 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003662}
3663
Daniel Veillard92ad2102001-03-27 12:47:33 +00003664/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003665 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003666 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003667
3668/**
3669 Print to file.
3670
3671 @param file File pointer.
3672 @param format Formatting string.
3673 @param ... Arguments.
3674 @return Number of printed characters.
3675 */
3676TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003677trio_fprintf
3678TRIO_VARGS3((file, format, va_alist),
3679 FILE *file,
3680 TRIO_CONST char *format,
3681 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003682{
3683 int status;
3684 va_list args;
3685
3686 assert(VALID(file));
3687 assert(VALID(format));
3688
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003689 TRIO_VA_START(args, format);
3690 status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3691 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003692 return status;
3693}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003694
Bjorn Reese026d29f2002-01-19 15:40:18 +00003695/**
3696 Print to file.
3697
3698 @param file File pointer.
3699 @param format Formatting string.
3700 @param args Arguments.
3701 @return Number of printed characters.
3702 */
3703TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003704trio_vfprintf
3705TRIO_ARGS3((file, format, args),
3706 FILE *file,
3707 TRIO_CONST char *format,
3708 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003709{
3710 assert(VALID(file));
3711 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003712
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003713 return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003714}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003715
Bjorn Reese026d29f2002-01-19 15:40:18 +00003716/**
3717 Print to file.
3718
3719 @param file File pointer.
3720 @param format Formatting string.
3721 @param args Arguments.
3722 @return Number of printed characters.
3723 */
3724TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003725trio_fprintfv
3726TRIO_ARGS3((file, format, args),
3727 FILE *file,
3728 TRIO_CONST char *format,
3729 trio_pointer_t * args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003730{
3731 assert(VALID(file));
3732 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003733
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003734 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003735}
3736
Daniel Veillard92ad2102001-03-27 12:47:33 +00003737/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003738 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003739 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003740
3741/**
3742 Print to file descriptor.
3743
3744 @param fd File descriptor.
3745 @param format Formatting string.
3746 @param ... Arguments.
3747 @return Number of printed characters.
3748 */
3749TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003750trio_dprintf
3751TRIO_VARGS3((fd, format, va_alist),
3752 int fd,
3753 TRIO_CONST char *format,
3754 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003755{
3756 int status;
3757 va_list args;
3758
3759 assert(VALID(format));
3760
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003761 TRIO_VA_START(args, format);
3762 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3763 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003764 return status;
3765}
3766
Bjorn Reese026d29f2002-01-19 15:40:18 +00003767/**
3768 Print to file descriptor.
3769
3770 @param fd File descriptor.
3771 @param format Formatting string.
3772 @param args Arguments.
3773 @return Number of printed characters.
3774 */
3775TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003776trio_vdprintf
3777TRIO_ARGS3((fd, format, args),
3778 int fd,
3779 TRIO_CONST char *format,
3780 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003781{
3782 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003783
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003784 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003785}
3786
Bjorn Reese026d29f2002-01-19 15:40:18 +00003787/**
3788 Print to file descriptor.
3789
3790 @param fd File descriptor.
3791 @param format Formatting string.
3792 @param args Arguments.
3793 @return Number of printed characters.
3794 */
3795TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003796trio_dprintfv
3797TRIO_ARGS3((fd, format, args),
3798 int fd,
3799 TRIO_CONST char *format,
3800 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003801{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003802 assert(VALID(format));
3803
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003804 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3805}
3806
3807/*************************************************************************
3808 * cprintf
3809 */
3810TRIO_PUBLIC int
3811trio_cprintf
3812TRIO_VARGS4((stream, closure, format, va_alist),
3813 trio_outstream_t stream,
3814 trio_pointer_t closure,
3815 TRIO_CONST char *format,
3816 TRIO_VA_DECL)
3817{
3818 int status;
3819 va_list args;
3820 trio_custom_t data;
3821
3822 assert(VALID(stream));
3823 assert(VALID(format));
3824
3825 TRIO_VA_START(args, format);
3826 data.stream.out = stream;
3827 data.closure = closure;
3828 status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3829 TRIO_VA_END(args);
3830 return status;
3831}
3832
3833TRIO_PUBLIC int
3834trio_vcprintf
3835TRIO_ARGS4((stream, closure, format, args),
3836 trio_outstream_t stream,
3837 trio_pointer_t closure,
3838 TRIO_CONST char *format,
3839 va_list args)
3840{
3841 trio_custom_t data;
3842
3843 assert(VALID(stream));
3844 assert(VALID(format));
3845
3846 data.stream.out = stream;
3847 data.closure = closure;
3848 return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3849}
3850
3851TRIO_PUBLIC int
3852trio_cprintfv
3853TRIO_ARGS4((stream, closure, format, args),
3854 trio_outstream_t stream,
3855 trio_pointer_t closure,
3856 TRIO_CONST char *format,
3857 void **args)
3858{
3859 trio_custom_t data;
3860
3861 assert(VALID(stream));
3862 assert(VALID(format));
3863
3864 data.stream.out = stream;
3865 data.closure = closure;
3866 return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003867}
3868
3869/*************************************************************************
3870 * sprintf
3871 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003872
3873/**
3874 Print to string.
3875
3876 @param buffer Output string.
3877 @param format Formatting string.
3878 @param ... Arguments.
3879 @return Number of printed characters.
3880 */
3881TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003882trio_sprintf
3883TRIO_VARGS3((buffer, format, va_alist),
3884 char *buffer,
3885 TRIO_CONST char *format,
3886 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003887{
3888 int status;
3889 va_list args;
3890
3891 assert(VALID(buffer));
3892 assert(VALID(format));
3893
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003894 TRIO_VA_START(args, format);
3895 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003896 *buffer = NIL; /* Terminate with NIL character */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003897 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003898 return status;
3899}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003900
Bjorn Reese026d29f2002-01-19 15:40:18 +00003901/**
3902 Print to string.
3903
3904 @param buffer Output string.
3905 @param format Formatting string.
3906 @param args Arguments.
3907 @return Number of printed characters.
3908 */
3909TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003910trio_vsprintf
3911TRIO_ARGS3((buffer, format, args),
3912 char *buffer,
3913 TRIO_CONST char *format,
3914 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003915{
3916 int status;
3917
3918 assert(VALID(buffer));
3919 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003920
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003921 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003922 *buffer = NIL;
3923 return status;
3924}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003925
Bjorn Reese026d29f2002-01-19 15:40:18 +00003926/**
3927 Print to string.
3928
3929 @param buffer Output string.
3930 @param format Formatting string.
3931 @param args Arguments.
3932 @return Number of printed characters.
3933 */
3934TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003935trio_sprintfv
3936TRIO_ARGS3((buffer, format, args),
3937 char *buffer,
3938 TRIO_CONST char *format,
3939 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003940{
3941 int status;
3942
3943 assert(VALID(buffer));
3944 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003945
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003946 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003947 *buffer = NIL;
3948 return status;
3949}
3950
Daniel Veillard92ad2102001-03-27 12:47:33 +00003951/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003952 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003953 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003954
3955/**
3956 Print at most @p max characters to string.
3957
3958 @param buffer Output string.
3959 @param max Maximum number of characters to print.
3960 @param format Formatting string.
3961 @param ... Arguments.
3962 @return Number of printed characters.
3963 */
3964TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003965trio_snprintf
3966TRIO_VARGS4((buffer, max, format, va_alist),
3967 char *buffer,
3968 size_t max,
3969 TRIO_CONST char *format,
3970 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003971{
3972 int status;
3973 va_list args;
3974
3975 assert(VALID(buffer));
3976 assert(VALID(format));
3977
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003978 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003979 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003980 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003981 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003982 *buffer = NIL;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003983 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003984 return status;
3985}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003986
Bjorn Reese026d29f2002-01-19 15:40:18 +00003987/**
3988 Print at most @p max characters to string.
3989
3990 @param buffer Output string.
3991 @param max Maximum number of characters to print.
3992 @param format Formatting string.
3993 @param args Arguments.
3994 @return Number of printed characters.
3995 */
3996TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00003997trio_vsnprintf
3998TRIO_ARGS4((buffer, max, format, args),
3999 char *buffer,
4000 size_t max,
4001 TRIO_CONST char *format,
4002 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004003{
4004 int status;
4005
4006 assert(VALID(buffer));
4007 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00004008
Bjorn Reese026d29f2002-01-19 15:40:18 +00004009 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004010 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004011 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004012 *buffer = NIL;
4013 return status;
4014}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004015
Bjorn Reese026d29f2002-01-19 15:40:18 +00004016/**
4017 Print at most @p max characters to string.
4018
4019 @param buffer Output string.
4020 @param max Maximum number of characters to print.
4021 @param format Formatting string.
4022 @param args Arguments.
4023 @return Number of printed characters.
4024 */
4025TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004026trio_snprintfv
4027TRIO_ARGS4((buffer, max, format, args),
4028 char *buffer,
4029 size_t max,
4030 TRIO_CONST char *format,
4031 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004032{
4033 int status;
4034
4035 assert(VALID(buffer));
4036 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004037
Bjorn Reese026d29f2002-01-19 15:40:18 +00004038 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004039 TrioOutStreamStringMax, format, NULL, args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004040 if (max > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004041 *buffer = NIL;
4042 return status;
4043}
4044
4045/*************************************************************************
4046 * snprintfcat
4047 * Appends the new string to the buffer string overwriting the '\0'
4048 * character at the end of buffer.
4049 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004050TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004051trio_snprintfcat
4052TRIO_VARGS4((buffer, max, format, va_alist),
4053 char *buffer,
4054 size_t max,
4055 TRIO_CONST char *format,
4056 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004057{
4058 int status;
4059 va_list args;
4060 size_t buf_len;
4061
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004062 TRIO_VA_START(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004063
4064 assert(VALID(buffer));
4065 assert(VALID(format));
4066
Bjorn Reese026d29f2002-01-19 15:40:18 +00004067 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004068 buffer = &buffer[buf_len];
4069
Bjorn Reese026d29f2002-01-19 15:40:18 +00004070 status = TrioFormat(&buffer, max - 1 - buf_len,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004071 TrioOutStreamStringMax, format, &args, NULL);
4072 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004073 *buffer = NIL;
4074 return status;
4075}
4076
Bjorn Reese026d29f2002-01-19 15:40:18 +00004077TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004078trio_vsnprintfcat
4079TRIO_ARGS4((buffer, max, format, args),
4080 char *buffer,
4081 size_t max,
4082 TRIO_CONST char *format,
4083 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004084{
4085 int status;
4086 size_t buf_len;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004087
Bjorn Reese70a9da52001-04-21 16:57:29 +00004088 assert(VALID(buffer));
4089 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004090
Bjorn Reese026d29f2002-01-19 15:40:18 +00004091 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004092 buffer = &buffer[buf_len];
Bjorn Reese026d29f2002-01-19 15:40:18 +00004093 status = TrioFormat(&buffer, max - 1 - buf_len,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004094 TrioOutStreamStringMax, format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004095 *buffer = NIL;
4096 return status;
4097}
4098
4099/*************************************************************************
4100 * trio_aprintf
4101 */
4102
4103/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004104TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004105trio_aprintf
4106TRIO_VARGS2((format, va_alist),
4107 TRIO_CONST char *format,
4108 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004109{
4110 va_list args;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004111 trio_string_t *info;
4112 char *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004113
4114 assert(VALID(format));
4115
Bjorn Reese026d29f2002-01-19 15:40:18 +00004116 info = trio_xstring_duplicate("");
4117 if (info)
4118 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004119 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004120 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004121 format, &args, NULL);
4122 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004123
Bjorn Reese026d29f2002-01-19 15:40:18 +00004124 trio_string_terminate(info);
4125 result = trio_string_extract(info);
4126 trio_string_destroy(info);
4127 }
4128 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004129}
4130
4131/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004132TRIO_PUBLIC char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004133trio_vaprintf
4134TRIO_ARGS2((format, args),
4135 TRIO_CONST char *format,
4136 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004137{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004138 trio_string_t *info;
4139 char *result = NULL;
4140
Bjorn Reese70a9da52001-04-21 16:57:29 +00004141 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004142
Bjorn Reese026d29f2002-01-19 15:40:18 +00004143 info = trio_xstring_duplicate("");
4144 if (info)
4145 {
4146 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004147 format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004148 trio_string_terminate(info);
4149 result = trio_string_extract(info);
4150 trio_string_destroy(info);
4151 }
4152 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004153}
4154
Bjorn Reese026d29f2002-01-19 15:40:18 +00004155TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004156trio_asprintf
4157TRIO_VARGS3((result, format, va_alist),
4158 char **result,
4159 TRIO_CONST char *format,
4160 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004161{
4162 va_list args;
4163 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004164 trio_string_t *info;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004165
4166 assert(VALID(format));
4167
Bjorn Reese026d29f2002-01-19 15:40:18 +00004168 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004169
Bjorn Reese026d29f2002-01-19 15:40:18 +00004170 info = trio_xstring_duplicate("");
4171 if (info == NULL)
4172 {
4173 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4174 }
4175 else
4176 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004177 TRIO_VA_START(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004178 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004179 format, &args, NULL);
4180 TRIO_VA_END(args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004181 if (status >= 0)
4182 {
4183 trio_string_terminate(info);
4184 *result = trio_string_extract(info);
4185 }
4186 trio_string_destroy(info);
4187 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004188 return status;
4189}
4190
Bjorn Reese026d29f2002-01-19 15:40:18 +00004191TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004192trio_vasprintf
4193TRIO_ARGS3((result, format, args),
4194 char **result,
4195 TRIO_CONST char *format,
4196 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004197{
4198 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004199 trio_string_t *info;
4200
Bjorn Reese70a9da52001-04-21 16:57:29 +00004201 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004202
Bjorn Reese026d29f2002-01-19 15:40:18 +00004203 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004204
Bjorn Reese026d29f2002-01-19 15:40:18 +00004205 info = trio_xstring_duplicate("");
4206 if (info == NULL)
4207 {
4208 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4209 }
4210 else
4211 {
4212 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004213 format, &args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004214 if (status >= 0)
4215 {
4216 trio_string_terminate(info);
4217 *result = trio_string_extract(info);
4218 }
4219 trio_string_destroy(info);
4220 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004221 return status;
4222}
4223
Bjorn Reese026d29f2002-01-19 15:40:18 +00004224/** @} End of Printf documentation module */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004225
4226/*************************************************************************
4227 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00004228 * CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00004229 *
4230 ************************************************************************/
4231
Bjorn Reese026d29f2002-01-19 15:40:18 +00004232#if defined(TRIO_DOCUMENTATION)
4233# include "doc/doc_register.h"
4234#endif
4235/**
4236 @addtogroup UserDefined
4237 @{
4238*/
4239
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004240#if TRIO_EXTENSION
4241
Bjorn Reese70a9da52001-04-21 16:57:29 +00004242/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004243 * trio_register
Bjorn Reese70a9da52001-04-21 16:57:29 +00004244 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004245
4246/**
4247 Register new user-defined specifier.
4248
4249 @param callback
4250 @param name
4251 @return Handle.
4252 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004253TRIO_PUBLIC trio_pointer_t
4254trio_register
4255TRIO_ARGS2((callback, name),
4256 trio_callback_t callback,
4257 TRIO_CONST char *name)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004258{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004259 trio_userdef_t *def;
4260 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004261
4262 if (callback == NULL)
4263 return NULL;
4264
4265 if (name)
4266 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004267 /* Handle built-in namespaces */
4268 if (name[0] == ':')
4269 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004270 if (trio_equal(name, ":enter"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004271 {
4272 internalEnterCriticalRegion = callback;
4273 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004274 else if (trio_equal(name, ":leave"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004275 {
4276 internalLeaveCriticalRegion = callback;
4277 }
4278 return NULL;
4279 }
4280
Bjorn Reese70a9da52001-04-21 16:57:29 +00004281 /* Bail out if namespace is too long */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004282 if (trio_length(name) >= MAX_USER_NAME)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004283 return NULL;
4284
4285 /* Bail out if namespace already is registered */
4286 def = TrioFindNamespace(name, &prev);
4287 if (def)
4288 return NULL;
4289 }
4290
Bjorn Reese026d29f2002-01-19 15:40:18 +00004291 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004292 if (def)
4293 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004294 if (internalEnterCriticalRegion)
4295 (void)internalEnterCriticalRegion(NULL);
4296
Bjorn Reese70a9da52001-04-21 16:57:29 +00004297 if (name)
4298 {
4299 /* Link into internal list */
4300 if (prev == NULL)
4301 internalUserDef = def;
4302 else
4303 prev->next = def;
4304 }
4305 /* Initialize */
4306 def->callback = callback;
4307 def->name = (name == NULL)
4308 ? NULL
Bjorn Reese026d29f2002-01-19 15:40:18 +00004309 : trio_duplicate(name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004310 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004311
4312 if (internalLeaveCriticalRegion)
4313 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004314 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004315 return (trio_pointer_t)def;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004316}
4317
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004318/**
4319 Unregister an existing user-defined specifier.
4320
4321 @param handle
Bjorn Reese70a9da52001-04-21 16:57:29 +00004322 */
4323void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004324trio_unregister
4325TRIO_ARGS1((handle),
4326 trio_pointer_t handle)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004327{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004328 trio_userdef_t *self = (trio_userdef_t *)handle;
4329 trio_userdef_t *def;
4330 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004331
4332 assert(VALID(self));
4333
4334 if (self->name)
4335 {
4336 def = TrioFindNamespace(self->name, &prev);
4337 if (def)
4338 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004339 if (internalEnterCriticalRegion)
4340 (void)internalEnterCriticalRegion(NULL);
4341
Bjorn Reese70a9da52001-04-21 16:57:29 +00004342 if (prev == NULL)
4343 internalUserDef = NULL;
4344 else
4345 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004346
4347 if (internalLeaveCriticalRegion)
4348 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004349 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004350 trio_destroy(self->name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004351 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004352 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004353}
4354
4355/*************************************************************************
4356 * trio_get_format [public]
4357 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004358TRIO_CONST char *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004359trio_get_format
4360TRIO_ARGS1((ref),
4361 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004362{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004363#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004364 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004365#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00004366
Bjorn Reese026d29f2002-01-19 15:40:18 +00004367 return (((trio_reference_t *)ref)->parameter->user_data);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004368}
4369
4370/*************************************************************************
4371 * trio_get_argument [public]
4372 */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004373trio_pointer_t
4374trio_get_argument
4375TRIO_ARGS1((ref),
4376 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004377{
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004378#if defined(FORMAT_USER_DEFINED)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004379 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004380#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00004381
Bjorn Reese026d29f2002-01-19 15:40:18 +00004382 return ((trio_reference_t *)ref)->parameter->data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004383}
4384
4385/*************************************************************************
4386 * trio_get_width / trio_set_width [public]
4387 */
4388int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004389trio_get_width
4390TRIO_ARGS1((ref),
4391 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004392{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004393 return ((trio_reference_t *)ref)->parameter->width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004394}
4395
4396void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004397trio_set_width
4398TRIO_ARGS2((ref, width),
4399 trio_pointer_t ref,
4400 int width)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004401{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004402 ((trio_reference_t *)ref)->parameter->width = width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004403}
4404
4405/*************************************************************************
4406 * trio_get_precision / trio_set_precision [public]
4407 */
4408int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004409trio_get_precision
4410TRIO_ARGS1((ref),
4411 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004412{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004413 return (((trio_reference_t *)ref)->parameter->precision);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004414}
4415
4416void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004417trio_set_precision
4418TRIO_ARGS2((ref, precision),
4419 trio_pointer_t ref,
4420 int precision)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004421{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004422 ((trio_reference_t *)ref)->parameter->precision = precision;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004423}
4424
4425/*************************************************************************
4426 * trio_get_base / trio_set_base [public]
4427 */
4428int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004429trio_get_base
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->base);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004434}
4435
4436void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004437trio_set_base
4438TRIO_ARGS2((ref, base),
4439 trio_pointer_t ref,
4440 int base)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004441{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004442 ((trio_reference_t *)ref)->parameter->base = base;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004443}
4444
4445/*************************************************************************
4446 * trio_get_long / trio_set_long [public]
4447 */
4448int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004449trio_get_long
4450TRIO_ARGS1((ref),
4451 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004452{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004453 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4454 ? TRUE
4455 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004456}
4457
4458void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004459trio_set_long
4460TRIO_ARGS2((ref, is_long),
4461 trio_pointer_t ref,
4462 int is_long)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004463{
4464 if (is_long)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004465 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004466 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004467 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004468}
4469
4470/*************************************************************************
4471 * trio_get_longlong / trio_set_longlong [public]
4472 */
4473int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004474trio_get_longlong
4475TRIO_ARGS1((ref),
4476 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004477{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004478 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4479 ? TRUE
4480 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004481}
4482
4483void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004484trio_set_longlong
4485TRIO_ARGS2((ref, is_longlong),
4486 trio_pointer_t ref,
4487 int is_longlong)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004488{
4489 if (is_longlong)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004490 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004491 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004492 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004493}
4494
4495/*************************************************************************
4496 * trio_get_longdouble / trio_set_longdouble [public]
4497 */
4498int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004499trio_get_longdouble
4500TRIO_ARGS1((ref),
4501 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004502{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004503 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4504 ? TRUE
4505 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004506}
4507
4508void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004509trio_set_longdouble
4510TRIO_ARGS2((ref, is_longdouble),
4511 trio_pointer_t ref,
4512 int is_longdouble)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004513{
4514 if (is_longdouble)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004515 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004516 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004517 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004518}
4519
4520/*************************************************************************
4521 * trio_get_short / trio_set_short [public]
4522 */
4523int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004524trio_get_short
4525TRIO_ARGS1((ref),
4526 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004527{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004528 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4529 ? TRUE
4530 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004531}
4532
4533void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004534trio_set_short
4535TRIO_ARGS2((ref, is_short),
4536 trio_pointer_t ref,
4537 int is_short)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004538{
4539 if (is_short)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004540 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004541 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004542 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004543}
4544
4545/*************************************************************************
4546 * trio_get_shortshort / trio_set_shortshort [public]
4547 */
4548int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004549trio_get_shortshort
4550TRIO_ARGS1((ref),
4551 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004552{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004553 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4554 ? TRUE
4555 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004556}
4557
4558void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004559trio_set_shortshort
4560TRIO_ARGS2((ref, is_shortshort),
4561 trio_pointer_t ref,
4562 int is_shortshort)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004563{
4564 if (is_shortshort)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004565 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004566 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004567 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004568}
4569
4570/*************************************************************************
4571 * trio_get_alternative / trio_set_alternative [public]
4572 */
4573int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004574trio_get_alternative
4575TRIO_ARGS1((ref),
4576 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004577{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004578 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4579 ? TRUE
4580 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004581}
4582
4583void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004584trio_set_alternative
4585TRIO_ARGS2((ref, is_alternative),
4586 trio_pointer_t ref,
4587 int is_alternative)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004588{
4589 if (is_alternative)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004590 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004591 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004592 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004593}
4594
4595/*************************************************************************
4596 * trio_get_alignment / trio_set_alignment [public]
4597 */
4598int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004599trio_get_alignment
4600TRIO_ARGS1((ref),
4601 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004602{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004603 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4604 ? TRUE
4605 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004606}
4607
4608void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004609trio_set_alignment
4610TRIO_ARGS2((ref, is_leftaligned),
4611 trio_pointer_t ref,
4612 int is_leftaligned)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004613{
4614 if (is_leftaligned)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004615 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004616 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004617 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004618}
4619
4620/*************************************************************************
4621 * trio_get_spacing /trio_set_spacing [public]
4622 */
4623int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004624trio_get_spacing
4625TRIO_ARGS1((ref),
4626 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004627{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004628 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4629 ? TRUE
4630 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004631}
4632
4633void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004634trio_set_spacing
4635TRIO_ARGS2((ref, is_space),
4636 trio_pointer_t ref,
4637 int is_space)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004638{
4639 if (is_space)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004640 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004641 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004642 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004643}
4644
4645/*************************************************************************
4646 * trio_get_sign / trio_set_sign [public]
4647 */
4648int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004649trio_get_sign
4650TRIO_ARGS1((ref),
4651 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004652{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004653 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4654 ? TRUE
4655 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004656}
4657
4658void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004659trio_set_sign
4660TRIO_ARGS2((ref, is_sign),
4661 trio_pointer_t ref,
4662 int is_sign)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004663{
4664 if (is_sign)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004665 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004666 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004667 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004668}
4669
4670/*************************************************************************
4671 * trio_get_padding / trio_set_padding [public]
4672 */
4673int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004674trio_get_padding
4675TRIO_ARGS1((ref),
4676 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004677{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004678 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4679 ? TRUE
4680 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004681}
4682
4683void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004684trio_set_padding
4685TRIO_ARGS2((ref, is_padding),
4686 trio_pointer_t ref,
4687 int is_padding)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004688{
4689 if (is_padding)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004690 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004691 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004692 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004693}
4694
4695/*************************************************************************
4696 * trio_get_quote / trio_set_quote [public]
4697 */
4698int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004699trio_get_quote
4700TRIO_ARGS1((ref),
4701 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004702{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004703 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4704 ? TRUE
4705 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004706}
4707
4708void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004709trio_set_quote
4710TRIO_ARGS2((ref, is_quote),
4711 trio_pointer_t ref,
4712 int is_quote)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004713{
4714 if (is_quote)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004715 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004716 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004717 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004718}
4719
4720/*************************************************************************
4721 * trio_get_upper / trio_set_upper [public]
4722 */
4723int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004724trio_get_upper
4725TRIO_ARGS1((ref),
4726 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004727{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004728 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4729 ? TRUE
4730 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004731}
4732
4733void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004734trio_set_upper
4735TRIO_ARGS2((ref, is_upper),
4736 trio_pointer_t ref,
4737 int is_upper)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004738{
4739 if (is_upper)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004740 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004741 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004742 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004743}
4744
4745/*************************************************************************
4746 * trio_get_largest / trio_set_largest [public]
4747 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004748#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004749int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004750trio_get_largest
4751TRIO_ARGS1((ref),
4752 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004753{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004754 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4755 ? TRUE
4756 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004757}
4758
4759void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004760trio_set_largest
4761TRIO_ARGS2((ref, is_largest),
4762 trio_pointer_t ref,
4763 int is_largest)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004764{
4765 if (is_largest)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004766 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004767 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004768 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004769}
4770#endif
4771
4772/*************************************************************************
4773 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4774 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004775int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004776trio_get_ptrdiff
4777TRIO_ARGS1((ref),
4778 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004779{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004780 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4781 ? TRUE
4782 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004783}
4784
4785void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004786trio_set_ptrdiff
4787TRIO_ARGS2((ref, is_ptrdiff),
4788 trio_pointer_t ref,
4789 int is_ptrdiff)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004790{
4791 if (is_ptrdiff)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004792 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004793 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004794 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004795}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004796
4797/*************************************************************************
4798 * trio_get_size / trio_set_size [public]
4799 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004800#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004801int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004802trio_get_size
4803TRIO_ARGS1((ref),
4804 trio_pointer_t ref)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004805{
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004806 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4807 ? TRUE
4808 : FALSE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004809}
4810
4811void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004812trio_set_size
4813TRIO_ARGS2((ref, is_size),
4814 trio_pointer_t ref,
4815 int is_size)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004816{
4817 if (is_size)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004818 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004819 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004820 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004821}
4822#endif
4823
4824/*************************************************************************
4825 * trio_print_int [public]
4826 */
4827void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004828trio_print_int
4829TRIO_ARGS2((ref, number),
4830 trio_pointer_t ref,
4831 int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004832{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004833 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004834
4835 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004836 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004837 self->parameter->flags,
4838 self->parameter->width,
4839 self->parameter->precision,
4840 self->parameter->base);
4841}
4842
4843/*************************************************************************
4844 * trio_print_uint [public]
4845 */
4846void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004847trio_print_uint
4848TRIO_ARGS2((ref, number),
4849 trio_pointer_t ref,
4850 unsigned int number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004851{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004852 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004853
4854 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004855 (trio_uintmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004856 self->parameter->flags | FLAGS_UNSIGNED,
4857 self->parameter->width,
4858 self->parameter->precision,
4859 self->parameter->base);
4860}
4861
4862/*************************************************************************
4863 * trio_print_double [public]
4864 */
4865void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004866trio_print_double
4867TRIO_ARGS2((ref, number),
4868 trio_pointer_t ref,
4869 double number)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004870{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004871 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004872
4873 TrioWriteDouble(self->data,
4874 number,
4875 self->parameter->flags,
4876 self->parameter->width,
4877 self->parameter->precision,
4878 self->parameter->base);
4879}
4880
4881/*************************************************************************
4882 * trio_print_string [public]
4883 */
4884void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004885trio_print_string
4886TRIO_ARGS2((ref, string),
4887 trio_pointer_t ref,
4888 char *string)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004889{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004890 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004891
4892 TrioWriteString(self->data,
4893 string,
4894 self->parameter->flags,
4895 self->parameter->width,
4896 self->parameter->precision);
4897}
4898
4899/*************************************************************************
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004900 * trio_print_ref [public]
4901 */
4902int
4903trio_print_ref
4904TRIO_VARGS3((ref, format, va_alist),
4905 trio_pointer_t ref,
4906 TRIO_CONST char *format,
4907 TRIO_VA_DECL)
4908{
4909 int status;
4910 va_list arglist;
4911
4912 assert(VALID(format));
4913
4914 TRIO_VA_START(arglist, format);
4915 status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4916 TRIO_VA_END(arglist);
4917 return status;
4918}
4919
4920/*************************************************************************
4921 * trio_vprint_ref [public]
4922 */
4923int
4924trio_vprint_ref
4925TRIO_ARGS3((ref, format, arglist),
4926 trio_pointer_t ref,
4927 TRIO_CONST char *format,
4928 va_list arglist)
4929{
4930 assert(VALID(format));
4931
4932 return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4933}
4934
4935/*************************************************************************
4936 * trio_printv_ref [public]
4937 */
4938int
4939trio_printv_ref
4940TRIO_ARGS3((ref, format, argarray),
4941 trio_pointer_t ref,
4942 TRIO_CONST char *format,
4943 trio_pointer_t *argarray)
4944{
4945 assert(VALID(format));
4946
4947 return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4948}
4949
4950#endif /* TRIO_EXTENSION */
4951
4952/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00004953 * trio_print_pointer [public]
4954 */
4955void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004956trio_print_pointer
4957TRIO_ARGS2((ref, pointer),
4958 trio_pointer_t ref,
4959 trio_pointer_t pointer)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004960{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004961 trio_reference_t *self = (trio_reference_t *)ref;
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00004962 trio_flags_t flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004963 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004964
4965 if (NULL == pointer)
4966 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004967 TRIO_CONST char *string = internalNullString;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004968 while (*string)
4969 self->data->OutStream(self->data, *string++);
4970 }
4971 else
4972 {
4973 /*
4974 * The subtraction of the null pointer is a workaround
4975 * to avoid a compiler warning. The performance overhead
4976 * is negligible (and likely to be removed by an
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004977 * optimizing compiler). The (char *) casting is done
Bjorn Reese70a9da52001-04-21 16:57:29 +00004978 * to please ANSI C++.
4979 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004980 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004981 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004982 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004983 flags = self->parameter->flags;
4984 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4985 FLAGS_NILPADDING);
4986 TrioWriteNumber(self->data,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004987 number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004988 flags,
4989 POINTER_WIDTH,
4990 NO_PRECISION,
4991 BASE_HEX);
4992 }
4993}
4994
Bjorn Reese026d29f2002-01-19 15:40:18 +00004995/** @} End of UserDefined documentation module */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004996
4997/*************************************************************************
4998 *
Daniel Veillardb7c29c32002-09-25 22:44:43 +00004999 * LOCALES
5000 *
5001 ************************************************************************/
5002
5003/*************************************************************************
5004 * trio_locale_set_decimal_point
5005 *
5006 * Decimal point can only be one character. The input argument is a
5007 * string to enable multibyte characters. At most MB_LEN_MAX characters
5008 * will be used.
5009 */
5010TRIO_PUBLIC void
5011trio_locale_set_decimal_point
5012TRIO_ARGS1((decimalPoint),
5013 char *decimalPoint)
5014{
5015#if defined(USE_LOCALE)
5016 if (NULL == internalLocaleValues)
5017 {
5018 TrioSetLocale();
5019 }
5020#endif
5021 internalDecimalPointLength = trio_length(decimalPoint);
5022 if (internalDecimalPointLength == 1)
5023 {
5024 internalDecimalPoint = *decimalPoint;
5025 }
5026 else
5027 {
5028 internalDecimalPoint = NIL;
5029 trio_copy_max(internalDecimalPointString,
5030 sizeof(internalDecimalPointString),
5031 decimalPoint);
5032 }
5033}
5034
5035/*************************************************************************
5036 * trio_locale_set_thousand_separator
5037 *
5038 * See trio_locale_set_decimal_point
5039 */
5040TRIO_PUBLIC void
5041trio_locale_set_thousand_separator
5042TRIO_ARGS1((thousandSeparator),
5043 char *thousandSeparator)
5044{
5045#if defined(USE_LOCALE)
5046 if (NULL == internalLocaleValues)
5047 {
5048 TrioSetLocale();
5049 }
5050#endif
5051 trio_copy_max(internalThousandSeparator,
5052 sizeof(internalThousandSeparator),
5053 thousandSeparator);
5054 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5055}
5056
5057/*************************************************************************
5058 * trio_locale_set_grouping
5059 *
5060 * Array of bytes. Reversed order.
5061 *
5062 * CHAR_MAX : No further grouping
5063 * 0 : Repeat last group for the remaining digits (not necessary
5064 * as C strings are zero-terminated)
5065 * n : Set current group to n
5066 *
5067 * Same order as the grouping attribute in LC_NUMERIC.
5068 */
5069TRIO_PUBLIC void
5070trio_locale_set_grouping
5071TRIO_ARGS1((grouping),
5072 char *grouping)
5073{
5074#if defined(USE_LOCALE)
5075 if (NULL == internalLocaleValues)
5076 {
5077 TrioSetLocale();
5078 }
5079#endif
5080 trio_copy_max(internalGrouping,
5081 sizeof(internalGrouping),
5082 grouping);
5083}
5084
5085
5086/*************************************************************************
5087 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00005088 * SCANNING
Bjorn Reese70a9da52001-04-21 16:57:29 +00005089 *
5090 ************************************************************************/
5091
Daniel Veillard92ad2102001-03-27 12:47:33 +00005092/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005093 * TrioSkipWhitespaces
Daniel Veillard92ad2102001-03-27 12:47:33 +00005094 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005095TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005096TrioSkipWhitespaces
5097TRIO_ARGS1((self),
5098 trio_class_t *self)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005099{
5100 int ch;
5101
5102 ch = self->current;
5103 while (isspace(ch))
5104 {
5105 self->InStream(self, &ch);
5106 }
5107 return ch;
5108}
5109
5110/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005111 * TrioGetCollation
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005112 */
5113#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +00005114TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005115TrioGetCollation(TRIO_NOARGS)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005116{
5117 int i;
5118 int j;
5119 int k;
5120 char first[2];
5121 char second[2];
5122
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005123 /* This is computationally expensive */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005124 first[1] = NIL;
5125 second[1] = NIL;
5126 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5127 {
5128 k = 0;
5129 first[0] = (char)i;
5130 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5131 {
5132 second[0] = (char)j;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005133 if (trio_equal_locale(first, second))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005134 internalCollationArray[i][k++] = (char)j;
5135 }
5136 internalCollationArray[i][k] = NIL;
5137 }
5138}
5139#endif
5140
5141/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005142 * TrioGetCharacterClass
Daniel Veillard92ad2102001-03-27 12:47:33 +00005143 *
5144 * FIXME:
5145 * multibyte
5146 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005147TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005148TrioGetCharacterClass
5149TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5150 TRIO_CONST char *format,
5151 int *indexPointer,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005152 trio_flags_t *flagsPointer,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005153 int *characterclass)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005154{
5155 int index = *indexPointer;
5156 int i;
5157 char ch;
5158 char range_begin;
5159 char range_end;
5160
5161 *flagsPointer &= ~FLAGS_EXCLUDE;
5162
5163 if (format[index] == QUALIFIER_CIRCUMFLEX)
5164 {
5165 *flagsPointer |= FLAGS_EXCLUDE;
5166 index++;
5167 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005168 /*
5169 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005170 * it will be part of the class, and a second ungroup character
5171 * must follow to end the group.
5172 */
5173 if (format[index] == SPECIFIER_UNGROUP)
5174 {
5175 characterclass[(int)SPECIFIER_UNGROUP]++;
5176 index++;
5177 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005178 /*
5179 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005180 * it must be at the beginning of the list
5181 */
5182 if (format[index] == QUALIFIER_MINUS)
5183 {
5184 characterclass[(int)QUALIFIER_MINUS]++;
5185 index++;
5186 }
5187 /* Collect characters */
5188 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005189 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005190 ch = format[++index])
5191 {
5192 switch (ch)
5193 {
5194 case QUALIFIER_MINUS: /* Scanlist ranges */
5195
Bjorn Reese70a9da52001-04-21 16:57:29 +00005196 /*
5197 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00005198 * defined.
5199 *
5200 * We support the following behaviour (although this may
5201 * change as we become wiser)
5202 * - only increasing ranges, ie. [a-b] but not [b-a]
5203 * - transitive ranges, ie. [a-b-c] == [a-c]
5204 * - trailing minus, ie. [a-] is interpreted as an 'a'
5205 * and a '-'
5206 * - duplicates (although we can easily convert these
5207 * into errors)
5208 */
5209 range_begin = format[index - 1];
5210 range_end = format[++index];
5211 if (range_end == SPECIFIER_UNGROUP)
5212 {
5213 /* Trailing minus is included */
5214 characterclass[(int)ch]++;
5215 ch = range_end;
5216 break; /* for */
5217 }
5218 if (range_end == NIL)
5219 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5220 if (range_begin > range_end)
5221 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5222
5223 for (i = (int)range_begin; i <= (int)range_end; i++)
5224 characterclass[i]++;
5225
5226 ch = range_end;
5227 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005228
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005229#if TRIO_EXTENSION
5230
5231 case SPECIFIER_GROUP:
5232
5233 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005234 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005235 case QUALIFIER_DOT: /* Collating symbol */
5236 /*
5237 * FIXME: This will be easier to implement when multibyte
5238 * characters have been implemented. Until now, we ignore
5239 * this feature.
5240 */
5241 for (i = index + 2; ; i++)
5242 {
5243 if (format[i] == NIL)
5244 /* Error in syntax */
5245 return -1;
5246 else if (format[i] == QUALIFIER_DOT)
5247 break; /* for */
5248 }
5249 if (format[++i] != SPECIFIER_UNGROUP)
5250 return -1;
5251
5252 index = i;
5253 break;
5254
5255 case QUALIFIER_EQUAL: /* Equivalence class expressions */
5256 {
5257 unsigned int j;
5258 unsigned int k;
5259
5260 if (internalCollationUnconverted)
5261 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005262 /* Lazy evaluation of collation array */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005263 TrioGetCollation();
5264 internalCollationUnconverted = FALSE;
5265 }
5266 for (i = index + 2; ; i++)
5267 {
5268 if (format[i] == NIL)
5269 /* Error in syntax */
5270 return -1;
5271 else if (format[i] == QUALIFIER_EQUAL)
5272 break; /* for */
5273 else
5274 {
5275 /* Mark any equivalent character */
5276 k = (unsigned int)format[i];
5277 for (j = 0; internalCollationArray[k][j] != NIL; j++)
5278 characterclass[(int)internalCollationArray[k][j]]++;
5279 }
5280 }
5281 if (format[++i] != SPECIFIER_UNGROUP)
5282 return -1;
5283
5284 index = i;
5285 }
5286 break;
5287
5288 case QUALIFIER_COLON: /* Character class expressions */
5289
Bjorn Reese026d29f2002-01-19 15:40:18 +00005290 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5291 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005292 {
5293 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5294 if (isalnum(i))
5295 characterclass[i]++;
5296 index += sizeof(CLASS_ALNUM) - 1;
5297 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005298 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5299 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005300 {
5301 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5302 if (isalpha(i))
5303 characterclass[i]++;
5304 index += sizeof(CLASS_ALPHA) - 1;
5305 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005306 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5307 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005308 {
5309 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5310 if (iscntrl(i))
5311 characterclass[i]++;
5312 index += sizeof(CLASS_CNTRL) - 1;
5313 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005314 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5315 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005316 {
5317 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5318 if (isdigit(i))
5319 characterclass[i]++;
5320 index += sizeof(CLASS_DIGIT) - 1;
5321 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005322 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5323 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005324 {
5325 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5326 if (isgraph(i))
5327 characterclass[i]++;
5328 index += sizeof(CLASS_GRAPH) - 1;
5329 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005330 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5331 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005332 {
5333 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5334 if (islower(i))
5335 characterclass[i]++;
5336 index += sizeof(CLASS_LOWER) - 1;
5337 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005338 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5339 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005340 {
5341 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5342 if (isprint(i))
5343 characterclass[i]++;
5344 index += sizeof(CLASS_PRINT) - 1;
5345 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005346 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5347 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005348 {
5349 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5350 if (ispunct(i))
5351 characterclass[i]++;
5352 index += sizeof(CLASS_PUNCT) - 1;
5353 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005354 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5355 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005356 {
5357 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5358 if (isspace(i))
5359 characterclass[i]++;
5360 index += sizeof(CLASS_SPACE) - 1;
5361 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005362 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5363 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005364 {
5365 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5366 if (isupper(i))
5367 characterclass[i]++;
5368 index += sizeof(CLASS_UPPER) - 1;
5369 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005370 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5371 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005372 {
5373 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5374 if (isxdigit(i))
5375 characterclass[i]++;
5376 index += sizeof(CLASS_XDIGIT) - 1;
5377 }
5378 else
5379 {
5380 characterclass[(int)ch]++;
5381 }
5382 break;
5383
5384 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005385 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005386 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005387 }
5388 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005389
5390#endif /* TRIO_EXTENSION */
5391
Daniel Veillard92ad2102001-03-27 12:47:33 +00005392 default:
5393 characterclass[(int)ch]++;
5394 break;
5395 }
5396 }
5397 return 0;
5398}
5399
5400/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005401 * TrioReadNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00005402 *
5403 * We implement our own number conversion in preference of strtol and
5404 * strtoul, because we must handle 'long long' and thousand separators.
5405 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005406TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005407TrioReadNumber
5408TRIO_ARGS5((self, target, flags, width, base),
5409 trio_class_t *self,
5410 trio_uintmax_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005411 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005412 int width,
5413 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005414{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005415 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005416 int digit;
5417 int count;
5418 BOOLEAN_T isNegative = FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005419 BOOLEAN_T gotNumber = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005420 int j;
5421
5422 assert(VALID(self));
5423 assert(VALID(self->InStream));
5424 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5425
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005426 if (internalDigitsUnconverted)
5427 {
5428 /* Lazy evaluation of digits array */
5429 memset(internalDigitArray, -1, sizeof(internalDigitArray));
5430 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5431 {
5432 internalDigitArray[(int)internalDigitsLower[j]] = j;
5433 internalDigitArray[(int)internalDigitsUpper[j]] = j;
5434 }
5435 internalDigitsUnconverted = FALSE;
5436 }
5437
Daniel Veillard92ad2102001-03-27 12:47:33 +00005438 TrioSkipWhitespaces(self);
5439
5440 if (!(flags & FLAGS_UNSIGNED))
5441 {
5442 /* Leading sign */
5443 if (self->current == '+')
5444 {
5445 self->InStream(self, NULL);
5446 }
5447 else if (self->current == '-')
5448 {
5449 self->InStream(self, NULL);
5450 isNegative = TRUE;
5451 }
5452 }
5453
5454 count = self->processed;
5455
5456 if (flags & FLAGS_ALTERNATIVE)
5457 {
5458 switch (base)
5459 {
5460 case NO_BASE:
5461 case BASE_OCTAL:
5462 case BASE_HEX:
5463 case BASE_BINARY:
5464 if (self->current == '0')
5465 {
5466 self->InStream(self, NULL);
5467 if (self->current)
5468 {
5469 if ((base == BASE_HEX) &&
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005470 (trio_to_upper(self->current) == 'X'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005471 {
5472 self->InStream(self, NULL);
5473 }
5474 else if ((base == BASE_BINARY) &&
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005475 (trio_to_upper(self->current) == 'B'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005476 {
5477 self->InStream(self, NULL);
5478 }
5479 }
5480 }
5481 else
5482 return FALSE;
5483 break;
5484 default:
5485 break;
5486 }
5487 }
5488
5489 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5490 (! ((self->current == EOF) || isspace(self->current))))
5491 {
5492 if (isascii(self->current))
5493 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005494 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005495 /* Abort if digit is not allowed in the specified base */
5496 if ((digit == -1) || (digit >= base))
5497 break;
5498 }
5499 else if (flags & FLAGS_QUOTE)
5500 {
5501 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005502 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005503 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005504 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005505 break;
5506
5507 self->InStream(self, NULL);
5508 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005509 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00005510 break; /* Mismatch */
5511 else
5512 continue; /* Match */
5513 }
5514 else
5515 break;
5516
5517 number *= base;
5518 number += digit;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005519 gotNumber = TRUE; /* we need at least one digit */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005520
5521 self->InStream(self, NULL);
5522 }
5523
5524 /* Was anything read at all? */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005525 if (!gotNumber)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005526 return FALSE;
5527
5528 if (target)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005529 *target = (isNegative) ? -((trio_intmax_t)number) : number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005530 return TRUE;
5531}
5532
5533/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005534 * TrioReadChar
Daniel Veillard92ad2102001-03-27 12:47:33 +00005535 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005536TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005537TrioReadChar
5538TRIO_ARGS4((self, target, flags, width),
5539 trio_class_t *self,
5540 char *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005541 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005542 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005543{
5544 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005545 char ch;
5546 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005547
5548 assert(VALID(self));
5549 assert(VALID(self->InStream));
5550
5551 for (i = 0;
5552 (self->current != EOF) && (i < width);
5553 i++)
5554 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005555 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005556 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005557 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5558 {
5559 switch (self->current)
5560 {
5561 case '\\': ch = '\\'; break;
5562 case 'a': ch = '\007'; break;
5563 case 'b': ch = '\b'; break;
5564 case 'f': ch = '\f'; break;
5565 case 'n': ch = '\n'; break;
5566 case 'r': ch = '\r'; break;
5567 case 't': ch = '\t'; break;
5568 case 'v': ch = '\v'; break;
5569 default:
5570 if (isdigit(self->current))
5571 {
5572 /* Read octal number */
5573 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5574 return 0;
5575 ch = (char)number;
5576 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005577 else if (trio_to_upper(self->current) == 'X')
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005578 {
5579 /* Read hexadecimal number */
5580 self->InStream(self, NULL);
5581 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5582 return 0;
5583 ch = (char)number;
5584 }
5585 else
5586 {
5587 ch = (char)self->current;
5588 }
5589 break;
5590 }
5591 }
5592
5593 if (target)
5594 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005595 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005596 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005597}
5598
5599/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005600 * TrioReadString
Daniel Veillard92ad2102001-03-27 12:47:33 +00005601 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005602TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005603TrioReadString
5604TRIO_ARGS4((self, target, flags, width),
5605 trio_class_t *self,
5606 char *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005607 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005608 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005609{
5610 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005611
5612 assert(VALID(self));
5613 assert(VALID(self->InStream));
5614
5615 TrioSkipWhitespaces(self);
5616
Bjorn Reese70a9da52001-04-21 16:57:29 +00005617 /*
5618 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005619 * or width is exceeded
5620 */
5621 for (i = 0;
5622 ((width == NO_WIDTH) || (i < width)) &&
5623 (! ((self->current == EOF) || isspace(self->current)));
5624 i++)
5625 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005626 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005627 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005628 }
5629 if (target)
5630 target[i] = NIL;
5631 return TRUE;
5632}
5633
5634/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005635 * TrioReadWideChar
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005636 */
5637#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005638TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005639TrioReadWideChar
5640TRIO_ARGS4((self, target, flags, width),
5641 trio_class_t *self,
5642 trio_wchar_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005643 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005644 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005645{
5646 int i;
5647 int j;
5648 int size;
5649 int amount = 0;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005650 trio_wchar_t wch;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005651 char buffer[MB_LEN_MAX + 1];
5652
5653 assert(VALID(self));
5654 assert(VALID(self->InStream));
5655
5656 for (i = 0;
5657 (self->current != EOF) && (i < width);
5658 i++)
5659 {
5660 if (isascii(self->current))
5661 {
5662 if (TrioReadChar(self, buffer, flags, 1) == 0)
5663 return 0;
5664 buffer[1] = NIL;
5665 }
5666 else
5667 {
5668 /*
5669 * Collect a multibyte character, by enlarging buffer until
5670 * it contains a fully legal multibyte character, or the
5671 * buffer is full.
5672 */
5673 j = 0;
5674 do
5675 {
5676 buffer[j++] = (char)self->current;
5677 buffer[j] = NIL;
5678 self->InStream(self, NULL);
5679 }
5680 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5681 }
5682 if (target)
5683 {
5684 size = mbtowc(&wch, buffer, sizeof(buffer));
5685 if (size > 0)
5686 target[i] = wch;
5687 }
5688 amount += size;
5689 self->InStream(self, NULL);
5690 }
5691 return amount;
5692}
5693#endif /* TRIO_WIDECHAR */
5694
5695/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005696 * TrioReadWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005697 */
5698#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00005699TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005700TrioReadWideString
5701TRIO_ARGS4((self, target, flags, width),
5702 trio_class_t *self,
5703 trio_wchar_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005704 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005705 int width)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005706{
5707 int i;
5708 int size;
5709
5710 assert(VALID(self));
5711 assert(VALID(self->InStream));
5712
5713 TrioSkipWhitespaces(self);
5714
5715#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005716 (void)mblen(NULL, 0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005717#endif
5718
5719 /*
5720 * Continue until end of string is reached, a whitespace is encountered,
5721 * or width is exceeded
5722 */
5723 for (i = 0;
5724 ((width == NO_WIDTH) || (i < width)) &&
5725 (! ((self->current == EOF) || isspace(self->current)));
5726 )
5727 {
5728 size = TrioReadWideChar(self, &target[i], flags, 1);
5729 if (size == 0)
5730 break; /* for */
5731
5732 i += size;
5733 }
5734 if (target)
Bjorn Reese026d29f2002-01-19 15:40:18 +00005735 target[i] = WCONST('\0');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005736 return TRUE;
5737}
5738#endif /* TRIO_WIDECHAR */
5739
5740/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005741 * TrioReadGroup
Daniel Veillard92ad2102001-03-27 12:47:33 +00005742 *
5743 * FIXME: characterclass does not work with multibyte characters
5744 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005745TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005746TrioReadGroup
5747TRIO_ARGS5((self, target, characterclass, flags, width),
5748 trio_class_t *self,
5749 char *target,
5750 int *characterclass,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005751 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005752 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005753{
Bjorn Reese70a9da52001-04-21 16:57:29 +00005754 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005755 int i;
5756
5757 assert(VALID(self));
5758 assert(VALID(self->InStream));
5759
5760 ch = self->current;
5761 for (i = 0;
5762 ((width == NO_WIDTH) || (i < width)) &&
5763 (! ((ch == EOF) ||
5764 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5765 i++)
5766 {
5767 if (target)
5768 target[i] = (char)ch;
5769 self->InStream(self, &ch);
5770 }
5771
5772 if (target)
5773 target[i] = NIL;
5774 return TRUE;
5775}
5776
5777/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005778 * TrioReadDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +00005779 *
5780 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00005781 * add long double
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005782 * handle base
Daniel Veillard92ad2102001-03-27 12:47:33 +00005783 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005784TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005785TrioReadDouble
5786TRIO_ARGS4((self, target, flags, width),
5787 trio_class_t *self,
5788 trio_pointer_t target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005789 trio_flags_t flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005790 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005791{
5792 int ch;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005793 char doubleString[512];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005794 int index = 0;
5795 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005796 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005797 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005798
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005799 doubleString[0] = 0;
5800
Bjorn Reese70a9da52001-04-21 16:57:29 +00005801 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005802 width = sizeof(doubleString) - 1;
5803
5804 TrioSkipWhitespaces(self);
5805
Bjorn Reese70a9da52001-04-21 16:57:29 +00005806 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +00005807 * Read entire double number from stream. trio_to_double requires
5808 * a string as input, but InStream can be anything, so we have to
Daniel Veillard92ad2102001-03-27 12:47:33 +00005809 * collect all characters.
5810 */
5811 ch = self->current;
5812 if ((ch == '+') || (ch == '-'))
5813 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005814 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005815 self->InStream(self, &ch);
5816 width--;
5817 }
5818
5819 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005820 switch (ch)
5821 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00005822 case 'n':
5823 case 'N':
5824 /* Not-a-number */
5825 if (index != 0)
5826 break;
5827 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005828 case 'i':
5829 case 'I':
5830 /* Infinity */
5831 while (isalpha(ch) && (index - start < width))
5832 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005833 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005834 self->InStream(self, &ch);
5835 }
5836 doubleString[index] = NIL;
5837
Daniel Veillard92ad2102001-03-27 12:47:33 +00005838 /* Case insensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005839 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5840 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005841 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005842 if (flags & FLAGS_LONGDOUBLE)
5843 {
5844 if ((start == 1) && (doubleString[0] == '-'))
5845 {
5846 *((trio_long_double_t *)target) = trio_ninf();
5847 }
5848 else
5849 {
5850 *((trio_long_double_t *)target) = trio_pinf();
5851 }
5852 }
5853 else
5854 {
5855 if ((start == 1) && (doubleString[0] == '-'))
5856 {
5857 *((double *)target) = trio_ninf();
5858 }
5859 else
5860 {
5861 *((double *)target) = trio_pinf();
5862 }
5863 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005864 return TRUE;
5865 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005866 if (trio_equal(doubleString, NAN_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005867 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005868 /* NaN must not have a preceeding + nor - */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005869 if (flags & FLAGS_LONGDOUBLE)
5870 {
5871 *((trio_long_double_t *)target) = trio_nan();
5872 }
5873 else
5874 {
5875 *((double *)target) = trio_nan();
5876 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005877 return TRUE;
5878 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005879 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005880
5881 case '0':
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005882 doubleString[index++] = (char)ch;
5883 self->InStream(self, &ch);
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005884 if (trio_to_upper(ch) == 'X')
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005885 {
5886 isHex = TRUE;
5887 doubleString[index++] = (char)ch;
5888 self->InStream(self, &ch);
5889 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005890 break;
5891
5892 default:
5893 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005894 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005895
Bjorn Reese70a9da52001-04-21 16:57:29 +00005896 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005897 {
5898 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005899 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00005900 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005901 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005902 self->InStream(self, &ch);
5903 }
5904 else if (flags & FLAGS_QUOTE)
5905 {
5906 /* Compare with thousands separator */
5907 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5908 {
5909 if (internalThousandSeparator[j] != self->current)
5910 break;
5911
5912 self->InStream(self, &ch);
5913 }
5914 if (internalThousandSeparator[j])
5915 break; /* Mismatch */
5916 else
5917 continue; /* Match */
5918 }
5919 else
5920 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005921 }
5922 if (ch == '.')
5923 {
5924 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005925 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005926 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005927 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5928 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005929 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005930 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005931 self->InStream(self, &ch);
5932 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005933 if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005934 {
5935 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005936 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005937 self->InStream(self, &ch);
5938 if ((ch == '+') || (ch == '-'))
5939 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005940 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005941 self->InStream(self, &ch);
5942 }
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005943 while (isdigit(ch) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005944 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005945 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005946 self->InStream(self, &ch);
5947 }
5948 }
5949 }
5950
5951 if ((index == start) || (*doubleString == NIL))
5952 return FALSE;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005953
5954 doubleString[index] = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005955
5956 if (flags & FLAGS_LONGDOUBLE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005957 {
5958 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5959 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005960 else
5961 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005962 *((double *)target) = trio_to_double(doubleString, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005963 }
5964 return TRUE;
5965}
5966
5967/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005968 * TrioReadPointer
Daniel Veillard92ad2102001-03-27 12:47:33 +00005969 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005970TRIO_PRIVATE BOOLEAN_T
Daniel Veillardb7c29c32002-09-25 22:44:43 +00005971TrioReadPointer
5972TRIO_ARGS3((self, target, flags),
5973 trio_class_t *self,
5974 trio_pointer_t *target,
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00005975 trio_flags_t flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005976{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005977 trio_uintmax_t number;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005978 char buffer[sizeof(internalNullString)];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005979
5980 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5981
5982 if (TrioReadNumber(self,
5983 &number,
5984 flags,
5985 POINTER_WIDTH,
5986 BASE_HEX))
5987 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005988 /*
5989 * The strange assignment of number is a workaround for a compiler
5990 * warning
5991 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005992 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005993 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005994 return TRUE;
5995 }
5996 else if (TrioReadString(self,
5997 (flags & FLAGS_IGNORE)
5998 ? NULL
5999 : buffer,
6000 0,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006001 sizeof(internalNullString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00006002 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00006003 if (trio_equal_case(buffer, internalNullString))
Daniel Veillard92ad2102001-03-27 12:47:33 +00006004 {
6005 if (target)
6006 *target = NULL;
6007 return TRUE;
6008 }
6009 }
6010 return FALSE;
6011}
6012
6013/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006014 * TrioScanProcess
Daniel Veillard92ad2102001-03-27 12:47:33 +00006015 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006016TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006017TrioScanProcess
6018TRIO_ARGS3((data, format, parameters),
6019 trio_class_t *data,
6020 TRIO_CONST char *format,
6021 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006022{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006023#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006024 int charlen;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006025 int cnt;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006026#endif
6027 int assignment;
6028 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006029 int index; /* Index of format string */
6030 int i; /* Index of current parameter */
Daniel Veillarda48ed3d2003-04-03 15:28:28 +00006031 trio_flags_t flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006032 int width;
6033 int base;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006034 trio_pointer_t pointer;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006035
Daniel Veillard92ad2102001-03-27 12:47:33 +00006036 assignment = 0;
6037 i = 0;
6038 index = 0;
6039 data->InStream(data, &ch);
6040
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006041#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006042 (void)mblen(NULL, 0);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006043#endif
6044
6045 while (format[index])
6046 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006047#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006048 if (! isascii(format[index]))
6049 {
6050 charlen = mblen(&format[index], MB_LEN_MAX);
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006051 if (charlen != -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006052 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006053 /* Compare multibyte characters in format string */
6054 for (cnt = 0; cnt < charlen - 1; cnt++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006055 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006056 if (ch != format[index + cnt])
6057 {
6058 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6059 }
6060 data->InStream(data, &ch);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006061 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006062 continue; /* while characters left in formatting string */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006063 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006064 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006065#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006066
6067 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6068 {
6069 return (assignment > 0) ? assignment : EOF;
6070 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006071
6072 if (CHAR_IDENTIFIER == format[index])
6073 {
6074 if (CHAR_IDENTIFIER == format[index + 1])
6075 {
6076 /* Two % in format matches one % in input stream */
6077 if (CHAR_IDENTIFIER == ch)
6078 {
6079 data->InStream(data, &ch);
6080 index += 2;
6081 continue; /* while format chars left */
6082 }
6083 else
6084 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6085 }
6086
6087 /* Skip the parameter entries */
6088 while (parameters[i].type == FORMAT_PARAMETER)
6089 i++;
6090
6091 flags = parameters[i].flags;
6092 /* Find width */
6093 width = parameters[i].width;
6094 if (flags & FLAGS_WIDTH_PARAMETER)
6095 {
6096 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006097 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006098 }
6099 /* Find base */
6100 base = parameters[i].base;
6101 if (flags & FLAGS_BASE_PARAMETER)
6102 {
6103 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00006104 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006105 }
6106
6107 switch (parameters[i].type)
6108 {
6109 case FORMAT_INT:
6110 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006111 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006112
6113 if (0 == base)
6114 base = BASE_DECIMAL;
6115
6116 if (!TrioReadNumber(data,
6117 &number,
6118 flags,
6119 width,
6120 base))
6121 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006122
Daniel Veillard92ad2102001-03-27 12:47:33 +00006123 if (!(flags & FLAGS_IGNORE))
6124 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006125 assignment++;
6126
Daniel Veillard92ad2102001-03-27 12:47:33 +00006127 pointer = parameters[i].data.pointer;
6128#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6129 if (flags & FLAGS_SIZE_T)
6130 *(size_t *)pointer = (size_t)number;
6131 else
6132#endif
6133#if defined(QUALIFIER_PTRDIFF_T)
6134 if (flags & FLAGS_PTRDIFF_T)
6135 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6136 else
6137#endif
6138#if defined(QUALIFIER_INTMAX_T)
6139 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006140 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006141 else
6142#endif
6143 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006144 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006145 else if (flags & FLAGS_LONG)
6146 *(long int *)pointer = (long int)number;
6147 else if (flags & FLAGS_SHORT)
6148 *(short int *)pointer = (short int)number;
6149 else
6150 *(int *)pointer = (int)number;
6151 }
6152 }
6153 break; /* FORMAT_INT */
6154
6155 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006156#if TRIO_WIDECHAR
6157 if (flags & FLAGS_WIDECHAR)
6158 {
6159 if (!TrioReadWideString(data,
6160 (flags & FLAGS_IGNORE)
6161 ? NULL
6162 : parameters[i].data.wstring,
6163 flags,
6164 width))
6165 return assignment;
6166 }
6167 else
6168#endif
6169 {
6170 if (!TrioReadString(data,
6171 (flags & FLAGS_IGNORE)
6172 ? NULL
6173 : parameters[i].data.string,
6174 flags,
6175 width))
6176 return assignment;
6177 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006178 if (!(flags & FLAGS_IGNORE))
6179 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006180 break; /* FORMAT_STRING */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006181
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006182 case FORMAT_DOUBLE:
6183 {
6184 trio_pointer_t pointer;
6185
6186 if (flags & FLAGS_IGNORE)
6187 {
6188 pointer = NULL;
6189 }
6190 else
6191 {
6192 pointer = (flags & FLAGS_LONGDOUBLE)
6193 ? (trio_pointer_t)parameters[i].data.longdoublePointer
6194 : (trio_pointer_t)parameters[i].data.doublePointer;
6195 }
6196 if (!TrioReadDouble(data, pointer, flags, width))
6197 {
6198 return assignment;
6199 }
6200 if (!(flags & FLAGS_IGNORE))
6201 {
6202 assignment++;
6203 }
6204 break; /* FORMAT_DOUBLE */
6205 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006206 case FORMAT_GROUP:
6207 {
6208 int characterclass[MAX_CHARACTER_CLASS + 1];
6209 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006210
6211 /* Skip over modifiers */
6212 while (format[index] != SPECIFIER_GROUP)
6213 {
6214 index++;
6215 }
6216 /* Skip over group specifier */
6217 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006218
Daniel Veillard92ad2102001-03-27 12:47:33 +00006219 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006220 rc = TrioGetCharacterClass(format,
6221 &index,
6222 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006223 characterclass);
6224 if (rc < 0)
6225 return rc;
6226
6227 if (!TrioReadGroup(data,
6228 (flags & FLAGS_IGNORE)
6229 ? NULL
6230 : parameters[i].data.string,
6231 characterclass,
6232 flags,
6233 parameters[i].width))
6234 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006235 if (!(flags & FLAGS_IGNORE))
6236 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006237 }
6238 break; /* FORMAT_GROUP */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006239
Daniel Veillard92ad2102001-03-27 12:47:33 +00006240 case FORMAT_COUNT:
6241 pointer = parameters[i].data.pointer;
6242 if (NULL != pointer)
6243 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006244 int count = data->committed;
6245 if (ch != EOF)
6246 count--; /* a character is read, but is not consumed yet */
Daniel Veillard92ad2102001-03-27 12:47:33 +00006247#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6248 if (flags & FLAGS_SIZE_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006249 *(size_t *)pointer = (size_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006250 else
6251#endif
6252#if defined(QUALIFIER_PTRDIFF_T)
6253 if (flags & FLAGS_PTRDIFF_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006254 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006255 else
6256#endif
6257#if defined(QUALIFIER_INTMAX_T)
6258 if (flags & FLAGS_INTMAX_T)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006259 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006260 else
6261#endif
6262 if (flags & FLAGS_QUAD)
6263 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006264 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006265 }
6266 else if (flags & FLAGS_LONG)
6267 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006268 *(long int *)pointer = (long int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006269 }
6270 else if (flags & FLAGS_SHORT)
6271 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006272 *(short int *)pointer = (short int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006273 }
6274 else
6275 {
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006276 *(int *)pointer = (int)count;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006277 }
6278 }
6279 break; /* FORMAT_COUNT */
6280
6281 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006282#if TRIO_WIDECHAR
6283 if (flags & FLAGS_WIDECHAR)
6284 {
6285 if (TrioReadWideChar(data,
6286 (flags & FLAGS_IGNORE)
6287 ? NULL
6288 : parameters[i].data.wstring,
6289 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006290 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006291 return assignment;
6292 }
6293 else
6294#endif
6295 {
6296 if (TrioReadChar(data,
6297 (flags & FLAGS_IGNORE)
6298 ? NULL
6299 : parameters[i].data.string,
6300 flags,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006301 (width == NO_WIDTH) ? 1 : width) == 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006302 return assignment;
6303 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006304 if (!(flags & FLAGS_IGNORE))
6305 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006306 break; /* FORMAT_CHAR */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006307
Daniel Veillard92ad2102001-03-27 12:47:33 +00006308 case FORMAT_POINTER:
6309 if (!TrioReadPointer(data,
6310 (flags & FLAGS_IGNORE)
6311 ? NULL
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006312 : (trio_pointer_t *)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00006313 flags))
6314 return assignment;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006315 if (!(flags & FLAGS_IGNORE))
6316 assignment++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006317 break; /* FORMAT_POINTER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006318
Daniel Veillard92ad2102001-03-27 12:47:33 +00006319 case FORMAT_PARAMETER:
6320 break; /* FORMAT_PARAMETER */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006321
Daniel Veillard92ad2102001-03-27 12:47:33 +00006322 default:
6323 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6324 }
6325 ch = data->current;
6326 index = parameters[i].indexAfterSpecifier;
6327 i++;
6328 }
6329 else /* Not an % identifier */
6330 {
6331 if (isspace((int)format[index]))
6332 {
6333 /* Whitespaces may match any amount of whitespaces */
6334 ch = TrioSkipWhitespaces(data);
6335 }
6336 else if (ch == format[index])
6337 {
6338 data->InStream(data, &ch);
6339 }
6340 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00006341 return assignment;
Daniel Veillard92ad2102001-03-27 12:47:33 +00006342
6343 index++;
6344 }
6345 }
6346 return assignment;
6347}
6348
6349/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006350 * TrioScan
Daniel Veillard92ad2102001-03-27 12:47:33 +00006351 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006352TRIO_PRIVATE int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006353TrioScan
6354TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6355 trio_pointer_t source,
6356 size_t sourceSize,
6357 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6358 TRIO_CONST char *format,
6359 va_list *arglist,
6360 trio_pointer_t *argarray)
Bjorn Reese026d29f2002-01-19 15:40:18 +00006361{
6362 int status;
6363 trio_parameter_t parameters[MAX_PARAMETERS];
6364 trio_class_t data;
6365
6366 assert(VALID(InStream));
6367 assert(VALID(format));
6368
6369 memset(&data, 0, sizeof(data));
6370 data.InStream = InStream;
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006371 data.location = (trio_pointer_t)source;
Bjorn Reese026d29f2002-01-19 15:40:18 +00006372 data.max = sourceSize;
6373 data.error = 0;
6374
6375#if defined(USE_LOCALE)
6376 if (NULL == internalLocaleValues)
6377 {
6378 TrioSetLocale();
6379 }
6380#endif
6381
6382 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6383 if (status < 0)
6384 return status;
6385
6386 status = TrioScanProcess(&data, format, parameters);
6387 if (data.error != 0)
6388 {
6389 status = data.error;
6390 }
6391 return status;
6392}
6393
6394/*************************************************************************
6395 * TrioInStreamFile
6396 */
6397TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006398TrioInStreamFile
6399TRIO_ARGS2((self, intPointer),
6400 trio_class_t *self,
6401 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006402{
6403 FILE *file = (FILE *)self->location;
6404
6405 assert(VALID(self));
6406 assert(VALID(file));
6407
6408 self->current = fgetc(file);
Bjorn Reese026d29f2002-01-19 15:40:18 +00006409 if (self->current == EOF)
6410 {
6411 self->error = (ferror(file))
6412 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6413 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
6414 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006415 else
6416 {
6417 self->processed++;
6418 self->committed++;
6419 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006420
6421 if (VALID(intPointer))
6422 {
6423 *intPointer = self->current;
6424 }
6425}
6426
6427/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006428 * TrioInStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00006429 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006430TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006431TrioInStreamFileDescriptor
6432TRIO_ARGS2((self, intPointer),
6433 trio_class_t *self,
6434 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006435{
6436 int fd = *((int *)self->location);
6437 int size;
6438 unsigned char input;
6439
6440 assert(VALID(self));
6441
6442 size = read(fd, &input, sizeof(char));
Bjorn Reese026d29f2002-01-19 15:40:18 +00006443 if (size == -1)
6444 {
6445 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6446 self->current = EOF;
6447 }
6448 else
6449 {
6450 self->current = (size == 0) ? EOF : input;
6451 }
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006452 if (self->current != EOF)
6453 {
6454 self->committed++;
6455 self->processed++;
6456 }
6457
6458 if (VALID(intPointer))
6459 {
6460 *intPointer = self->current;
6461 }
6462}
6463
6464/*************************************************************************
6465 * TrioInStreamCustom
6466 */
6467TRIO_PRIVATE void
6468TrioInStreamCustom
6469TRIO_ARGS2((self, intPointer),
6470 trio_class_t *self,
6471 int *intPointer)
6472{
6473 trio_custom_t *data;
6474
6475 assert(VALID(self));
6476 assert(VALID(self->location));
6477
6478 data = (trio_custom_t *)self->location;
6479
6480 self->current = (data->stream.in == NULL)
6481 ? NIL
6482 : (data->stream.in)(data->closure);
6483
6484 if (self->current == NIL)
6485 {
6486 self->current = EOF;
6487 }
6488 else
6489 {
6490 self->processed++;
6491 self->committed++;
6492 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006493
6494 if (VALID(intPointer))
6495 {
6496 *intPointer = self->current;
6497 }
6498}
6499
6500/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006501 * TrioInStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00006502 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006503TRIO_PRIVATE void
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006504TrioInStreamString
6505TRIO_ARGS2((self, intPointer),
6506 trio_class_t *self,
6507 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006508{
6509 unsigned char **buffer;
6510
6511 assert(VALID(self));
Daniel Veillard92ad2102001-03-27 12:47:33 +00006512 assert(VALID(self->location));
6513
6514 buffer = (unsigned char **)self->location;
6515 self->current = (*buffer)[0];
6516 if (self->current == NIL)
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006517 {
6518 self->current = EOF;
6519 }
6520 else
6521 {
6522 (*buffer)++;
6523 self->processed++;
6524 self->committed++;
6525 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00006526
6527 if (VALID(intPointer))
6528 {
6529 *intPointer = self->current;
6530 }
6531}
6532
6533/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00006534 *
6535 * Formatted scanning functions
6536 *
6537 ************************************************************************/
6538
6539#if defined(TRIO_DOCUMENTATION)
6540# include "doc/doc_scanf.h"
6541#endif
6542/** @addtogroup Scanf
6543 @{
6544*/
6545
6546/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00006547 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00006548 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006549
6550/**
6551 Scan characters from standard input stream.
6552
6553 @param format Formatting string.
6554 @param ... Arguments.
6555 @return Number of scanned characters.
6556 */
6557TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006558trio_scanf
6559TRIO_VARGS2((format, va_alist),
6560 TRIO_CONST char *format,
6561 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006562{
6563 int status;
6564 va_list args;
6565
6566 assert(VALID(format));
6567
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006568 TRIO_VA_START(args, format);
6569 status = TrioScan((trio_pointer_t)stdin, 0,
6570 TrioInStreamFile,
6571 format, &args, NULL);
6572 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006573 return status;
6574}
6575
Bjorn Reese026d29f2002-01-19 15:40:18 +00006576TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006577trio_vscanf
6578TRIO_ARGS2((format, args),
6579 TRIO_CONST char *format,
6580 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006581{
6582 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006583
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006584 return TrioScan((trio_pointer_t)stdin, 0,
6585 TrioInStreamFile,
6586 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006587}
6588
Bjorn Reese026d29f2002-01-19 15:40:18 +00006589TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006590trio_scanfv
6591TRIO_ARGS2((format, args),
6592 TRIO_CONST char *format,
6593 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006594{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006595 assert(VALID(format));
6596
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006597 return TrioScan((trio_pointer_t)stdin, 0,
6598 TrioInStreamFile,
6599 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006600}
6601
6602/*************************************************************************
6603 * fscanf
6604 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006605TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006606trio_fscanf
6607TRIO_VARGS3((file, format, va_alist),
6608 FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006609 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006610 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006611{
6612 int status;
6613 va_list args;
6614
6615 assert(VALID(file));
6616 assert(VALID(format));
6617
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006618 TRIO_VA_START(args, format);
6619 status = TrioScan((trio_pointer_t)file, 0,
6620 TrioInStreamFile,
6621 format, &args, NULL);
6622 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006623 return status;
6624}
6625
Bjorn Reese026d29f2002-01-19 15:40:18 +00006626TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006627trio_vfscanf
6628TRIO_ARGS3((file, format, args),
6629 FILE *file,
6630 TRIO_CONST char *format,
6631 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006632{
6633 assert(VALID(file));
6634 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006635
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006636 return TrioScan((trio_pointer_t)file, 0,
6637 TrioInStreamFile,
6638 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006639}
6640
Bjorn Reese026d29f2002-01-19 15:40:18 +00006641TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006642trio_fscanfv
6643TRIO_ARGS3((file, format, args),
6644 FILE *file,
6645 TRIO_CONST char *format,
6646 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006647{
6648 assert(VALID(file));
6649 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006650
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006651 return TrioScan((trio_pointer_t)file, 0,
6652 TrioInStreamFile,
6653 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006654}
6655
6656/*************************************************************************
6657 * dscanf
6658 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006659TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006660trio_dscanf
6661TRIO_VARGS3((fd, format, va_alist),
6662 int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006663 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006664 TRIO_VA_DECL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006665{
6666 int status;
6667 va_list args;
6668
6669 assert(VALID(format));
6670
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006671 TRIO_VA_START(args, format);
6672 status = TrioScan((trio_pointer_t)&fd, 0,
6673 TrioInStreamFileDescriptor,
6674 format, &args, NULL);
6675 TRIO_VA_END(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006676 return status;
6677}
6678
Bjorn Reese026d29f2002-01-19 15:40:18 +00006679TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006680trio_vdscanf
6681TRIO_ARGS3((fd, format, args),
6682 int fd,
6683 TRIO_CONST char *format,
6684 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006685{
6686 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006687
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006688 return TrioScan((trio_pointer_t)&fd, 0,
6689 TrioInStreamFileDescriptor,
6690 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006691}
6692
Bjorn Reese026d29f2002-01-19 15:40:18 +00006693TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006694trio_dscanfv
6695TRIO_ARGS3((fd, format, args),
6696 int fd,
6697 TRIO_CONST char *format,
6698 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006699{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006700 assert(VALID(format));
6701
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006702 return TrioScan((trio_pointer_t)&fd, 0,
6703 TrioInStreamFileDescriptor,
6704 format, NULL, args);
6705}
6706
6707/*************************************************************************
6708 * cscanf
6709 */
6710TRIO_PUBLIC int
6711trio_cscanf
6712TRIO_VARGS4((stream, closure, format, va_alist),
6713 trio_instream_t stream,
6714 trio_pointer_t closure,
6715 TRIO_CONST char *format,
6716 TRIO_VA_DECL)
6717{
6718 int status;
6719 va_list args;
6720 trio_custom_t data;
6721
6722 assert(VALID(stream));
6723 assert(VALID(format));
6724
6725 TRIO_VA_START(args, format);
6726 data.stream.in = stream;
6727 data.closure = closure;
6728 status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6729 TRIO_VA_END(args);
6730 return status;
6731}
6732
6733TRIO_PUBLIC int
6734trio_vcscanf
6735TRIO_ARGS4((stream, closure, format, args),
6736 trio_instream_t stream,
6737 trio_pointer_t closure,
6738 TRIO_CONST char *format,
6739 va_list args)
6740{
6741 trio_custom_t data;
6742
6743 assert(VALID(stream));
6744 assert(VALID(format));
6745
6746 data.stream.in = stream;
6747 data.closure = closure;
6748 return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6749}
6750
6751TRIO_PUBLIC int
6752trio_cscanfv
6753TRIO_ARGS4((stream, closure, format, args),
6754 trio_instream_t stream,
6755 trio_pointer_t closure,
6756 TRIO_CONST char *format,
6757 trio_pointer_t *args)
6758{
6759 trio_custom_t data;
6760
6761 assert(VALID(stream));
6762 assert(VALID(format));
6763
6764 data.stream.in = stream;
6765 data.closure = closure;
6766 return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006767}
6768
6769/*************************************************************************
6770 * sscanf
6771 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00006772TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006773trio_sscanf
6774TRIO_VARGS3((buffer, format, va_alist),
6775 TRIO_CONST char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00006776 TRIO_CONST char *format,
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006777 TRIO_VA_DECL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00006778{
6779 int status;
6780 va_list args;
6781
6782 assert(VALID(buffer));
6783 assert(VALID(format));
6784
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006785 TRIO_VA_START(args, format);
6786 status = TrioScan((trio_pointer_t)&buffer, 0,
6787 TrioInStreamString,
6788 format, &args, NULL);
6789 TRIO_VA_END(args);
Daniel Veillard92ad2102001-03-27 12:47:33 +00006790 return status;
6791}
6792
Bjorn Reese026d29f2002-01-19 15:40:18 +00006793TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006794trio_vsscanf
6795TRIO_ARGS3((buffer, format, args),
6796 TRIO_CONST char *buffer,
6797 TRIO_CONST char *format,
6798 va_list args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006799{
6800 assert(VALID(buffer));
6801 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006802
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006803 return TrioScan((trio_pointer_t)&buffer, 0,
6804 TrioInStreamString,
6805 format, &args, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006806}
6807
Bjorn Reese026d29f2002-01-19 15:40:18 +00006808TRIO_PUBLIC int
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006809trio_sscanfv
6810TRIO_ARGS3((buffer, format, args),
6811 TRIO_CONST char *buffer,
6812 TRIO_CONST char *format,
6813 trio_pointer_t *args)
Bjorn Reese70a9da52001-04-21 16:57:29 +00006814{
6815 assert(VALID(buffer));
6816 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00006817
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006818 return TrioScan((trio_pointer_t)&buffer, 0,
6819 TrioInStreamString,
6820 format, NULL, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00006821}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00006822
Bjorn Reese026d29f2002-01-19 15:40:18 +00006823/** @} End of Scanf documentation module */
Daniel Veillardb7c29c32002-09-25 22:44:43 +00006824
6825/*************************************************************************
6826 * trio_strerror
6827 */
6828TRIO_PUBLIC TRIO_CONST char *
6829trio_strerror
6830TRIO_ARGS1((errorcode),
6831 int errorcode)
6832{
6833 /* Textual versions of the error codes */
6834 switch (TRIO_ERROR_CODE(errorcode))
6835 {
6836 case TRIO_EOF:
6837 return "End of file";
6838 case TRIO_EINVAL:
6839 return "Invalid argument";
6840 case TRIO_ETOOMANY:
6841 return "Too many arguments";
6842 case TRIO_EDBLREF:
6843 return "Double reference";
6844 case TRIO_EGAP:
6845 return "Reference gap";
6846 case TRIO_ENOMEM:
6847 return "Out of memory";
6848 case TRIO_ERANGE:
6849 return "Invalid range";
6850 case TRIO_ECUSTOM:
6851 return "Custom error";
6852 default:
6853 return "Unknown";
6854 }
6855}