blob: 1a844bcda30fb104b7be8e540f0c8445f81c5c07 [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 %#[] ?
Bjorn Reese70a9da52001-04-21 16:57:29 +000031 * - C99 support has not been properly tested.
Daniel Veillard92ad2102001-03-27 12:47:33 +000032 * - Multibyte characters (done for format parsing, except scan groups)
Daniel Veillard92ad2102001-03-27 12:47:33 +000033 * - Complex numbers? (C99 _Complex)
34 * - Boolean values? (C99 _Bool)
35 * - C99 NaN(n-char-sequence) missing
36 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
37 * for %a, because C99 used %a for other purposes. If specified as
38 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
39 * the C99 hex-float. This means that you cannot scan %as as a hex-float
40 * immediately followed by an 's'.
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 Reese026d29f2002-01-19 15:40:18 +000050#include "triostr.h"
Bjorn Reese45029602001-08-21 09:23:53 +000051#include "trionan.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000052
Bjorn Reese70a9da52001-04-21 16:57:29 +000053/*
54 * Encode the error code and the position. This is decoded
Daniel Veillard92ad2102001-03-27 12:47:33 +000055 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
56 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +000057#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +000058# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
59#else
60# define TRIO_ERROR_RETURN(x,y) (-1)
61#endif
62
Bjorn Reese906ec8a2001-06-05 12:46:33 +000063#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
64# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
65# if !defined(MB_LEN_MAX)
66# define MB_LEN_MAX 6
67# endif
68#endif
69
70
71/*************************************************************************
72 * Generic definitions
73 */
74
75#if !(defined(DEBUG) || defined(NDEBUG))
76# define NDEBUG
77#endif
78#include <assert.h>
79#include <ctype.h>
80#if !defined(TRIO_COMPILER_SUPPORTS_C99)
81# define isblank(x) (((x)==32) || ((x)==9))
82#endif
83#include <math.h>
84#include <limits.h>
85#include <float.h>
86#include <stdarg.h>
87#include <stddef.h>
88#include <errno.h>
89
90#ifndef NULL
91# define NULL 0
92#endif
93#define NIL ((char)0)
94#ifndef FALSE
95# define FALSE (1 == 0)
96# define TRUE (! FALSE)
97#endif
98#define BOOLEAN_T int
99
100/* mincore() can be used for debugging purposes */
101#define VALID(x) (NULL != (x))
102
103/* xlC crashes on log10(0) */
Bjorn Reese45029602001-08-21 09:23:53 +0000104#define guarded_log10(x) (((x) == 0.0) ? trio_ninf() : log10(x))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000105#define guarded_log16(x) (guarded_log10(x) / log10(16.0))
106
107
108/*************************************************************************
109 * Platform specific definitions
110 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000111#if defined(TRIO_PLATFORM_UNIX)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000112# include <unistd.h>
113# include <signal.h>
114# include <locale.h>
115# define USE_LOCALE
Bjorn Reese026d29f2002-01-19 15:40:18 +0000116#endif /* TRIO_PLATFORM_UNIX */
117#if defined(TRIO_PLATFORM_VMS)
118# include <unistd.h>
119#endif
120#if defined(TRIO_PLATFORM_WIN32)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000121# include <io.h>
122# define read _read
123# define write _write
Bjorn Reese026d29f2002-01-19 15:40:18 +0000124#endif /* TRIO_PLATFORM_WIN32 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000125
Bjorn Reese45029602001-08-21 09:23:53 +0000126#define TRIO_MSVC_VERSION_5 1100
127
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000128#if TRIO_WIDECHAR
129# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
130# include <wchar.h>
131# include <wctype.h>
132# else
133typedef char wchar_t;
134typedef int wint_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000135# define WCONST(x) L ## x
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000136# define WEOF EOF
137# define iswalnum(x) isalnum(x)
138# define iswalpha(x) isalpha(x)
139# define iswblank(x) isblank(x)
140# define iswcntrl(x) iscntrl(x)
141# define iswdigit(x) isdigit(x)
142# define iswgraph(x) isgraph(x)
143# define iswlower(x) islower(x)
144# define iswprint(x) isprint(x)
145# define iswpunct(x) ispunct(x)
146# define iswspace(x) isspace(x)
147# define iswupper(x) isupper(x)
148# define iswxdigit(x) isxdigit(x)
149# endif
150#endif
151
152
153/*************************************************************************
154 * Compiler dependent definitions
155 */
156
157/* Support for long long */
158#ifndef __cplusplus
159# if !defined(USE_LONGLONG)
Bjorn Reese026d29f2002-01-19 15:40:18 +0000160# if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000161# define USE_LONGLONG
Bjorn Reese026d29f2002-01-19 15:40:18 +0000162# elif defined(TRIO_COMPILER_SUNPRO)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000163# define USE_LONGLONG
164# elif defined(_LONG_LONG) || defined(_LONGLONG)
165# define USE_LONGLONG
166# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000167# endif
168#endif
169
170/* The extra long numbers */
171#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000172typedef signed long long int trio_longlong_t;
173typedef unsigned long long int trio_ulonglong_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000174#elif defined(TRIO_COMPILER_MSVC)
Bjorn Reese45029602001-08-21 09:23:53 +0000175# if (_MSC_VER >= TRIO_MSVC_VERSION_5)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000176typedef signed __int64 trio_longlong_t;
177typedef unsigned __int64 trio_ulonglong_t;
178# else
179typedef signed long int trio_longlong_t;
180typedef unsigned long int trio_ulonglong_t;
181# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000182#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000183typedef signed long int trio_longlong_t;
184typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000185#endif
186
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000187/* Maximal and fixed integer types */
188#if defined(TRIO_COMPILER_SUPPORTS_C99)
189# include <stdint.h>
190typedef intmax_t trio_intmax_t;
191typedef uintmax_t trio_uintmax_t;
192typedef int8_t trio_int8_t;
193typedef int16_t trio_int16_t;
194typedef int32_t trio_int32_t;
195typedef int64_t trio_int64_t;
196#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
197# include <inttypes.h>
198typedef intmax_t trio_intmax_t;
199typedef uintmax_t trio_uintmax_t;
200typedef int8_t trio_int8_t;
201typedef int16_t trio_int16_t;
202typedef int32_t trio_int32_t;
203typedef int64_t trio_int64_t;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000204#elif defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= TRIO_MSVC_VERSION_5)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000205typedef trio_longlong_t trio_intmax_t;
206typedef trio_ulonglong_t trio_uintmax_t;
207typedef __int8 trio_int8_t;
208typedef __int16 trio_int16_t;
209typedef __int32 trio_int32_t;
210typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000211#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000212typedef trio_longlong_t trio_intmax_t;
213typedef trio_ulonglong_t trio_uintmax_t;
214# if defined(TRIO_INT8_T)
215typedef TRIO_INT8_T trio_int8_t;
216# else
217typedef signed char trio_int8_t;
218# endif
219# if defined(TRIO_INT16_T)
220typedef TRIO_INT16_T trio_int16_t;
221# else
222typedef signed short trio_int16_t;
223# endif
224# if defined(TRIO_INT32_T)
225typedef TRIO_INT32_T trio_int32_t;
226# else
227typedef signed int trio_int32_t;
228# endif
229# if defined(TRIO_INT64_T)
230typedef TRIO_INT64_T trio_int64_t;
231# else
232typedef trio_longlong_t trio_int64_t;
233# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000234#endif
235
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000236
237/*************************************************************************
238 * Internal definitions
239 */
240
241/* Long double sizes */
242#ifdef LDBL_DIG
243# define MAX_MANTISSA_DIGITS LDBL_DIG
244# define MAX_EXPONENT_DIGITS 4
245#else
246# define MAX_MANTISSA_DIGITS DBL_DIG
247# define MAX_EXPONENT_DIGITS 3
248#endif
249
250/* The maximal number of digits is for base 2 */
251#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000252/* The width of a pointer. The number of bits in a hex digit is 4 */
253#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
254
255/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000256#define INFINITE_LOWER "inf"
257#define INFINITE_UPPER "INF"
258#define LONG_INFINITE_LOWER "infinite"
259#define LONG_INFINITE_UPPER "INFINITE"
260#define NAN_LOWER "nan"
261#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000262
263/* Various constants */
264enum {
265 TYPE_PRINT = 1,
266 TYPE_SCAN = 2,
267
268 /* Flags. Use maximum 32 */
269 FLAGS_NEW = 0,
270 FLAGS_STICKY = 1,
271 FLAGS_SPACE = 2 * FLAGS_STICKY,
272 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
273 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
274 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
275 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
276 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
277 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
278 FLAGS_QUAD = 2 * FLAGS_LONG,
279 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
280 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
281 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
282 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
283 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
284 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
285 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
286 FLAGS_WIDTH = 2 * FLAGS_UPPER,
287 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
288 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
289 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
290 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
291 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
292 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
293 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
294 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
295 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
296 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
297 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
298 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000299 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
300 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000301 /* Reused flags */
302 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000303 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000304 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000305 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000306 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000307
308 NO_POSITION = -1,
309 NO_WIDTH = 0,
310 NO_PRECISION = -1,
311 NO_SIZE = -1,
312
313 NO_BASE = -1,
314 MIN_BASE = 2,
315 MAX_BASE = 36,
316 BASE_BINARY = 2,
317 BASE_OCTAL = 8,
318 BASE_DECIMAL = 10,
319 BASE_HEX = 16,
320
321 /* Maximal number of allowed parameters */
322 MAX_PARAMETERS = 64,
323 /* Maximal number of characters in class */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000324 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000325
Bjorn Reese70a9da52001-04-21 16:57:29 +0000326 /* Maximal string lengths for user-defined specifiers */
327 MAX_USER_NAME = 64,
328 MAX_USER_DATA = 256,
329
Daniel Veillard92ad2102001-03-27 12:47:33 +0000330 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000331 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000332 /* Maximal number of integers in grouping */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000333 MAX_LOCALE_GROUPS = 64,
334
335 /* Initial size of asprintf buffer */
336 DYNAMIC_START_SIZE = 32
Daniel Veillard92ad2102001-03-27 12:47:33 +0000337};
338
339#define NO_GROUPING ((int)CHAR_MAX)
340
341/* Fundamental formatting parameter types */
342#define FORMAT_UNKNOWN 0
343#define FORMAT_INT 1
344#define FORMAT_DOUBLE 2
345#define FORMAT_CHAR 3
346#define FORMAT_STRING 4
347#define FORMAT_POINTER 5
348#define FORMAT_COUNT 6
349#define FORMAT_PARAMETER 7
350#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000351#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000352# define FORMAT_ERRNO 9
353#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000354#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000355# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000356#endif
357
358/* Character constants */
359#define CHAR_IDENTIFIER '%'
360#define CHAR_BACKSLASH '\\'
361#define CHAR_QUOTE '\"'
362#define CHAR_ADJUST ' '
363
364/* Character class expressions */
365#define CLASS_ALNUM ":alnum:"
366#define CLASS_ALPHA ":alpha:"
Bjorn Reese026d29f2002-01-19 15:40:18 +0000367#define CLASS_BLANK ":blank:"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000368#define CLASS_CNTRL ":cntrl:"
369#define CLASS_DIGIT ":digit:"
370#define CLASS_GRAPH ":graph:"
371#define CLASS_LOWER ":lower:"
372#define CLASS_PRINT ":print:"
373#define CLASS_PUNCT ":punct:"
374#define CLASS_SPACE ":space:"
375#define CLASS_UPPER ":upper:"
376#define CLASS_XDIGIT ":xdigit:"
377
378/*
379 * SPECIFIERS:
380 *
381 *
382 * a Hex-float
383 * A Hex-float
384 * c Character
385 * C Widechar character (wint_t)
386 * d Decimal
387 * e Float
388 * E Float
389 * F Float
390 * F Float
391 * g Float
392 * G Float
393 * i Integer
394 * m Error message
395 * n Count
396 * o Octal
397 * p Pointer
398 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000399 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000400 * u Unsigned
401 * x Hex
402 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000403 * [] Group
404 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000405 *
406 * Reserved:
407 *
408 * D Binary Coded Decimal %D(length,precision) (OS/390)
409 */
410#define SPECIFIER_CHAR 'c'
411#define SPECIFIER_STRING 's'
412#define SPECIFIER_DECIMAL 'd'
413#define SPECIFIER_INTEGER 'i'
414#define SPECIFIER_UNSIGNED 'u'
415#define SPECIFIER_OCTAL 'o'
416#define SPECIFIER_HEX 'x'
417#define SPECIFIER_HEX_UPPER 'X'
418#define SPECIFIER_FLOAT_E 'e'
419#define SPECIFIER_FLOAT_E_UPPER 'E'
420#define SPECIFIER_FLOAT_F 'f'
421#define SPECIFIER_FLOAT_F_UPPER 'F'
422#define SPECIFIER_FLOAT_G 'g'
423#define SPECIFIER_FLOAT_G_UPPER 'G'
424#define SPECIFIER_POINTER 'p'
425#define SPECIFIER_GROUP '['
426#define SPECIFIER_UNGROUP ']'
427#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000428#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000429# define SPECIFIER_CHAR_UPPER 'C'
430# define SPECIFIER_STRING_UPPER 'S'
431#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000432#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000433# define SPECIFIER_HEXFLOAT 'a'
434# define SPECIFIER_HEXFLOAT_UPPER 'A'
435#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000436#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000437# define SPECIFIER_ERRNO 'm'
438#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000439#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000440# define SPECIFIER_BINARY 'b'
441# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000442# define SPECIFIER_USER_DEFINED_BEGIN '<'
443# define SPECIFIER_USER_DEFINED_END '>'
444# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000445#endif
446
447/*
448 * QUALIFIERS:
449 *
450 *
451 * Numbers = d,i,o,u,x,X
452 * Float = a,A,e,E,f,F,g,G
453 * String = s
454 * Char = c
455 *
456 *
457 * 9$ Position
458 * Use the 9th parameter. 9 can be any number between 1 and
459 * the maximal argument
460 *
461 * 9 Width
462 * Set width to 9. 9 can be any number, but must not be postfixed
463 * by '$'
464 *
465 * h Short
466 * Numbers:
467 * (unsigned) short int
468 *
469 * hh Short short
470 * Numbers:
471 * (unsigned) char
472 *
473 * l Long
474 * Numbers:
475 * (unsigned) long int
476 * String:
477 * as the S specifier
478 * Char:
479 * as the C specifier
480 *
481 * ll Long Long
482 * Numbers:
483 * (unsigned) long long int
484 *
485 * L Long Double
486 * Float
487 * long double
488 *
489 * # Alternative
490 * Float:
491 * Decimal-point is always present
492 * String:
493 * non-printable characters are handled as \number
494 *
495 * Spacing
496 *
497 * + Sign
498 *
499 * - Alignment
500 *
501 * . Precision
502 *
503 * * Parameter
504 * print: use parameter
505 * scan: no parameter (ignore)
506 *
507 * q Quad
508 *
509 * Z size_t
510 *
511 * w Widechar
512 *
513 * ' Thousands/quote
514 * Numbers:
515 * Integer part grouped in thousands
516 * Binary numbers:
517 * Number grouped in nibbles (4 bits)
518 * String:
519 * Quoted string
520 *
521 * j intmax_t
522 * t prtdiff_t
523 * z size_t
524 *
525 * ! Sticky
526 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000527 *
528 * I n-bit Integer
529 * Numbers:
530 * The following options exists
531 * I8 = 8-bit integer
532 * I16 = 16-bit integer
533 * I32 = 32-bit integer
534 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000535 */
536#define QUALIFIER_POSITION '$'
537#define QUALIFIER_SHORT 'h'
538#define QUALIFIER_LONG 'l'
539#define QUALIFIER_LONG_UPPER 'L'
540#define QUALIFIER_ALTERNATIVE '#'
541#define QUALIFIER_SPACE ' '
542#define QUALIFIER_PLUS '+'
543#define QUALIFIER_MINUS '-'
544#define QUALIFIER_DOT '.'
545#define QUALIFIER_STAR '*'
546#define QUALIFIER_CIRCUMFLEX '^'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000547#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000548# define QUALIFIER_SIZE_T 'z'
549# define QUALIFIER_PTRDIFF_T 't'
550# define QUALIFIER_INTMAX_T 'j'
551#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000552#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000553# define QUALIFIER_QUAD 'q'
554#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000555#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000556# define QUALIFIER_SIZE_T_UPPER 'Z'
557#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000558#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000559# define QUALIFIER_WIDECHAR 'w'
560#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000561#if TRIO_MICROSOFT
562# define QUALIFIER_FIXED_SIZE 'I'
563#endif
564#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000565# define QUALIFIER_QUOTE '\''
566# define QUALIFIER_STICKY '!'
567# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
568# define QUALIFIER_PARAM '@' /* Experimental */
569# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000570# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000571#endif
572
Bjorn Reese70a9da52001-04-21 16:57:29 +0000573
574/*************************************************************************
575 * Internal structures
576 */
577
578/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000579typedef struct {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000580 /* An indication of which entry in the data union is used */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000581 int type;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000582 /* The flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000583 unsigned long flags;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000584 /* The width qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000585 int width;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000586 /* The precision qualifier */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000587 int precision;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000588 /* The base qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000589 int base;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000590 /* The size for the variable size qualifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000591 int varsize;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000592 /* The marker of the end of the specifier */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000593 int indexAfterSpecifier;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000594 /* The data from the argument list */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000595 union {
596 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000597#if TRIO_WIDECHAR
598 wchar_t *wstring;
599#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000600 void *pointer;
601 union {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000602 trio_uintmax_t as_signed;
603 trio_intmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000604 } number;
605 double doubleNumber;
606 double *doublePointer;
607 long double longdoubleNumber;
608 long double *longdoublePointer;
609 int errorNumber;
610 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000611 /* For the user-defined specifier */
612 char user_name[MAX_USER_NAME];
613 char user_data[MAX_USER_DATA];
Bjorn Reese026d29f2002-01-19 15:40:18 +0000614} trio_parameter_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000615
Bjorn Reese70a9da52001-04-21 16:57:29 +0000616/* General trio "class" */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000617typedef struct _trio_class_t {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000618 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +0000619 * The function to write characters to a stream.
620 */
621 void (*OutStream)(struct _trio_class_t *, int);
622 /*
623 * The function to read characters from a stream.
624 */
625 void (*InStream)(struct _trio_class_t *, int *);
626 /*
627 * The current location in the stream.
628 */
629 void *location;
630 /*
631 * The character currently being processed.
632 */
633 int current;
634 /*
635 * The number of characters that would have been written/read
636 * if there had been sufficient space.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000637 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000638 int processed;
639 /*
640 * The number of characters that are actually written/read.
Bjorn Reese026d29f2002-01-19 15:40:18 +0000641 * Processed and committed will only differ for the *nprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +0000642 * and *nscanf functions.
643 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000644 int committed;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000645 /*
646 * The upper limit of characters that may be written/read.
647 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000648 int max;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000649 /*
650 * The last output error that was detected.
651 */
652 int error;
653} trio_class_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000654
Bjorn Reese70a9da52001-04-21 16:57:29 +0000655/* References (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000656typedef struct _trio_reference_t {
657 trio_class_t *data;
658 trio_parameter_t *parameter;
659} trio_reference_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000660
661/* Registered entries (for user-defined callbacks) */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000662typedef struct _trio_userdef_t {
663 struct _trio_userdef_t *next;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000664 trio_callback_t callback;
665 char *name;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000666} trio_userdef_t;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000667
Daniel Veillard92ad2102001-03-27 12:47:33 +0000668
669/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000670 * Internal variables
Daniel Veillard92ad2102001-03-27 12:47:33 +0000671 */
672
Bjorn Reese026d29f2002-01-19 15:40:18 +0000673static TRIO_CONST char rcsid[] = "@(#)$Id$";
674
675/*
676 * Need this to workaround a parser bug in HP C/iX compiler that fails
677 * to resolves macro definitions that includes type 'long double',
678 * e.g: va_arg(arg_ptr, long double)
679 */
680#if defined(TRIO_PLATFORM_MPEIX)
681static TRIO_CONST long double ___dummy_long_double = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000682#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +0000683
684static TRIO_CONST char internalNullString[] = "(nil)";
Daniel Veillard92ad2102001-03-27 12:47:33 +0000685
Bjorn Reese70a9da52001-04-21 16:57:29 +0000686#if defined(USE_LOCALE)
687static struct lconv *internalLocaleValues = NULL;
688#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000689
Bjorn Reese70a9da52001-04-21 16:57:29 +0000690/*
691 * UNIX98 says "in a locale where the radix character is not defined,
692 * the radix character defaults to a period (.)"
693 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000694static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
695static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000696static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
697
Bjorn Reese026d29f2002-01-19 15:40:18 +0000698static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
699static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000700static BOOLEAN_T internalDigitsUnconverted = TRUE;
701static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000702#if TRIO_EXTENSION
703static BOOLEAN_T internalCollationUnconverted = TRUE;
704static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
705#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000706
Bjorn Reese026d29f2002-01-19 15:40:18 +0000707static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
708static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
709static trio_userdef_t *internalUserDef = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000710
711
712/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000713 * trio_strerror
Bjorn Reese70a9da52001-04-21 16:57:29 +0000714 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000715TRIO_PUBLIC TRIO_CONST char *
716trio_strerror(int errorcode)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000717{
718 /* Textual versions of the error codes */
719 switch (TRIO_ERROR_CODE(errorcode))
720 {
721 case TRIO_EOF:
722 return "End of file";
723 case TRIO_EINVAL:
724 return "Invalid argument";
725 case TRIO_ETOOMANY:
726 return "Too many arguments";
727 case TRIO_EDBLREF:
728 return "Double reference";
729 case TRIO_EGAP:
730 return "Reference gap";
731 case TRIO_ENOMEM:
732 return "Out of memory";
733 case TRIO_ERANGE:
734 return "Invalid range";
735 default:
736 return "Unknown";
737 }
738}
Daniel Veillard92ad2102001-03-27 12:47:33 +0000739
740/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000741 * TrioIsQualifier
Daniel Veillard92ad2102001-03-27 12:47:33 +0000742 *
743 * Description:
744 * Remember to add all new qualifiers to this function.
745 * QUALIFIER_POSITION must not be added.
746 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000747TRIO_PRIVATE BOOLEAN_T
748TrioIsQualifier(TRIO_CONST char ch)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000749{
750 /* QUALIFIER_POSITION is not included */
751 switch (ch)
752 {
753 case '0': case '1': case '2': case '3': case '4':
754 case '5': case '6': case '7': case '8': case '9':
755 case QUALIFIER_PLUS:
756 case QUALIFIER_MINUS:
757 case QUALIFIER_SPACE:
758 case QUALIFIER_DOT:
759 case QUALIFIER_STAR:
760 case QUALIFIER_ALTERNATIVE:
761 case QUALIFIER_SHORT:
762 case QUALIFIER_LONG:
763 case QUALIFIER_LONG_UPPER:
764 case QUALIFIER_CIRCUMFLEX:
765#if defined(QUALIFIER_SIZE_T)
766 case QUALIFIER_SIZE_T:
767#endif
768#if defined(QUALIFIER_PTRDIFF_T)
769 case QUALIFIER_PTRDIFF_T:
770#endif
771#if defined(QUALIFIER_INTMAX_T)
772 case QUALIFIER_INTMAX_T:
773#endif
774#if defined(QUALIFIER_QUAD)
775 case QUALIFIER_QUAD:
776#endif
777#if defined(QUALIFIER_SIZE_T_UPPER)
778 case QUALIFIER_SIZE_T_UPPER:
779#endif
780#if defined(QUALIFIER_WIDECHAR)
781 case QUALIFIER_WIDECHAR:
782#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000783#if defined(QUALIFIER_QUOTE)
784 case QUALIFIER_QUOTE:
785#endif
786#if defined(QUALIFIER_STICKY)
787 case QUALIFIER_STICKY:
788#endif
789#if defined(QUALIFIER_VARSIZE)
790 case QUALIFIER_VARSIZE:
791#endif
792#if defined(QUALIFIER_PARAM)
793 case QUALIFIER_PARAM:
794#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000795#if defined(QUALIFIER_FIXED_SIZE)
796 case QUALIFIER_FIXED_SIZE:
797#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000798 return TRUE;
799 default:
800 return FALSE;
801 }
802}
803
804/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000805 * TrioSetLocale
Bjorn Reese70a9da52001-04-21 16:57:29 +0000806 */
807#if defined(USE_LOCALE)
Bjorn Reese026d29f2002-01-19 15:40:18 +0000808TRIO_PUBLIC void
Bjorn Reese70a9da52001-04-21 16:57:29 +0000809TrioSetLocale(void)
810{
811 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000812 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000813 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000814 if ((internalLocaleValues->decimal_point) &&
815 (internalLocaleValues->decimal_point[0] != NIL))
816 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000817 trio_copy_max(internalDecimalPoint,
818 sizeof(internalDecimalPoint),
819 internalLocaleValues->decimal_point);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000820 }
821 if ((internalLocaleValues->thousands_sep) &&
822 (internalLocaleValues->thousands_sep[0] != NIL))
823 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000824 trio_copy_max(internalThousandSeparator,
825 sizeof(internalThousandSeparator),
826 internalLocaleValues->thousands_sep);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000827 }
828 if ((internalLocaleValues->grouping) &&
829 (internalLocaleValues->grouping[0] != NIL))
830 {
Bjorn Reese026d29f2002-01-19 15:40:18 +0000831 trio_copy_max(internalGrouping,
832 sizeof(internalGrouping),
833 internalLocaleValues->grouping);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000834 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000835 }
836}
837#endif /* defined(USE_LOCALE) */
838
839/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000840 * TrioGetPosition
Daniel Veillard92ad2102001-03-27 12:47:33 +0000841 *
842 * Get the %n$ position.
843 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000844TRIO_PRIVATE int
845TrioGetPosition(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000846 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000847{
848 char *tmpformat;
849 int number = 0;
850 int index = *indexPointer;
851
Bjorn Reese026d29f2002-01-19 15:40:18 +0000852 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +0000853 index = (int)(tmpformat - format);
854 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
855 {
856 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000857 /*
858 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000859 * the array it is indexing starts from 0.
860 */
861 return number - 1;
862 }
863 return NO_POSITION;
864}
865
866/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000867 * TrioFindNamespace
Bjorn Reese70a9da52001-04-21 16:57:29 +0000868 *
869 * Find registered user-defined specifier.
Bjorn Reese026d29f2002-01-19 15:40:18 +0000870 * The prev argument is used for optimisation only.
Bjorn Reese70a9da52001-04-21 16:57:29 +0000871 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000872TRIO_PRIVATE trio_userdef_t *
873TrioFindNamespace(TRIO_CONST char *name, trio_userdef_t **prev)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000874{
Bjorn Reese026d29f2002-01-19 15:40:18 +0000875 trio_userdef_t *def;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000876
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000877 if (internalEnterCriticalRegion)
878 (void)internalEnterCriticalRegion(NULL);
879
Bjorn Reese70a9da52001-04-21 16:57:29 +0000880 for (def = internalUserDef; def; def = def->next)
881 {
882 /* Case-sensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000883 if (trio_equal_case(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000884 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000885
886 if (prev)
887 *prev = def;
888 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000889
890 if (internalLeaveCriticalRegion)
891 (void)internalLeaveCriticalRegion(NULL);
892
Bjorn Reese70a9da52001-04-21 16:57:29 +0000893 return def;
894}
895
896/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +0000897 * TrioParse
Daniel Veillard92ad2102001-03-27 12:47:33 +0000898 *
899 * Description:
900 * Parse the format string
901 */
Bjorn Reese026d29f2002-01-19 15:40:18 +0000902TRIO_PRIVATE int
903TrioParse(int type,
904 TRIO_CONST char *format,
905 trio_parameter_t *parameters,
906 va_list arglist,
907 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000908{
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000909#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +0000910 /* Count the number of times a parameter is referenced */
911 unsigned short usedEntries[MAX_PARAMETERS];
912#endif
913 /* Parameter counters */
914 int parameterPosition;
915 int currentParam;
916 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000917 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000918 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000919 int width;
920 int precision;
921 int varsize;
922 int base;
923 int index; /* Index into formatting string */
924 int dots; /* Count number of dots in modifier part */
925 BOOLEAN_T positional; /* Does the specifier have a positional? */
926 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000927 /*
928 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +0000929 * read from the va_args (this is necessary to handle positionals)
930 */
931 int indices[MAX_PARAMETERS];
932 int pos = 0;
933 /* Various variables */
934 char ch;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000935#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000936 int charlen;
Bjorn Reese026d29f2002-01-19 15:40:18 +0000937#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000938 int i = -1;
939 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000940 char *tmpformat;
941
942
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000943#if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +0000944 /*
945 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +0000946 * know which entries we have used.
947 */
948 memset(usedEntries, 0, sizeof(usedEntries));
949#endif
950
951 index = 0;
952 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000953#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000954 mblen(NULL, 0);
955#endif
956
957 while (format[index])
958 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000959#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000960 if (! isascii(format[index]))
961 {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000962 /*
963 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +0000964 * modifiers, so we skip over them.
965 */
966 charlen = mblen(&format[index], MB_LEN_MAX);
967 index += (charlen > 0) ? charlen : 1;
968 continue; /* while */
969 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000970#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000971 if (CHAR_IDENTIFIER == format[index++])
972 {
973 if (CHAR_IDENTIFIER == format[index])
974 {
975 index++;
976 continue; /* while */
977 }
978
979 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000980 dots = 0;
981 currentParam = TrioGetPosition(format, &index);
982 positional = (NO_POSITION != currentParam);
983 if (!positional)
984 {
985 /* We have no positional, get the next counter */
986 currentParam = parameterPosition;
987 }
988 if(currentParam >= MAX_PARAMETERS)
989 {
990 /* Bail out completely to make the error more obvious */
991 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
992 }
993
994 if (currentParam > maxParam)
995 maxParam = currentParam;
996
997 /* Default values */
998 width = NO_WIDTH;
999 precision = NO_PRECISION;
1000 base = NO_BASE;
1001 varsize = NO_SIZE;
1002
Bjorn Reese70a9da52001-04-21 16:57:29 +00001003 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001004 {
1005 ch = format[index++];
1006
Daniel Veillard92ad2102001-03-27 12:47:33 +00001007 switch (ch)
1008 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001009 case QUALIFIER_SPACE:
1010 flags |= FLAGS_SPACE;
1011 break;
1012
1013 case QUALIFIER_PLUS:
1014 flags |= FLAGS_SHOWSIGN;
1015 break;
1016
1017 case QUALIFIER_MINUS:
1018 flags |= FLAGS_LEFTADJUST;
1019 flags &= ~FLAGS_NILPADDING;
1020 break;
1021
1022 case QUALIFIER_ALTERNATIVE:
1023 flags |= FLAGS_ALTERNATIVE;
1024 break;
1025
1026 case QUALIFIER_DOT:
1027 if (dots == 0) /* Precision */
1028 {
1029 dots++;
1030
1031 /* Skip if no precision */
1032 if (QUALIFIER_DOT == format[index])
1033 break;
1034
1035 /* After the first dot we have the precision */
1036 flags |= FLAGS_PRECISION;
1037 if ((QUALIFIER_STAR == format[index]) ||
1038 (QUALIFIER_PARAM == format[index]))
1039 {
1040 index++;
1041 flags |= FLAGS_PRECISION_PARAMETER;
1042
1043 precision = TrioGetPosition(format, &index);
1044 if (precision == NO_POSITION)
1045 {
1046 parameterPosition++;
1047 if (positional)
1048 precision = parameterPosition;
1049 else
1050 {
1051 precision = currentParam;
1052 currentParam = precision + 1;
1053 }
1054 }
1055 else
1056 {
1057 if (! positional)
1058 currentParam = precision + 1;
1059 if (width > maxParam)
1060 maxParam = precision;
1061 }
1062 if (currentParam > maxParam)
1063 maxParam = currentParam;
1064 }
1065 else
1066 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001067 precision = trio_to_long(&format[index],
1068 &tmpformat,
1069 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001070 index = (int)(tmpformat - format);
1071 }
1072 }
1073 else if (dots == 1) /* Base */
1074 {
1075 dots++;
1076
1077 /* After the second dot we have the base */
1078 flags |= FLAGS_BASE;
1079 if ((QUALIFIER_STAR == format[index]) ||
1080 (QUALIFIER_PARAM == format[index]))
1081 {
1082 index++;
1083 flags |= FLAGS_BASE_PARAMETER;
1084 base = TrioGetPosition(format, &index);
1085 if (base == NO_POSITION)
1086 {
1087 parameterPosition++;
1088 if (positional)
1089 base = parameterPosition;
1090 else
1091 {
1092 base = currentParam;
1093 currentParam = base + 1;
1094 }
1095 }
1096 else
1097 {
1098 if (! positional)
1099 currentParam = base + 1;
1100 if (base > maxParam)
1101 maxParam = base;
1102 }
1103 if (currentParam > maxParam)
1104 maxParam = currentParam;
1105 }
1106 else
1107 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00001108 base = trio_to_long(&format[index],
1109 &tmpformat,
1110 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001111 if (base > MAX_BASE)
1112 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1113 index = (int)(tmpformat - format);
1114 }
1115 }
1116 else
1117 {
1118 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1119 }
1120 break; /* QUALIFIER_DOT */
1121
1122 case QUALIFIER_PARAM:
1123 type = TYPE_PRINT;
1124 /* FALLTHROUGH */
1125 case QUALIFIER_STAR:
1126 /* This has different meanings for print and scan */
1127 if (TYPE_PRINT == type)
1128 {
1129 /* Read with from parameter */
1130 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1131 width = TrioGetPosition(format, &index);
1132 if (width == NO_POSITION)
1133 {
1134 parameterPosition++;
1135 if (positional)
1136 width = parameterPosition;
1137 else
1138 {
1139 width = currentParam;
1140 currentParam = width + 1;
1141 }
1142 }
1143 else
1144 {
1145 if (! positional)
1146 currentParam = width + 1;
1147 if (width > maxParam)
1148 maxParam = width;
1149 }
1150 if (currentParam > maxParam)
1151 maxParam = currentParam;
1152 }
1153 else
1154 {
1155 /* Scan, but do not store result */
1156 flags |= FLAGS_IGNORE;
1157 }
1158
1159 break; /* QUALIFIER_STAR */
1160
1161 case '0':
1162 if (! (flags & FLAGS_LEFTADJUST))
1163 flags |= FLAGS_NILPADDING;
1164 /* FALLTHROUGH */
1165 case '1': case '2': case '3': case '4':
1166 case '5': case '6': case '7': case '8': case '9':
1167 flags |= FLAGS_WIDTH;
1168 /* &format[index - 1] is used to "rewind" the read
1169 * character from format
1170 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001171 width = trio_to_long(&format[index - 1],
1172 &tmpformat,
1173 BASE_DECIMAL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001174 index = (int)(tmpformat - format);
1175 break;
1176
1177 case QUALIFIER_SHORT:
1178 if (flags & FLAGS_SHORTSHORT)
1179 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1180 else if (flags & FLAGS_SHORT)
1181 flags |= FLAGS_SHORTSHORT;
1182 else
1183 flags |= FLAGS_SHORT;
1184 break;
1185
1186 case QUALIFIER_LONG:
1187 if (flags & FLAGS_QUAD)
1188 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1189 else if (flags & FLAGS_LONG)
1190 flags |= FLAGS_QUAD;
1191 else
1192 flags |= FLAGS_LONG;
1193 break;
1194
1195 case QUALIFIER_LONG_UPPER:
1196 flags |= FLAGS_LONGDOUBLE;
1197 break;
1198
1199#if defined(QUALIFIER_SIZE_T)
1200 case QUALIFIER_SIZE_T:
1201 flags |= FLAGS_SIZE_T;
1202 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001203 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001204 flags |= FLAGS_QUAD;
1205 else if (sizeof(size_t) == sizeof(long))
1206 flags |= FLAGS_LONG;
1207 break;
1208#endif
1209
1210#if defined(QUALIFIER_PTRDIFF_T)
1211 case QUALIFIER_PTRDIFF_T:
1212 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001213 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001214 flags |= FLAGS_QUAD;
1215 else if (sizeof(ptrdiff_t) == sizeof(long))
1216 flags |= FLAGS_LONG;
1217 break;
1218#endif
1219
1220#if defined(QUALIFIER_INTMAX_T)
1221 case QUALIFIER_INTMAX_T:
1222 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001223 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001224 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001225 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001226 flags |= FLAGS_LONG;
1227 break;
1228#endif
1229
1230#if defined(QUALIFIER_QUAD)
1231 case QUALIFIER_QUAD:
1232 flags |= FLAGS_QUAD;
1233 break;
1234#endif
1235
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001236#if defined(QUALIFIER_FIXED_SIZE)
1237 case QUALIFIER_FIXED_SIZE:
1238 if (flags & FLAGS_FIXED_SIZE)
1239 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1240
1241 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1242 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1243 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1244
1245 if ((format[index] == '6') &&
1246 (format[index + 1] == '4'))
1247 {
1248 varsize = sizeof(trio_int64_t);
1249 index += 2;
1250 }
1251 else if ((format[index] == '3') &&
1252 (format[index + 1] == '2'))
1253 {
1254 varsize = sizeof(trio_int32_t);
1255 index += 2;
1256 }
1257 else if ((format[index] == '1') &&
1258 (format[index + 1] == '6'))
1259 {
1260 varsize = sizeof(trio_int16_t);
1261 index += 2;
1262 }
1263 else if (format[index] == '8')
1264 {
1265 varsize = sizeof(trio_int8_t);
1266 index++;
1267 }
1268 else
1269 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1270
1271 flags |= FLAGS_FIXED_SIZE;
1272 break;
1273#endif
1274
Daniel Veillard92ad2102001-03-27 12:47:33 +00001275#if defined(QUALIFIER_WIDECHAR)
1276 case QUALIFIER_WIDECHAR:
1277 flags |= FLAGS_WIDECHAR;
1278 break;
1279#endif
1280
1281#if defined(QUALIFIER_SIZE_T_UPPER)
1282 case QUALIFIER_SIZE_T_UPPER:
1283 break;
1284#endif
1285
1286#if defined(QUALIFIER_QUOTE)
1287 case QUALIFIER_QUOTE:
1288 flags |= FLAGS_QUOTE;
1289 break;
1290#endif
1291
1292#if defined(QUALIFIER_STICKY)
1293 case QUALIFIER_STICKY:
1294 flags |= FLAGS_STICKY;
1295 got_sticky = TRUE;
1296 break;
1297#endif
1298
1299#if defined(QUALIFIER_VARSIZE)
1300 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001301 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001302 parameterPosition++;
1303 if (positional)
1304 varsize = parameterPosition;
1305 else
1306 {
1307 varsize = currentParam;
1308 currentParam = varsize + 1;
1309 }
1310 if (currentParam > maxParam)
1311 maxParam = currentParam;
1312 break;
1313#endif
1314
1315 default:
1316 /* Bail out completely to make the error more obvious */
1317 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1318 }
1319 } /* while qualifier */
1320
Bjorn Reese70a9da52001-04-21 16:57:29 +00001321 /*
1322 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001323 * read later.
1324 */
1325 if (flags & FLAGS_WIDTH_PARAMETER)
1326 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001327#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001328 usedEntries[width] += 1;
1329#endif
1330 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001331 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001332 indices[width] = pos;
1333 width = pos++;
1334 }
1335 if (flags & FLAGS_PRECISION_PARAMETER)
1336 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001337#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001338 usedEntries[precision] += 1;
1339#endif
1340 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001341 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001342 indices[precision] = pos;
1343 precision = pos++;
1344 }
1345 if (flags & FLAGS_BASE_PARAMETER)
1346 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001347#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001348 usedEntries[base] += 1;
1349#endif
1350 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001351 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001352 indices[base] = pos;
1353 base = pos++;
1354 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001355 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001356 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001357#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001358 usedEntries[varsize] += 1;
1359#endif
1360 parameters[pos].type = FORMAT_PARAMETER;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001361 parameters[pos].flags = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001362 indices[varsize] = pos;
1363 varsize = pos++;
1364 }
1365
1366 indices[currentParam] = pos;
1367
1368 switch (format[index++])
1369 {
1370#if defined(SPECIFIER_CHAR_UPPER)
1371 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001372 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001373 /* FALLTHROUGH */
1374#endif
1375 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001376 if (flags & FLAGS_LONG)
1377 flags |= FLAGS_WIDECHAR;
1378 else if (flags & FLAGS_SHORT)
1379 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001380 parameters[pos].type = FORMAT_CHAR;
1381 break;
1382
1383#if defined(SPECIFIER_STRING_UPPER)
1384 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001385 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001386 /* FALLTHROUGH */
1387#endif
1388 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001389 if (flags & FLAGS_LONG)
1390 flags |= FLAGS_WIDECHAR;
1391 else if (flags & FLAGS_SHORT)
1392 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001393 parameters[pos].type = FORMAT_STRING;
1394 break;
1395
1396 case SPECIFIER_GROUP:
1397 if (TYPE_SCAN == type)
1398 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001399 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001400 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001401 if (format[index] == QUALIFIER_CIRCUMFLEX)
1402 index++;
1403 if (format[index] == SPECIFIER_UNGROUP)
1404 index++;
1405 if (format[index] == QUALIFIER_MINUS)
1406 index++;
1407 /* Skip nested brackets */
1408 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001409 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001410 if (format[index] == SPECIFIER_GROUP)
1411 {
1412 depth++;
1413 }
1414 else if (format[index] == SPECIFIER_UNGROUP)
1415 {
1416 if (--depth <= 0)
1417 {
1418 index++;
1419 break;
1420 }
1421 }
1422 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001423 }
1424 }
1425 break;
1426
1427 case SPECIFIER_INTEGER:
1428 parameters[pos].type = FORMAT_INT;
1429 break;
1430
1431 case SPECIFIER_UNSIGNED:
1432 flags |= FLAGS_UNSIGNED;
1433 parameters[pos].type = FORMAT_INT;
1434 break;
1435
1436 case SPECIFIER_DECIMAL:
1437 /* Disable base modifier */
1438 flags &= ~FLAGS_BASE_PARAMETER;
1439 base = BASE_DECIMAL;
1440 parameters[pos].type = FORMAT_INT;
1441 break;
1442
1443 case SPECIFIER_OCTAL:
1444 flags &= ~FLAGS_BASE_PARAMETER;
1445 base = BASE_OCTAL;
1446 parameters[pos].type = FORMAT_INT;
1447 break;
1448
1449#if defined(SPECIFIER_BINARY)
1450 case SPECIFIER_BINARY_UPPER:
1451 flags |= FLAGS_UPPER;
1452 /* FALLTHROUGH */
1453 case SPECIFIER_BINARY:
1454 flags |= FLAGS_NILPADDING;
1455 flags &= ~FLAGS_BASE_PARAMETER;
1456 base = BASE_BINARY;
1457 parameters[pos].type = FORMAT_INT;
1458 break;
1459#endif
1460
1461 case SPECIFIER_HEX_UPPER:
1462 flags |= FLAGS_UPPER;
1463 /* FALLTHROUGH */
1464 case SPECIFIER_HEX:
1465 flags |= FLAGS_UNSIGNED;
1466 flags &= ~FLAGS_BASE_PARAMETER;
1467 base = BASE_HEX;
1468 parameters[pos].type = FORMAT_INT;
1469 break;
1470
1471 case SPECIFIER_FLOAT_E_UPPER:
1472 flags |= FLAGS_UPPER;
1473 /* FALLTHROUGH */
1474 case SPECIFIER_FLOAT_E:
1475 flags |= FLAGS_FLOAT_E;
1476 parameters[pos].type = FORMAT_DOUBLE;
1477 break;
1478
1479 case SPECIFIER_FLOAT_G_UPPER:
1480 flags |= FLAGS_UPPER;
1481 /* FALLTHROUGH */
1482 case SPECIFIER_FLOAT_G:
1483 flags |= FLAGS_FLOAT_G;
1484 parameters[pos].type = FORMAT_DOUBLE;
1485 break;
1486
1487 case SPECIFIER_FLOAT_F_UPPER:
1488 flags |= FLAGS_UPPER;
1489 /* FALLTHROUGH */
1490 case SPECIFIER_FLOAT_F:
1491 parameters[pos].type = FORMAT_DOUBLE;
1492 break;
1493
1494 case SPECIFIER_POINTER:
1495 parameters[pos].type = FORMAT_POINTER;
1496 break;
1497
1498 case SPECIFIER_COUNT:
1499 parameters[pos].type = FORMAT_COUNT;
1500 break;
1501
1502#if defined(SPECIFIER_HEXFLOAT)
1503# if defined(SPECIFIER_HEXFLOAT_UPPER)
1504 case SPECIFIER_HEXFLOAT_UPPER:
1505 flags |= FLAGS_UPPER;
1506 /* FALLTHROUGH */
1507# endif
1508 case SPECIFIER_HEXFLOAT:
1509 base = BASE_HEX;
1510 parameters[pos].type = FORMAT_DOUBLE;
1511 break;
1512#endif
1513
1514#if defined(FORMAT_ERRNO)
1515 case SPECIFIER_ERRNO:
1516 parameters[pos].type = FORMAT_ERRNO;
1517 break;
1518#endif
1519
Bjorn Reese70a9da52001-04-21 16:57:29 +00001520#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1521 case SPECIFIER_USER_DEFINED_BEGIN:
1522 {
1523 unsigned int max;
1524 int without_namespace = TRUE;
1525
1526 parameters[pos].type = FORMAT_USER_DEFINED;
1527 parameters[pos].user_name[0] = NIL;
1528 tmpformat = (char *)&format[index];
1529
1530 while ((ch = format[index]))
1531 {
1532 index++;
1533 if (ch == SPECIFIER_USER_DEFINED_END)
1534 {
1535 if (without_namespace)
1536 {
1537 /* We must get the handle first */
1538 parameters[pos].type = FORMAT_PARAMETER;
1539 parameters[pos].indexAfterSpecifier = index;
1540 parameters[pos].flags = FLAGS_USER_DEFINED;
1541 /* Adjust parameters for insertion of new one */
1542 pos++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001543# if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +00001544 usedEntries[currentParam] += 1;
1545# endif
1546 parameters[pos].type = FORMAT_USER_DEFINED;
1547 currentParam++;
1548 indices[currentParam] = pos;
1549 if (currentParam > maxParam)
1550 maxParam = currentParam;
1551 }
1552 /* Copy the user data */
1553 max = (unsigned int)(&format[index] - tmpformat);
1554 if (max > MAX_USER_DATA)
1555 max = MAX_USER_DATA;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001556 trio_copy_max(parameters[pos].user_data,
1557 max,
1558 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001559 break; /* while */
1560 }
1561 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1562 {
1563 without_namespace = FALSE;
1564 /* Copy the namespace for later looking-up */
1565 max = (int)(&format[index] - tmpformat);
1566 if (max > MAX_USER_NAME)
1567 max = MAX_USER_NAME;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001568 trio_copy_max(parameters[pos].user_name,
1569 max,
1570 tmpformat);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001571 tmpformat = (char *)&format[index];
1572 }
1573 }
1574 if (ch != SPECIFIER_USER_DEFINED_END)
1575 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1576 }
1577 break;
1578#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1579
Daniel Veillard92ad2102001-03-27 12:47:33 +00001580 default:
1581 /* Bail out completely to make the error more obvious */
1582 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1583 }
1584
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001585#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001586 /* Count the number of times this entry has been used */
1587 usedEntries[currentParam] += 1;
1588#endif
1589
1590 /* Find last sticky parameters */
1591 if (got_sticky && !(flags & FLAGS_STICKY))
1592 {
1593 for (i = pos - 1; i >= 0; i--)
1594 {
1595 if (parameters[i].type == FORMAT_PARAMETER)
1596 continue;
1597 if ((parameters[i].flags & FLAGS_STICKY) &&
1598 (parameters[i].type == parameters[pos].type))
1599 {
1600 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001601 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001602 if (width == NO_WIDTH)
1603 width = parameters[i].width;
1604 if (precision == NO_PRECISION)
1605 precision = parameters[i].precision;
1606 if (base == NO_BASE)
1607 base = parameters[i].base;
1608 break;
1609 }
1610 }
1611 }
1612
1613 parameters[pos].indexAfterSpecifier = index;
1614 parameters[pos].flags = flags;
1615 parameters[pos].width = width;
1616 parameters[pos].precision = precision;
1617 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1618 parameters[pos].varsize = varsize;
1619 pos++;
1620
Bjorn Reese70a9da52001-04-21 16:57:29 +00001621 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001622 parameterPosition++;
1623
1624 } /* if identifier */
1625
1626 } /* while format characters left */
1627
1628 for (num = 0; num <= maxParam; num++)
1629 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001630#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001631 if (usedEntries[num] != 1)
1632 {
1633 if (usedEntries[num] == 0) /* gap detected */
1634 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1635 else /* double references detected */
1636 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1637 }
1638#endif
1639
1640 i = indices[num];
1641
Bjorn Reese70a9da52001-04-21 16:57:29 +00001642 /*
1643 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001644 * so it makes no sense to check the ignore flag (besides,
1645 * the flags variable is not set for that particular type)
1646 */
1647 if ((parameters[i].type != FORMAT_PARAMETER) &&
1648 (parameters[i].flags & FLAGS_IGNORE))
1649 continue; /* for all arguments */
1650
Bjorn Reese70a9da52001-04-21 16:57:29 +00001651 /*
1652 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001653 * default argument promotions:
1654 *
1655 * char = int
1656 * short = int
1657 * unsigned char = unsigned int
1658 * unsigned short = unsigned int
1659 * float = double
1660 *
1661 * In addition to the ANSI C89 these types are read (the
1662 * default argument promotions of C99 has not been
1663 * considered yet)
1664 *
1665 * long long
1666 * long double
1667 * size_t
1668 * ptrdiff_t
1669 * intmax_t
1670 */
1671 switch (parameters[i].type)
1672 {
1673 case FORMAT_GROUP:
1674 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001675#if TRIO_WIDECHAR
1676 if (flags & FLAGS_WIDECHAR)
1677 {
1678 parameters[i].data.wstring = (argarray == NULL)
1679 ? va_arg(arglist, wchar_t *)
1680 : (wchar_t *)(argarray[num]);
1681 }
1682 else
1683#endif
1684 {
1685 parameters[i].data.string = (argarray == NULL)
1686 ? va_arg(arglist, char *)
1687 : (char *)(argarray[num]);
1688 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001689 break;
1690
1691 case FORMAT_POINTER:
1692 case FORMAT_COUNT:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001693 case FORMAT_USER_DEFINED:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001694 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001695 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001696 ? va_arg(arglist, void *)
1697 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001698 break;
1699
1700 case FORMAT_CHAR:
1701 case FORMAT_INT:
1702 if (TYPE_SCAN == type)
1703 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001704 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001705 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001706 (trio_uintmax_t *)va_arg(arglist, void *);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001707 else
1708 {
1709 if (parameters[i].type == FORMAT_CHAR)
1710 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001711 (trio_uintmax_t *)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001712 else if (parameters[i].flags & FLAGS_SHORT)
1713 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001714 (trio_uintmax_t *)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001715 else
1716 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001717 (trio_uintmax_t *)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001718 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001719 }
1720 else
1721 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001722#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
Bjorn Reese026d29f2002-01-19 15:40:18 +00001723 if (parameters[i].flags
1724 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001725 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001726 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1727 {
1728 /*
1729 * Variable sizes are mapped onto the fixed sizes, in
1730 * accordance with integer promotion.
1731 *
1732 * Please note that this may not be portable, as we
1733 * only guess the size, not the layout of the numbers.
1734 * For example, if int is little-endian, and long is
1735 * big-endian, then this will fail.
1736 */
1737 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1738 }
1739 else
1740 {
1741 /* Used for the I<bits> modifiers */
1742 varsize = parameters[i].varsize;
1743 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001744 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001745
Daniel Veillard92ad2102001-03-27 12:47:33 +00001746 if (varsize <= (int)sizeof(int))
1747 ;
1748 else if (varsize <= (int)sizeof(long))
1749 parameters[i].flags |= FLAGS_LONG;
1750#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001751 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001752 parameters[i].flags |= FLAGS_QUAD;
1753 else
1754 parameters[i].flags |= FLAGS_INTMAX_T;
1755#else
1756 else
1757 parameters[i].flags |= FLAGS_QUAD;
1758#endif
1759 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001760#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001761#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1762 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001763 parameters[i].data.number.as_unsigned = (argarray == NULL)
1764 ? (trio_uintmax_t)va_arg(arglist, size_t)
1765 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001766 else
1767#endif
1768#if defined(QUALIFIER_PTRDIFF_T)
1769 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001770 parameters[i].data.number.as_unsigned = (argarray == NULL)
1771 ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
1772 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001773 else
1774#endif
1775#if defined(QUALIFIER_INTMAX_T)
1776 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001777 parameters[i].data.number.as_unsigned = (argarray == NULL)
1778 ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
1779 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001780 else
1781#endif
1782 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001783 parameters[i].data.number.as_unsigned = (argarray == NULL)
1784 ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
1785 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001786 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001787 parameters[i].data.number.as_unsigned = (argarray == NULL)
1788 ? (trio_uintmax_t)va_arg(arglist, long)
1789 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001790 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001791 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001792 if (argarray == NULL)
1793 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001794 else
1795 {
1796 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001797 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001798 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001799 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001800 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001801 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001802 }
1803 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001804 }
1805 break;
1806
1807 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001808 /*
1809 * The parameter for the user-defined specifier is a pointer,
1810 * whereas the rest (width, precision, base) uses an integer.
1811 */
1812 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001813 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001814 ? va_arg(arglist, void *)
1815 : argarray[num];
1816 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001817 parameters[i].data.number.as_unsigned = (argarray == NULL)
1818 ? (trio_uintmax_t)va_arg(arglist, int)
1819 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001820 break;
1821
1822 case FORMAT_DOUBLE:
1823 if (TYPE_SCAN == type)
1824 {
1825 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001826 parameters[i].data.longdoublePointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001827 ? va_arg(arglist, long double *)
1828 : (long double *)((long double *)argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001829 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001830 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001831 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001832 parameters[i].data.doublePointer =
1833 va_arg(arglist, double *);
1834 else
1835 {
1836 if (parameters[i].flags & FLAGS_SHORT)
1837 parameters[i].data.doublePointer =
1838 (double *)((float *)argarray[num]);
1839 else
1840 parameters[i].data.doublePointer =
1841 (double *)((double *)argarray[num]);
1842 }
1843 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001844 }
1845 else
1846 {
1847 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001848 parameters[i].data.longdoubleNumber = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001849 ? va_arg(arglist, long double)
1850 : (long double)(*((long double *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001851 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001852 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001853 if (argarray == NULL)
Bjorn Reese026d29f2002-01-19 15:40:18 +00001854 parameters[i].data.longdoubleNumber =
1855 (long double)va_arg(arglist, double);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001856 else
1857 {
1858 if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese026d29f2002-01-19 15:40:18 +00001859 parameters[i].data.longdoubleNumber =
1860 (long double)(*((float *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001861 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00001862 parameters[i].data.longdoubleNumber =
1863 (long double)(long double)(*((double *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001864 }
1865 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001866 }
1867 break;
1868
1869#if defined(FORMAT_ERRNO)
1870 case FORMAT_ERRNO:
1871 parameters[i].data.errorNumber = errno;
1872 break;
1873#endif
1874
1875 default:
1876 break;
1877 }
1878 } /* for all specifiers */
1879 return num;
1880}
1881
1882
1883/*************************************************************************
1884 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00001885 * FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00001886 *
1887 ************************************************************************/
1888
1889
1890/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00001891 * TrioWriteNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00001892 *
1893 * Description:
1894 * Output a number.
1895 * The complexity of this function is a result of the complexity
1896 * of the dependencies of the flags.
1897 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001898TRIO_PRIVATE void
1899TrioWriteNumber(trio_class_t *self,
1900 trio_uintmax_t number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001901 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001902 int width,
1903 int precision,
1904 int base)
1905{
1906 BOOLEAN_T isNegative;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001907 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001908 char *bufferend;
1909 char *pointer;
Bjorn Reese026d29f2002-01-19 15:40:18 +00001910 TRIO_CONST char *digits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001911 int i;
1912 int length;
1913 char *p;
1914 int charsPerThousand;
1915 int groupingIndex;
1916 int count;
1917
1918 assert(VALID(self));
1919 assert(VALID(self->OutStream));
Bjorn Reese026d29f2002-01-19 15:40:18 +00001920 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001921
Bjorn Reese70a9da52001-04-21 16:57:29 +00001922 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001923
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001924 isNegative = (flags & FLAGS_UNSIGNED)
1925 ? FALSE
Bjorn Reese026d29f2002-01-19 15:40:18 +00001926 : ((trio_intmax_t)number < 0);
1927 if (isNegative)
1928 number = -number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001929
1930 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001931 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001932 else if (flags & FLAGS_LONG)
1933 number &= (unsigned long)-1;
1934 else
1935 number &= (unsigned int)-1;
1936
1937 /* Build number */
1938 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1939 *pointer-- = NIL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001940 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001941 groupingIndex = 1;
1942 for (i = 1; i < (int)sizeof(buffer); i++)
1943 {
1944 *pointer-- = digits[number % base];
1945 number /= base;
1946 if (number == 0)
1947 break;
1948
1949 if ((flags & FLAGS_QUOTE)
1950 && (charsPerThousand != NO_GROUPING)
1951 && (i % charsPerThousand == 0))
1952 {
1953 /*
1954 * We are building the number from the least significant
1955 * to the most significant digit, so we have to copy the
1956 * thousand separator backwards
1957 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00001958 length = trio_length(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001959 if (((int)(pointer - buffer) - length) > 0)
1960 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001961 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001962 while (length-- > 0)
1963 *pointer-- = *p--;
1964 }
1965
1966 /* Advance to next grouping number */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001967 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00001968 {
1969 case CHAR_MAX: /* Disable grouping */
1970 charsPerThousand = NO_GROUPING;
1971 break;
1972 case 0: /* Repeat last group */
1973 break;
1974 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001975 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001976 break;
1977 }
1978 }
1979 }
1980
1981 /* Adjust width */
1982 width -= (bufferend - pointer) - 1;
1983
1984 /* Adjust precision */
1985 if (NO_PRECISION != precision)
1986 {
1987 precision -= (bufferend - pointer) - 1;
1988 if (precision < 0)
1989 precision = 0;
1990 flags |= FLAGS_NILPADDING;
1991 }
1992
1993 /* Adjust width further */
1994 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
1995 width--;
1996 if (flags & FLAGS_ALTERNATIVE)
1997 {
1998 switch (base)
1999 {
2000 case BASE_BINARY:
2001 case BASE_HEX:
2002 width -= 2;
2003 break;
2004 case BASE_OCTAL:
2005 width--;
2006 break;
2007 default:
2008 break;
2009 }
2010 }
2011
2012 /* Output prefixes spaces if needed */
2013 if (! ((flags & FLAGS_LEFTADJUST) ||
2014 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2015 {
2016 count = (precision == NO_PRECISION) ? 0 : precision;
2017 while (width-- > count)
2018 self->OutStream(self, CHAR_ADJUST);
2019 }
2020
2021 /* width has been adjusted for signs and alternatives */
2022 if (isNegative)
2023 self->OutStream(self, '-');
2024 else if (flags & FLAGS_SHOWSIGN)
2025 self->OutStream(self, '+');
2026 else if (flags & FLAGS_SPACE)
2027 self->OutStream(self, ' ');
2028
2029 if (flags & FLAGS_ALTERNATIVE)
2030 {
2031 switch (base)
2032 {
2033 case BASE_BINARY:
2034 self->OutStream(self, '0');
2035 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2036 break;
2037
2038 case BASE_OCTAL:
2039 self->OutStream(self, '0');
2040 break;
2041
2042 case BASE_HEX:
2043 self->OutStream(self, '0');
2044 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2045 break;
2046
2047 default:
2048 break;
2049 } /* switch base */
2050 }
2051
2052 /* Output prefixed zero padding if needed */
2053 if (flags & FLAGS_NILPADDING)
2054 {
2055 if (precision == NO_PRECISION)
2056 precision = width;
2057 while (precision-- > 0)
2058 {
2059 self->OutStream(self, '0');
2060 width--;
2061 }
2062 }
2063
2064 /* Output the number itself */
2065 while (*(++pointer))
2066 {
2067 self->OutStream(self, *pointer);
2068 }
2069
2070 /* Output trailing spaces if needed */
2071 if (flags & FLAGS_LEFTADJUST)
2072 {
2073 while (width-- > 0)
2074 self->OutStream(self, CHAR_ADJUST);
2075 }
2076}
2077
2078/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002079 * TrioWriteStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002080 *
2081 * Description:
2082 * Output a single character of a string
2083 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002084TRIO_PRIVATE void
2085TrioWriteStringCharacter(trio_class_t *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002086 int ch,
2087 unsigned long flags)
2088{
2089 if (flags & FLAGS_ALTERNATIVE)
2090 {
2091 if (! (isprint(ch) || isspace(ch)))
2092 {
2093 /*
2094 * Non-printable characters are converted to C escapes or
2095 * \number, if no C escape exists.
2096 */
2097 self->OutStream(self, CHAR_BACKSLASH);
2098 switch (ch)
2099 {
2100 case '\007': self->OutStream(self, 'a'); break;
2101 case '\b': self->OutStream(self, 'b'); break;
2102 case '\f': self->OutStream(self, 'f'); break;
2103 case '\n': self->OutStream(self, 'n'); break;
2104 case '\r': self->OutStream(self, 'r'); break;
2105 case '\t': self->OutStream(self, 't'); break;
2106 case '\v': self->OutStream(self, 'v'); break;
2107 case '\\': self->OutStream(self, '\\'); break;
2108 default:
2109 self->OutStream(self, 'x');
2110 TrioWriteNumber(self, (trio_intmax_t)ch,
2111 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2112 2, 2, BASE_HEX);
2113 break;
2114 }
2115 }
2116 else if (ch == CHAR_BACKSLASH)
2117 {
2118 self->OutStream(self, CHAR_BACKSLASH);
2119 self->OutStream(self, CHAR_BACKSLASH);
2120 }
2121 else
2122 {
2123 self->OutStream(self, ch);
2124 }
2125 }
2126 else
2127 {
2128 self->OutStream(self, ch);
2129 }
2130}
2131
2132/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002133 * TrioWriteString
Daniel Veillard92ad2102001-03-27 12:47:33 +00002134 *
2135 * Description:
2136 * Output a string
2137 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002138TRIO_PRIVATE void
2139TrioWriteString(trio_class_t *self,
2140 TRIO_CONST char *string,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002141 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002142 int width,
2143 int precision)
2144{
2145 int length;
2146 int ch;
2147
2148 assert(VALID(self));
2149 assert(VALID(self->OutStream));
2150
2151 if (string == NULL)
2152 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002153 string = internalNullString;
2154 length = sizeof(internalNullString) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002155 /* Disable quoting for the null pointer */
2156 flags &= (~FLAGS_QUOTE);
2157 width = 0;
2158 }
2159 else
2160 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002161 length = trio_length(string);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002162 }
2163 if ((NO_PRECISION != precision) &&
2164 (precision < length))
2165 {
2166 length = precision;
2167 }
2168 width -= length;
2169
2170 if (flags & FLAGS_QUOTE)
2171 self->OutStream(self, CHAR_QUOTE);
2172
2173 if (! (flags & FLAGS_LEFTADJUST))
2174 {
2175 while (width-- > 0)
2176 self->OutStream(self, CHAR_ADJUST);
2177 }
2178
2179 while (length-- > 0)
2180 {
2181 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002182 ch = (int)((unsigned char)(*string++));
2183 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002184 }
2185
2186 if (flags & FLAGS_LEFTADJUST)
2187 {
2188 while (width-- > 0)
2189 self->OutStream(self, CHAR_ADJUST);
2190 }
2191 if (flags & FLAGS_QUOTE)
2192 self->OutStream(self, CHAR_QUOTE);
2193}
2194
2195/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002196 * TrioWriteWideStringCharacter
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002197 *
2198 * Description:
2199 * Output a wide string as a multi-byte sequence
2200 */
2201#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002202TRIO_PRIVATE int
2203TrioWriteWideStringCharacter(trio_class_t *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002204 wchar_t wch,
2205 unsigned long flags,
2206 int width)
2207{
2208 int size;
2209 int i;
2210 int ch;
2211 char *string;
2212 char buffer[MB_LEN_MAX + 1];
2213
2214 if (width == NO_WIDTH)
2215 width = sizeof(buffer);
2216
2217 size = wctomb(buffer, wch);
2218 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2219 return 0;
2220
2221 string = buffer;
2222 i = size;
2223 while ((width >= i) && (width-- > 0) && (i-- > 0))
2224 {
2225 /* The ctype parameters must be an unsigned char (or EOF) */
2226 ch = (int)((unsigned char)(*string++));
2227 TrioWriteStringCharacter(self, ch, flags);
2228 }
2229 return size;
2230}
2231#endif /* TRIO_WIDECHAR */
2232
2233/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002234 * TrioWriteWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002235 *
2236 * Description:
2237 * Output a wide character string as a multi-byte string
2238 */
2239#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00002240TRIO_PRIVATE void
2241TrioWriteWideString(trio_class_t *self,
2242 TRIO_CONST wchar_t *wstring,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002243 unsigned long flags,
2244 int width,
2245 int precision)
2246{
2247 int length;
2248 int size;
2249
2250 assert(VALID(self));
2251 assert(VALID(self->OutStream));
2252
2253#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2254 mblen(NULL, 0);
2255#endif
2256
2257 if (wstring == NULL)
2258 {
2259 TrioWriteString(self, NULL, flags, width, precision);
2260 return;
2261 }
2262
2263 if (NO_PRECISION == precision)
2264 {
2265 length = INT_MAX;
2266 }
2267 else
2268 {
2269 length = precision;
2270 width -= length;
2271 }
2272
2273 if (flags & FLAGS_QUOTE)
2274 self->OutStream(self, CHAR_QUOTE);
2275
2276 if (! (flags & FLAGS_LEFTADJUST))
2277 {
2278 while (width-- > 0)
2279 self->OutStream(self, CHAR_ADJUST);
2280 }
2281
2282 while (length > 0)
2283 {
2284 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2285 if (size == 0)
2286 break; /* while */
2287 length -= size;
2288 }
2289
2290 if (flags & FLAGS_LEFTADJUST)
2291 {
2292 while (width-- > 0)
2293 self->OutStream(self, CHAR_ADJUST);
2294 }
2295 if (flags & FLAGS_QUOTE)
2296 self->OutStream(self, CHAR_QUOTE);
2297}
2298#endif /* TRIO_WIDECHAR */
2299
2300/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002301 * TrioWriteDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +00002302 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002303TRIO_PRIVATE void
2304TrioWriteDouble(trio_class_t *self,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002305 long double longdoubleNumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002306 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002307 int width,
2308 int precision,
2309 int base)
2310{
2311 int charsPerThousand;
2312 int length;
2313 double number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002314 double workNumber;
2315 int integerDigits;
2316 int fractionDigits;
2317 int exponentDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002318 int expectedWidth;
2319 int exponent;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002320 unsigned int uExponent = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002321 double dblBase;
2322 BOOLEAN_T isNegative;
2323 BOOLEAN_T isExponentNegative = FALSE;
2324 BOOLEAN_T isHex;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002325 TRIO_CONST char *digits;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002326 char numberBuffer[MAX_MANTISSA_DIGITS
2327 * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002328 char *numberPointer;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002329 char exponentBuffer[MAX_EXPONENT_DIGITS + 1];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002330 char *exponentPointer = NULL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002331 int groupingIndex;
2332 char *work;
2333 int i;
2334 BOOLEAN_T onlyzero;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002335 int zeroes = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002336
2337 assert(VALID(self));
2338 assert(VALID(self->OutStream));
2339 assert(base == BASE_DECIMAL || base == BASE_HEX);
2340
2341 number = (double)longdoubleNumber;
2342
Bjorn Reese70a9da52001-04-21 16:57:29 +00002343 /* Look for infinite numbers and non-a-number first */
Bjorn Reese45029602001-08-21 09:23:53 +00002344 switch (trio_isinf(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002345 {
2346 case 1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002347 /* Positive infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002348 TrioWriteString(self,
2349 (flags & FLAGS_UPPER)
2350 ? INFINITE_UPPER
2351 : INFINITE_LOWER,
2352 flags, width, precision);
2353 return;
2354
2355 case -1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002356 /* Negative infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002357 TrioWriteString(self,
2358 (flags & FLAGS_UPPER)
2359 ? "-" INFINITE_UPPER
2360 : "-" INFINITE_LOWER,
2361 flags, width, precision);
2362 return;
2363
2364 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002365 /* Finitude */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002366 break;
2367 }
Bjorn Reese45029602001-08-21 09:23:53 +00002368 if (trio_isnan(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002369 {
2370 TrioWriteString(self,
2371 (flags & FLAGS_UPPER)
2372 ? NAN_UPPER
2373 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002374 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002375 return;
2376 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002377
2378 /* Normal numbers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002379 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002380 isHex = (base == BASE_HEX);
2381 dblBase = (double)base;
2382
2383 if (precision == NO_PRECISION)
2384 precision = FLT_DIG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002385
2386 isNegative = (number < 0.0);
2387 if (isNegative)
2388 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002389
Daniel Veillard92ad2102001-03-27 12:47:33 +00002390 if ((flags & FLAGS_FLOAT_G) || isHex)
2391 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002392 if (precision == 0)
2393 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002394
2395 if ((number < 1.0e-4) || (number > pow(10.0, (double)precision)))
2396 {
2397 /* Use scientific notation */
2398 flags |= FLAGS_FLOAT_E;
2399 }
2400 else if (number < 1.0)
2401 {
2402 /*
2403 * Use normal notation. If the integer part of the number is
2404 * zero, then adjust the precision to include leading fractional
2405 * zeros.
2406 */
2407 workNumber = fabs(guarded_log10(number));
2408 if (workNumber - floor(workNumber) < 0.001)
2409 workNumber--;
2410 zeroes = (int)floor(workNumber);
2411 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002412 }
2413
2414 if (flags & FLAGS_FLOAT_E)
2415 {
2416 /* Scale the number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002417 workNumber = guarded_log10(number);
Bjorn Reese45029602001-08-21 09:23:53 +00002418 if (trio_isinf(workNumber) == -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002419 {
2420 exponent = 0;
2421 /* Undo setting */
2422 if (flags & FLAGS_FLOAT_G)
2423 flags &= ~FLAGS_FLOAT_E;
2424 }
2425 else
2426 {
2427 exponent = (int)floor(workNumber);
2428 number /= pow(10.0, (double)exponent);
2429 isExponentNegative = (exponent < 0);
2430 uExponent = (isExponentNegative) ? -exponent : exponent;
2431 /* No thousand separators */
2432 flags &= ~FLAGS_QUOTE;
2433 }
2434 }
2435
2436 /*
2437 * Truncated number.
2438 *
2439 * precision is number of significant digits for FLOAT_G
2440 * and number of fractional digits for others
2441 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002442 integerDigits = (floor(number) > DBL_EPSILON)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002443 ? 1 + (int)guarded_log10(floor(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002444 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002445 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002446 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002447 : zeroes + precision;
2448
2449 number = floor(0.5 + number * pow(dblBase, (double)fractionDigits));
2450 workNumber = (isHex
2451 ? guarded_log16(0.5 + number)
2452 : guarded_log10(0.5 + number));
2453 if ((int)workNumber + 1 > integerDigits + fractionDigits)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002454 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002455 if (flags & FLAGS_FLOAT_E)
2456 {
2457 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2458 exponent--;
2459 uExponent -= (isExponentNegative) ? 1 : -1;
2460 number /= dblBase;
2461 }
2462 else
2463 {
2464 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2465 integerDigits++;
2466 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002467 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002468
2469 /* Build the fraction part */
2470 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
2471 *numberPointer = NIL;
2472 onlyzero = TRUE;
2473 for (i = 0; i < fractionDigits; i++)
2474 {
2475 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2476 number = floor(number / dblBase);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002477
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002478 if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE))
2479 {
2480 /* Prune trailing zeroes */
2481 if (numberPointer[0] != digits[0])
2482 onlyzero = FALSE;
2483 else if (onlyzero && (numberPointer[0] == digits[0]))
2484 numberPointer++;
2485 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002486 else
2487 onlyzero = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002488 }
2489
2490 /* Insert decimal point */
2491 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
2492 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002493 i = trio_length(internalDecimalPoint);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002494 while (i> 0)
2495 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002496 *(--numberPointer) = internalDecimalPoint[--i];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002497 }
2498 }
2499 /* Insert the integer part and thousand separators */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002500 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002501 groupingIndex = 1;
2502 for (i = 1; i < integerDigits + 1; i++)
2503 {
2504 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2505 number = floor(number / dblBase);
2506 if (number < DBL_EPSILON)
2507 break;
2508
2509 if ((i > 0)
2510 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2511 && (charsPerThousand != NO_GROUPING)
2512 && (i % charsPerThousand == 0))
2513 {
2514 /*
2515 * We are building the number from the least significant
2516 * to the most significant digit, so we have to copy the
2517 * thousand separator backwards
2518 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002519 length = trio_length(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002520 integerDigits += length;
2521 if (((int)(numberPointer - numberBuffer) - length) > 0)
2522 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002523 work = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002524 while (length-- > 0)
2525 *(--numberPointer) = *work--;
2526 }
2527
2528 /* Advance to next grouping number */
2529 if (charsPerThousand != NO_GROUPING)
2530 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002531 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002532 {
2533 case CHAR_MAX: /* Disable grouping */
2534 charsPerThousand = NO_GROUPING;
2535 break;
2536 case 0: /* Repeat last group */
2537 break;
2538 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002539 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002540 break;
2541 }
2542 }
2543 }
2544 }
2545
2546 /* Build the exponent */
2547 exponentDigits = 0;
2548 if (flags & FLAGS_FLOAT_E)
2549 {
2550 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2551 *exponentPointer-- = NIL;
2552 do {
2553 *exponentPointer-- = digits[uExponent % base];
2554 uExponent /= base;
2555 exponentDigits++;
2556 } while (uExponent);
2557 }
2558
Bjorn Reese70a9da52001-04-21 16:57:29 +00002559 /*
2560 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002561 * sign + integer part + thousands separators + decimal point
2562 * + fraction + exponent
2563 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002564 expectedWidth = trio_length(numberPointer);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002565 if (isNegative || (flags & FLAGS_SHOWSIGN))
2566 expectedWidth += sizeof("-") - 1;
2567 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002568 expectedWidth += exponentDigits +
2569 ((exponentDigits > 1) ? sizeof("E+") : sizeof("E+0")) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002570 if (isHex)
2571 expectedWidth += sizeof("0X") - 1;
2572
2573 /* Output prefixing */
2574 if (flags & FLAGS_NILPADDING)
2575 {
2576 /* Leading zeros must be after sign */
2577 if (isNegative)
2578 self->OutStream(self, '-');
2579 else if (flags & FLAGS_SHOWSIGN)
2580 self->OutStream(self, '+');
2581 if (isHex)
2582 {
2583 self->OutStream(self, '0');
2584 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2585 }
2586 if (!(flags & FLAGS_LEFTADJUST))
2587 {
2588 for (i = expectedWidth; i < width; i++)
2589 {
2590 self->OutStream(self, '0');
2591 }
2592 }
2593 }
2594 else
2595 {
2596 /* Leading spaces must be before sign */
2597 if (!(flags & FLAGS_LEFTADJUST))
2598 {
2599 for (i = expectedWidth; i < width; i++)
2600 {
2601 self->OutStream(self, CHAR_ADJUST);
2602 }
2603 }
2604 if (isNegative)
2605 self->OutStream(self, '-');
2606 else if (flags & FLAGS_SHOWSIGN)
2607 self->OutStream(self, '+');
2608 if (isHex)
2609 {
2610 self->OutStream(self, '0');
2611 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2612 }
2613 }
2614 /* Output number */
2615 for (i = 0; numberPointer[i]; i++)
2616 {
2617 self->OutStream(self, numberPointer[i]);
2618 }
2619 /* Output exponent */
2620 if (exponentDigits > 0)
2621 {
2622 self->OutStream(self,
2623 isHex
2624 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2625 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2626 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002627
2628 /* The exponent must contain at least two digits */
2629 if (exponentDigits == 1)
2630 self->OutStream(self, '0');
2631
Daniel Veillard92ad2102001-03-27 12:47:33 +00002632 for (i = 0; i < exponentDigits; i++)
2633 {
2634 self->OutStream(self, exponentPointer[i + 1]);
2635 }
2636 }
2637 /* Output trailing spaces */
2638 if (flags & FLAGS_LEFTADJUST)
2639 {
2640 for (i = expectedWidth; i < width; i++)
2641 {
2642 self->OutStream(self, CHAR_ADJUST);
2643 }
2644 }
2645}
2646
2647/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002648 * TrioFormatProcess
2649 *
2650 * Description:
2651 * This is the main engine for formatting output
Daniel Veillard92ad2102001-03-27 12:47:33 +00002652 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002653TRIO_PRIVATE int
2654TrioFormatProcess(trio_class_t *data,
2655 TRIO_CONST char *format,
2656 trio_parameter_t *parameters)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002657
Daniel Veillard92ad2102001-03-27 12:47:33 +00002658{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002659#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002660 int charlen;
2661#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00002662 int i;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002663 TRIO_CONST char *string;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002664 void *pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002665 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002666 int width;
2667 int precision;
2668 int base;
2669 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002670
Daniel Veillard92ad2102001-03-27 12:47:33 +00002671 index = 0;
2672 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002673#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002674 mblen(NULL, 0);
2675#endif
2676
2677 while (format[index])
2678 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002679#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002680 if (! isascii(format[index]))
2681 {
2682 charlen = mblen(&format[index], MB_LEN_MAX);
2683 while (charlen-- > 0)
2684 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002685 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002686 }
2687 continue; /* while */
2688 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002689#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002690 if (CHAR_IDENTIFIER == format[index])
2691 {
2692 if (CHAR_IDENTIFIER == format[index + 1])
2693 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002694 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002695 index += 2;
2696 }
2697 else
2698 {
2699 /* Skip the parameter entries */
2700 while (parameters[i].type == FORMAT_PARAMETER)
2701 i++;
2702
2703 flags = parameters[i].flags;
2704
2705 /* Find width */
2706 width = parameters[i].width;
2707 if (flags & FLAGS_WIDTH_PARAMETER)
2708 {
2709 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002710 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002711 }
2712
2713 /* Find precision */
2714 if (flags & FLAGS_PRECISION)
2715 {
2716 precision = parameters[i].precision;
2717 if (flags & FLAGS_PRECISION_PARAMETER)
2718 {
2719 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002720 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002721 }
2722 }
2723 else
2724 {
2725 precision = NO_PRECISION;
2726 }
2727
2728 /* Find base */
2729 base = parameters[i].base;
2730 if (flags & FLAGS_BASE_PARAMETER)
2731 {
2732 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002733 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002734 }
2735
2736 switch (parameters[i].type)
2737 {
2738 case FORMAT_CHAR:
2739 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002740 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002741 if (! (flags & FLAGS_LEFTADJUST))
2742 {
2743 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002744 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002745 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002746#if TRIO_WIDECHAR
2747 if (flags & FLAGS_WIDECHAR)
2748 {
2749 TrioWriteWideStringCharacter(data,
2750 (wchar_t)parameters[i].data.number.as_signed,
2751 flags,
2752 NO_WIDTH);
2753 }
2754 else
2755#endif
Bjorn Reese026d29f2002-01-19 15:40:18 +00002756 {
2757 TrioWriteStringCharacter(data,
2758 (int)parameters[i].data.number.as_signed,
2759 flags);
2760 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002761
2762 if (flags & FLAGS_LEFTADJUST)
2763 {
2764 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002765 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002766 }
2767 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002768 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002769
2770 break; /* FORMAT_CHAR */
2771
2772 case FORMAT_INT:
2773 if (base == NO_BASE)
2774 base = BASE_DECIMAL;
2775
2776 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002777 parameters[i].data.number.as_signed,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002778 flags,
2779 width,
2780 precision,
2781 base);
2782
2783 break; /* FORMAT_INT */
2784
2785 case FORMAT_DOUBLE:
2786 TrioWriteDouble(data,
2787 parameters[i].data.longdoubleNumber,
2788 flags,
2789 width,
2790 precision,
2791 base);
2792 break; /* FORMAT_DOUBLE */
2793
2794 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002795#if TRIO_WIDECHAR
2796 if (flags & FLAGS_WIDECHAR)
2797 {
2798 TrioWriteWideString(data,
2799 parameters[i].data.wstring,
2800 flags,
2801 width,
2802 precision);
2803 }
2804 else
2805#endif
2806 {
2807 TrioWriteString(data,
2808 parameters[i].data.string,
2809 flags,
2810 width,
2811 precision);
2812 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002813 break; /* FORMAT_STRING */
2814
2815 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002816 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002817 trio_reference_t reference;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002818
2819 reference.data = data;
2820 reference.parameter = &parameters[i];
2821 trio_print_pointer(&reference, parameters[i].data.pointer);
2822 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002823 break; /* FORMAT_POINTER */
2824
2825 case FORMAT_COUNT:
2826 pointer = parameters[i].data.pointer;
2827 if (NULL != pointer)
2828 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002829 /*
2830 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00002831 * characters written to the output stream so far by
2832 * this call", which is data->committed
2833 */
2834#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2835 if (flags & FLAGS_SIZE_T)
2836 *(size_t *)pointer = (size_t)data->committed;
2837 else
2838#endif
2839#if defined(QUALIFIER_PTRDIFF_T)
2840 if (flags & FLAGS_PTRDIFF_T)
2841 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2842 else
2843#endif
2844#if defined(QUALIFIER_INTMAX_T)
2845 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002846 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002847 else
2848#endif
2849 if (flags & FLAGS_QUAD)
2850 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002851 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002852 }
2853 else if (flags & FLAGS_LONG)
2854 {
2855 *(long int *)pointer = (long int)data->committed;
2856 }
2857 else if (flags & FLAGS_SHORT)
2858 {
2859 *(short int *)pointer = (short int)data->committed;
2860 }
2861 else
2862 {
2863 *(int *)pointer = (int)data->committed;
2864 }
2865 }
2866 break; /* FORMAT_COUNT */
2867
2868 case FORMAT_PARAMETER:
2869 break; /* FORMAT_PARAMETER */
2870
2871#if defined(FORMAT_ERRNO)
2872 case FORMAT_ERRNO:
Bjorn Reese026d29f2002-01-19 15:40:18 +00002873 string = trio_error(parameters[i].data.errorNumber);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 if (string)
2875 {
2876 TrioWriteString(data,
2877 string,
2878 flags,
2879 width,
2880 precision);
2881 }
2882 else
2883 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002884 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002885 TrioWriteNumber(data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002886 (trio_intmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002887 flags,
2888 width,
2889 precision,
2890 BASE_DECIMAL);
2891 }
2892 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002893#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002894
Bjorn Reese70a9da52001-04-21 16:57:29 +00002895#if defined(FORMAT_USER_DEFINED)
2896 case FORMAT_USER_DEFINED:
2897 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00002898 trio_reference_t reference;
2899 trio_userdef_t *def = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002900
2901 if (parameters[i].user_name[0] == NIL)
2902 {
2903 /* Use handle */
2904 if ((i > 0) ||
2905 (parameters[i - 1].type == FORMAT_PARAMETER))
Bjorn Reese026d29f2002-01-19 15:40:18 +00002906 def = (trio_userdef_t *)parameters[i - 1].data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002907 }
2908 else
2909 {
2910 /* Look up namespace */
2911 def = TrioFindNamespace(parameters[i].user_name, NULL);
2912 }
2913 if (def) {
2914 reference.data = data;
2915 reference.parameter = &parameters[i];
2916 def->callback(&reference);
2917 }
2918 }
2919 break;
2920#endif /* defined(FORMAT_USER_DEFINED) */
2921
Daniel Veillard92ad2102001-03-27 12:47:33 +00002922 default:
2923 break;
2924 } /* switch parameter type */
2925
2926 /* Prepare for next */
2927 index = parameters[i].indexAfterSpecifier;
2928 i++;
2929 }
2930 }
2931 else /* not identifier */
2932 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002933 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002934 }
2935 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002936 return data->processed;
2937}
2938
2939/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002940 * TrioFormatRef
Bjorn Reese70a9da52001-04-21 16:57:29 +00002941 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002942TRIO_PRIVATE int
2943TrioFormatRef(trio_reference_t *reference,
2944 TRIO_CONST char *format,
2945 va_list arglist,
2946 void **argarray)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002947{
2948 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002949 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002950
Bjorn Reese026d29f2002-01-19 15:40:18 +00002951 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002952 if (status < 0)
2953 return status;
2954
Bjorn Reese026d29f2002-01-19 15:40:18 +00002955 status = TrioFormatProcess(reference->data, format, parameters);
2956 if (reference->data->error != 0)
2957 {
2958 status = reference->data->error;
2959 }
2960 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002961}
2962
2963/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00002964 * TrioFormat
Bjorn Reese70a9da52001-04-21 16:57:29 +00002965 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00002966TRIO_PRIVATE int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002967TrioFormat(void *destination,
2968 size_t destinationSize,
Bjorn Reese026d29f2002-01-19 15:40:18 +00002969 void (*OutStream)(trio_class_t *, int),
2970 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002971 va_list arglist,
2972 void **argarray)
2973{
2974 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002975 trio_class_t data;
2976 trio_parameter_t parameters[MAX_PARAMETERS];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002977
2978 assert(VALID(OutStream));
2979 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002980
2981 memset(&data, 0, sizeof(data));
2982 data.OutStream = OutStream;
2983 data.location = destination;
2984 data.max = destinationSize;
Bjorn Reese026d29f2002-01-19 15:40:18 +00002985 data.error = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002986
2987#if defined(USE_LOCALE)
2988 if (NULL == internalLocaleValues)
2989 {
2990 TrioSetLocale();
2991 }
2992#endif
2993
Bjorn Reese026d29f2002-01-19 15:40:18 +00002994 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002995 if (status < 0)
2996 return status;
2997
Bjorn Reese026d29f2002-01-19 15:40:18 +00002998 status = TrioFormatProcess(&data, format, parameters);
2999 if (data.error != 0)
3000 {
3001 status = data.error;
3002 }
3003 return status;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003004}
3005
3006/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003007 * TrioOutStreamFile
Daniel Veillard92ad2102001-03-27 12:47:33 +00003008 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003009TRIO_PRIVATE void
3010TrioOutStreamFile(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003011 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003012{
3013 FILE *file = (FILE *)self->location;
3014
3015 assert(VALID(self));
3016 assert(VALID(file));
3017
3018 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003019 if (fputc(output, file) == EOF)
3020 {
3021 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3022 }
3023 else
3024 {
3025 self->committed++;
3026 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003027}
3028
3029/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003030 * TrioOutStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00003031 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003032TRIO_PRIVATE void
3033TrioOutStreamFileDescriptor(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003034 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003035{
3036 int fd = *((int *)self->location);
3037 char ch;
3038
3039 assert(VALID(self));
3040
3041 ch = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003042 self->processed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003043 if (write(fd, &ch, sizeof(char)) == -1)
3044 {
3045 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3046 }
3047 else
3048 {
3049 self->committed++;
3050 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00003051}
3052
3053/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003054 * TrioOutStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00003055 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003056TRIO_PRIVATE void
3057TrioOutStreamString(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003058 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003059{
3060 char **buffer = (char **)self->location;
3061
3062 assert(VALID(self));
3063 assert(VALID(buffer));
3064
3065 **buffer = (char)output;
3066 (*buffer)++;
3067 self->processed++;
3068 self->committed++;
3069}
3070
3071/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003072 * TrioOutStreamStringMax
Daniel Veillard92ad2102001-03-27 12:47:33 +00003073 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003074TRIO_PRIVATE void
3075TrioOutStreamStringMax(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003076 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003077{
3078 char **buffer;
3079
3080 assert(VALID(self));
3081 buffer = (char **)self->location;
3082 assert(VALID(buffer));
3083
3084 if (self->processed < self->max)
3085 {
3086 **buffer = (char)output;
3087 (*buffer)++;
3088 self->committed++;
3089 }
3090 self->processed++;
3091}
3092
3093/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003094 * TrioOutStreamStringDynamic
Daniel Veillard92ad2102001-03-27 12:47:33 +00003095 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003096TRIO_PRIVATE void
3097TrioOutStreamStringDynamic(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003098 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003099{
Daniel Veillard92ad2102001-03-27 12:47:33 +00003100 assert(VALID(self));
3101 assert(VALID(self->location));
3102
Bjorn Reese026d29f2002-01-19 15:40:18 +00003103 if (self->error == 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003104 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003105 trio_xstring_append_char((trio_string_t *)self->location,
3106 (char)output);
3107 self->committed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003108 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003109 /* The processed variable must always be increased */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003110 self->processed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003111}
3112
Daniel Veillard92ad2102001-03-27 12:47:33 +00003113/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003114 *
3115 * Formatted printing functions
3116 *
3117 ************************************************************************/
3118
3119#if defined(TRIO_DOCUMENTATION)
3120# include "doc/doc_printf.h"
3121#endif
3122/** @addtogroup Printf
3123 @{
3124*/
3125
3126/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003127 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003128 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003129
3130/**
3131 Print to standard output stream.
3132
3133 @param format Formatting string.
3134 @param ... Arguments.
3135 @return Number of printed characters.
3136 */
3137TRIO_PUBLIC int
3138trio_printf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003139 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003140{
3141 int status;
3142 va_list args;
3143
3144 assert(VALID(format));
3145
3146 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003147 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003148 va_end(args);
3149 return status;
3150}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003151
Bjorn Reese026d29f2002-01-19 15:40:18 +00003152/**
3153 Print to standard output stream.
3154
3155 @param format Formatting string.
3156 @param args Arguments.
3157 @return Number of printed characters.
3158 */
3159TRIO_PUBLIC int
3160trio_vprintf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003161 va_list args)
3162{
3163 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003164
3165 return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
3166}
3167
Bjorn Reese026d29f2002-01-19 15:40:18 +00003168/**
3169 Print to standard output stream.
3170
3171 @param format Formatting string.
3172 @param args Arguments.
3173 @return Number of printed characters.
3174 */
3175TRIO_PUBLIC int
3176trio_printfv(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003177 void ** args)
3178{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003179 va_list dummy;
3180
Bjorn Reese70a9da52001-04-21 16:57:29 +00003181 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003182
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003183 return TrioFormat(stdout, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003184}
3185
Daniel Veillard92ad2102001-03-27 12:47:33 +00003186/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003187 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003188 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003189
3190/**
3191 Print to file.
3192
3193 @param file File pointer.
3194 @param format Formatting string.
3195 @param ... Arguments.
3196 @return Number of printed characters.
3197 */
3198TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003199trio_fprintf(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003200 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003201 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003202{
3203 int status;
3204 va_list args;
3205
3206 assert(VALID(file));
3207 assert(VALID(format));
3208
3209 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003210 status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003211 va_end(args);
3212 return status;
3213}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003214
Bjorn Reese026d29f2002-01-19 15:40:18 +00003215/**
3216 Print to file.
3217
3218 @param file File pointer.
3219 @param format Formatting string.
3220 @param args Arguments.
3221 @return Number of printed characters.
3222 */
3223TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003224trio_vfprintf(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003225 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003226 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003227{
3228 assert(VALID(file));
3229 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003230
Bjorn Reese70a9da52001-04-21 16:57:29 +00003231 return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003232}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003233
Bjorn Reese026d29f2002-01-19 15:40:18 +00003234/**
3235 Print to file.
3236
3237 @param file File pointer.
3238 @param format Formatting string.
3239 @param args Arguments.
3240 @return Number of printed characters.
3241 */
3242TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003243trio_fprintfv(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003244 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003245 void ** args)
3246{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003247 va_list dummy;
3248
Bjorn Reese70a9da52001-04-21 16:57:29 +00003249 assert(VALID(file));
3250 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003251
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003252 return TrioFormat(file, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003253}
3254
Daniel Veillard92ad2102001-03-27 12:47:33 +00003255/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003256 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003257 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003258
3259/**
3260 Print to file descriptor.
3261
3262 @param fd File descriptor.
3263 @param format Formatting string.
3264 @param ... Arguments.
3265 @return Number of printed characters.
3266 */
3267TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003268trio_dprintf(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003269 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003270 ...)
3271{
3272 int status;
3273 va_list args;
3274
3275 assert(VALID(format));
3276
3277 va_start(args, format);
3278 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3279 va_end(args);
3280 return status;
3281}
3282
Bjorn Reese026d29f2002-01-19 15:40:18 +00003283/**
3284 Print to file descriptor.
3285
3286 @param fd File descriptor.
3287 @param format Formatting string.
3288 @param args Arguments.
3289 @return Number of printed characters.
3290 */
3291TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003292trio_vdprintf(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003293 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003294 va_list args)
3295{
3296 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003297
3298 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3299}
3300
Bjorn Reese026d29f2002-01-19 15:40:18 +00003301/**
3302 Print to file descriptor.
3303
3304 @param fd File descriptor.
3305 @param format Formatting string.
3306 @param args Arguments.
3307 @return Number of printed characters.
3308 */
3309TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003310trio_dprintfv(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003311 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003312 void **args)
3313{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003314 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003315
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003316 assert(VALID(format));
3317
3318 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003319}
3320
3321/*************************************************************************
3322 * sprintf
3323 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003324
3325/**
3326 Print to string.
3327
3328 @param buffer Output string.
3329 @param format Formatting string.
3330 @param ... Arguments.
3331 @return Number of printed characters.
3332 */
3333TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003334trio_sprintf(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003335 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003336 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003337{
3338 int status;
3339 va_list args;
3340
3341 assert(VALID(buffer));
3342 assert(VALID(format));
3343
3344 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003345 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003346 *buffer = NIL; /* Terminate with NIL character */
3347 va_end(args);
3348 return status;
3349}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003350
Bjorn Reese026d29f2002-01-19 15:40:18 +00003351/**
3352 Print to string.
3353
3354 @param buffer Output string.
3355 @param format Formatting string.
3356 @param args Arguments.
3357 @return Number of printed characters.
3358 */
3359TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003360trio_vsprintf(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003361 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003362 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003363{
3364 int status;
3365
3366 assert(VALID(buffer));
3367 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003368
Bjorn Reese70a9da52001-04-21 16:57:29 +00003369 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003370 *buffer = NIL;
3371 return status;
3372}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003373
Bjorn Reese026d29f2002-01-19 15:40:18 +00003374/**
3375 Print to string.
3376
3377 @param buffer Output string.
3378 @param format Formatting string.
3379 @param args Arguments.
3380 @return Number of printed characters.
3381 */
3382TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003383trio_sprintfv(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003384 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003385 void **args)
3386{
3387 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003388 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003389
3390 assert(VALID(buffer));
3391 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003392
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003393 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003394 *buffer = NIL;
3395 return status;
3396}
3397
Daniel Veillard92ad2102001-03-27 12:47:33 +00003398/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003399 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003400 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003401
3402/**
3403 Print at most @p max characters to string.
3404
3405 @param buffer Output string.
3406 @param max Maximum number of characters to print.
3407 @param format Formatting string.
3408 @param ... Arguments.
3409 @return Number of printed characters.
3410 */
3411TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003412trio_snprintf(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003413 size_t max,
3414 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003415 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003416{
3417 int status;
3418 va_list args;
3419
3420 assert(VALID(buffer));
3421 assert(VALID(format));
3422
3423 va_start(args, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003424 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003425 TrioOutStreamStringMax, format, args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003426 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003427 *buffer = NIL;
3428 va_end(args);
3429 return status;
3430}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003431
Bjorn Reese026d29f2002-01-19 15:40:18 +00003432/**
3433 Print at most @p max characters to string.
3434
3435 @param buffer Output string.
3436 @param max Maximum number of characters to print.
3437 @param format Formatting string.
3438 @param args Arguments.
3439 @return Number of printed characters.
3440 */
3441TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003442trio_vsnprintf(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003443 size_t max,
3444 TRIO_CONST char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003445 va_list args)
3446{
3447 int status;
3448
3449 assert(VALID(buffer));
3450 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003451
Bjorn Reese026d29f2002-01-19 15:40:18 +00003452 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003453 TrioOutStreamStringMax, format, args, NULL);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003454 if (max > 0)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003455 *buffer = NIL;
3456 return status;
3457}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003458
Bjorn Reese026d29f2002-01-19 15:40:18 +00003459/**
3460 Print at most @p max characters to string.
3461
3462 @param buffer Output string.
3463 @param max Maximum number of characters to print.
3464 @param format Formatting string.
3465 @param args Arguments.
3466 @return Number of printed characters.
3467 */
3468TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003469trio_snprintfv(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003470 size_t max,
3471 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003472 void **args)
3473{
3474 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003475 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003476
3477 assert(VALID(buffer));
3478 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003479
Bjorn Reese026d29f2002-01-19 15:40:18 +00003480 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003481 TrioOutStreamStringMax, format, dummy, args);
Bjorn Reese026d29f2002-01-19 15:40:18 +00003482 if (max > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003483 *buffer = NIL;
3484 return status;
3485}
3486
3487/*************************************************************************
3488 * snprintfcat
3489 * Appends the new string to the buffer string overwriting the '\0'
3490 * character at the end of buffer.
3491 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003492TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003493trio_snprintfcat(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003494 size_t max,
3495 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003496 ...)
3497{
3498 int status;
3499 va_list args;
3500 size_t buf_len;
3501
3502 va_start(args, format);
3503
3504 assert(VALID(buffer));
3505 assert(VALID(format));
3506
Bjorn Reese026d29f2002-01-19 15:40:18 +00003507 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003508 buffer = &buffer[buf_len];
3509
Bjorn Reese026d29f2002-01-19 15:40:18 +00003510 status = TrioFormat(&buffer, max - 1 - buf_len,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003511 TrioOutStreamStringMax, format, args, NULL);
3512 va_end(args);
3513 *buffer = NIL;
3514 return status;
3515}
3516
Bjorn Reese026d29f2002-01-19 15:40:18 +00003517TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003518trio_vsnprintfcat(char *buffer,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003519 size_t max,
3520 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003521 va_list args)
3522{
3523 int status;
3524 size_t buf_len;
3525 assert(VALID(buffer));
3526 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003527
Bjorn Reese026d29f2002-01-19 15:40:18 +00003528 buf_len = trio_length(buffer);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003529 buffer = &buffer[buf_len];
Bjorn Reese026d29f2002-01-19 15:40:18 +00003530 status = TrioFormat(&buffer, max - 1 - buf_len,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003531 TrioOutStreamStringMax, format, args, NULL);
3532 *buffer = NIL;
3533 return status;
3534}
3535
3536/*************************************************************************
3537 * trio_aprintf
3538 */
3539
3540/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003541TRIO_PUBLIC char *
3542trio_aprintf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003543 ...)
3544{
3545 va_list args;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003546 trio_string_t *info;
3547 char *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003548
3549 assert(VALID(format));
3550
Bjorn Reese026d29f2002-01-19 15:40:18 +00003551 info = trio_xstring_duplicate("");
3552 if (info)
3553 {
3554 va_start(args, format);
3555 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
3556 format, args, NULL);
3557 va_end(args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003558
Bjorn Reese026d29f2002-01-19 15:40:18 +00003559 trio_string_terminate(info);
3560 result = trio_string_extract(info);
3561 trio_string_destroy(info);
3562 }
3563 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003564}
3565
3566/* Deprecated */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003567TRIO_PUBLIC char *
3568trio_vaprintf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003569 va_list args)
3570{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003571 trio_string_t *info;
3572 char *result = NULL;
3573
Bjorn Reese70a9da52001-04-21 16:57:29 +00003574 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003575
Bjorn Reese026d29f2002-01-19 15:40:18 +00003576 info = trio_xstring_duplicate("");
3577 if (info)
3578 {
3579 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
3580 format, args, NULL);
3581 trio_string_terminate(info);
3582 result = trio_string_extract(info);
3583 trio_string_destroy(info);
3584 }
3585 return result;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003586}
3587
Bjorn Reese026d29f2002-01-19 15:40:18 +00003588TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003589trio_asprintf(char **result,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003590 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003591 ...)
3592{
3593 va_list args;
3594 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003595 trio_string_t *info;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003596
3597 assert(VALID(format));
3598
Bjorn Reese026d29f2002-01-19 15:40:18 +00003599 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003600
Bjorn Reese026d29f2002-01-19 15:40:18 +00003601 info = trio_xstring_duplicate("");
3602 if (info == NULL)
3603 {
3604 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3605 }
3606 else
3607 {
3608 va_start(args, format);
3609 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
3610 format, args, NULL);
3611 va_end(args);
3612 if (status >= 0)
3613 {
3614 trio_string_terminate(info);
3615 *result = trio_string_extract(info);
3616 }
3617 trio_string_destroy(info);
3618 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003619 return status;
3620}
3621
Bjorn Reese026d29f2002-01-19 15:40:18 +00003622TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003623trio_vasprintf(char **result,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003624 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003625 va_list args)
3626{
3627 int status;
Bjorn Reese026d29f2002-01-19 15:40:18 +00003628 trio_string_t *info;
3629
Bjorn Reese70a9da52001-04-21 16:57:29 +00003630 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003631
Bjorn Reese026d29f2002-01-19 15:40:18 +00003632 *result = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003633
Bjorn Reese026d29f2002-01-19 15:40:18 +00003634 info = trio_xstring_duplicate("");
3635 if (info == NULL)
3636 {
3637 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3638 }
3639 else
3640 {
3641 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
3642 format, args, NULL);
3643 if (status >= 0)
3644 {
3645 trio_string_terminate(info);
3646 *result = trio_string_extract(info);
3647 }
3648 trio_string_destroy(info);
3649 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003650 return status;
3651}
3652
Bjorn Reese026d29f2002-01-19 15:40:18 +00003653/** @} End of Printf documentation module */
Daniel Veillard92ad2102001-03-27 12:47:33 +00003654
3655/*************************************************************************
3656 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00003657 * CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00003658 *
3659 ************************************************************************/
3660
Bjorn Reese70a9da52001-04-21 16:57:29 +00003661
Bjorn Reese026d29f2002-01-19 15:40:18 +00003662#if defined(TRIO_DOCUMENTATION)
3663# include "doc/doc_register.h"
3664#endif
3665/**
3666 @addtogroup UserDefined
3667 @{
3668*/
3669
Bjorn Reese70a9da52001-04-21 16:57:29 +00003670/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00003671 * trio_register
Bjorn Reese70a9da52001-04-21 16:57:29 +00003672 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003673
3674/**
3675 Register new user-defined specifier.
3676
3677 @param callback
3678 @param name
3679 @return Handle.
3680 */
3681TRIO_PUBLIC void *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003682trio_register(trio_callback_t callback,
Bjorn Reese026d29f2002-01-19 15:40:18 +00003683 TRIO_CONST char *name)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003684{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003685 trio_userdef_t *def;
3686 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003687
3688 if (callback == NULL)
3689 return NULL;
3690
3691 if (name)
3692 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003693 /* Handle built-in namespaces */
3694 if (name[0] == ':')
3695 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00003696 if (trio_equal(name, ":enter"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003697 {
3698 internalEnterCriticalRegion = callback;
3699 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003700 else if (trio_equal(name, ":leave"))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003701 {
3702 internalLeaveCriticalRegion = callback;
3703 }
3704 return NULL;
3705 }
3706
Bjorn Reese70a9da52001-04-21 16:57:29 +00003707 /* Bail out if namespace is too long */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003708 if (trio_length(name) >= MAX_USER_NAME)
Bjorn Reese70a9da52001-04-21 16:57:29 +00003709 return NULL;
3710
3711 /* Bail out if namespace already is registered */
3712 def = TrioFindNamespace(name, &prev);
3713 if (def)
3714 return NULL;
3715 }
3716
Bjorn Reese026d29f2002-01-19 15:40:18 +00003717 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003718 if (def)
3719 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003720 if (internalEnterCriticalRegion)
3721 (void)internalEnterCriticalRegion(NULL);
3722
Bjorn Reese70a9da52001-04-21 16:57:29 +00003723 if (name)
3724 {
3725 /* Link into internal list */
3726 if (prev == NULL)
3727 internalUserDef = def;
3728 else
3729 prev->next = def;
3730 }
3731 /* Initialize */
3732 def->callback = callback;
3733 def->name = (name == NULL)
3734 ? NULL
Bjorn Reese026d29f2002-01-19 15:40:18 +00003735 : trio_duplicate(name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003736 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003737
3738 if (internalLeaveCriticalRegion)
3739 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003740 }
3741 return def;
3742}
3743
3744/*************************************************************************
3745 * trio_unregister [public]
3746 */
3747void
3748trio_unregister(void *handle)
3749{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003750 trio_userdef_t *self = (trio_userdef_t *)handle;
3751 trio_userdef_t *def;
3752 trio_userdef_t *prev = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003753
3754 assert(VALID(self));
3755
3756 if (self->name)
3757 {
3758 def = TrioFindNamespace(self->name, &prev);
3759 if (def)
3760 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003761 if (internalEnterCriticalRegion)
3762 (void)internalEnterCriticalRegion(NULL);
3763
Bjorn Reese70a9da52001-04-21 16:57:29 +00003764 if (prev == NULL)
3765 internalUserDef = NULL;
3766 else
3767 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003768
3769 if (internalLeaveCriticalRegion)
3770 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003771 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00003772 trio_destroy(self->name);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003773 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003774 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003775}
3776
3777/*************************************************************************
3778 * trio_get_format [public]
3779 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00003780TRIO_CONST char *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003781trio_get_format(void *ref)
3782{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003783 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003784
Bjorn Reese026d29f2002-01-19 15:40:18 +00003785 return (((trio_reference_t *)ref)->parameter->user_data);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003786}
3787
3788/*************************************************************************
3789 * trio_get_argument [public]
3790 */
3791void *
3792trio_get_argument(void *ref)
3793{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003794 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003795
Bjorn Reese026d29f2002-01-19 15:40:18 +00003796 return ((trio_reference_t *)ref)->parameter->data.pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003797}
3798
3799/*************************************************************************
3800 * trio_get_width / trio_set_width [public]
3801 */
3802int
3803trio_get_width(void *ref)
3804{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003805 return ((trio_reference_t *)ref)->parameter->width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003806}
3807
3808void
3809trio_set_width(void *ref,
3810 int width)
3811{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003812 ((trio_reference_t *)ref)->parameter->width = width;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003813}
3814
3815/*************************************************************************
3816 * trio_get_precision / trio_set_precision [public]
3817 */
3818int
3819trio_get_precision(void *ref)
3820{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003821 return (((trio_reference_t *)ref)->parameter->precision);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003822}
3823
3824void
3825trio_set_precision(void *ref,
3826 int precision)
3827{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003828 ((trio_reference_t *)ref)->parameter->precision = precision;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003829}
3830
3831/*************************************************************************
3832 * trio_get_base / trio_set_base [public]
3833 */
3834int
3835trio_get_base(void *ref)
3836{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003837 return (((trio_reference_t *)ref)->parameter->base);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003838}
3839
3840void
3841trio_set_base(void *ref,
3842 int base)
3843{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003844 ((trio_reference_t *)ref)->parameter->base = base;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003845}
3846
3847/*************************************************************************
3848 * trio_get_long / trio_set_long [public]
3849 */
3850int
3851trio_get_long(void *ref)
3852{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003853 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003854}
3855
3856void
3857trio_set_long(void *ref,
3858 int is_long)
3859{
3860 if (is_long)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003861 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003862 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003863 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003864}
3865
3866/*************************************************************************
3867 * trio_get_longlong / trio_set_longlong [public]
3868 */
3869int
3870trio_get_longlong(void *ref)
3871{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003872 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003873}
3874
3875void
3876trio_set_longlong(void *ref,
3877 int is_longlong)
3878{
3879 if (is_longlong)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003880 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003881 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003882 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003883}
3884
3885/*************************************************************************
3886 * trio_get_longdouble / trio_set_longdouble [public]
3887 */
3888int
3889trio_get_longdouble(void *ref)
3890{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003891 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003892}
3893
3894void
3895trio_set_longdouble(void *ref,
3896 int is_longdouble)
3897{
3898 if (is_longdouble)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003899 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003900 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003901 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003902}
3903
3904/*************************************************************************
3905 * trio_get_short / trio_set_short [public]
3906 */
3907int
3908trio_get_short(void *ref)
3909{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003910 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003911}
3912
3913void
3914trio_set_short(void *ref,
3915 int is_short)
3916{
3917 if (is_short)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003918 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003919 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003920 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003921}
3922
3923/*************************************************************************
3924 * trio_get_shortshort / trio_set_shortshort [public]
3925 */
3926int
3927trio_get_shortshort(void *ref)
3928{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003929 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003930}
3931
3932void
3933trio_set_shortshort(void *ref,
3934 int is_shortshort)
3935{
3936 if (is_shortshort)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003937 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003938 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003939 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003940}
3941
3942/*************************************************************************
3943 * trio_get_alternative / trio_set_alternative [public]
3944 */
3945int
3946trio_get_alternative(void *ref)
3947{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003948 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003949}
3950
3951void
3952trio_set_alternative(void *ref,
3953 int is_alternative)
3954{
3955 if (is_alternative)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003956 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003957 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003958 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003959}
3960
3961/*************************************************************************
3962 * trio_get_alignment / trio_set_alignment [public]
3963 */
3964int
3965trio_get_alignment(void *ref)
3966{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003967 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003968}
3969
3970void
3971trio_set_alignment(void *ref,
3972 int is_leftaligned)
3973{
3974 if (is_leftaligned)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003975 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003976 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003977 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003978}
3979
3980/*************************************************************************
3981 * trio_get_spacing /trio_set_spacing [public]
3982 */
3983int
3984trio_get_spacing(void *ref)
3985{
Bjorn Reese026d29f2002-01-19 15:40:18 +00003986 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003987}
3988
3989void
3990trio_set_spacing(void *ref,
3991 int is_space)
3992{
3993 if (is_space)
Bjorn Reese026d29f2002-01-19 15:40:18 +00003994 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003995 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00003996 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003997}
3998
3999/*************************************************************************
4000 * trio_get_sign / trio_set_sign [public]
4001 */
4002int
4003trio_get_sign(void *ref)
4004{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004005 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004006}
4007
4008void
4009trio_set_sign(void *ref,
4010 int is_sign)
4011{
4012 if (is_sign)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004013 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004014 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004015 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004016}
4017
4018/*************************************************************************
4019 * trio_get_padding / trio_set_padding [public]
4020 */
4021int
4022trio_get_padding(void *ref)
4023{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004024 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004025}
4026
4027void
4028trio_set_padding(void *ref,
4029 int is_padding)
4030{
4031 if (is_padding)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004032 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004033 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004034 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004035}
4036
4037/*************************************************************************
4038 * trio_get_quote / trio_set_quote [public]
4039 */
4040int
4041trio_get_quote(void *ref)
4042{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004043 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004044}
4045
4046void
4047trio_set_quote(void *ref,
4048 int is_quote)
4049{
4050 if (is_quote)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004051 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004052 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004053 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004054}
4055
4056/*************************************************************************
4057 * trio_get_upper / trio_set_upper [public]
4058 */
4059int
4060trio_get_upper(void *ref)
4061{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004062 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004063}
4064
4065void
4066trio_set_upper(void *ref,
4067 int is_upper)
4068{
4069 if (is_upper)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004070 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004071 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004072 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004073}
4074
4075/*************************************************************************
4076 * trio_get_largest / trio_set_largest [public]
4077 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004078#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004079int
4080trio_get_largest(void *ref)
4081{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004082 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004083}
4084
4085void
4086trio_set_largest(void *ref,
4087 int is_largest)
4088{
4089 if (is_largest)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004090 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004091 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004092 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004093}
4094#endif
4095
4096/*************************************************************************
4097 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4098 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004099int
4100trio_get_ptrdiff(void *ref)
4101{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004102 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004103}
4104
4105void
4106trio_set_ptrdiff(void *ref,
4107 int is_ptrdiff)
4108{
4109 if (is_ptrdiff)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004110 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004111 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004112 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004113}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004114
4115/*************************************************************************
4116 * trio_get_size / trio_set_size [public]
4117 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004118#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004119int
4120trio_get_size(void *ref)
4121{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004122 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004123}
4124
4125void
4126trio_set_size(void *ref,
4127 int is_size)
4128{
4129 if (is_size)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004130 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004131 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00004132 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004133}
4134#endif
4135
4136/*************************************************************************
4137 * trio_print_int [public]
4138 */
4139void
4140trio_print_int(void *ref,
4141 int number)
4142{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004143 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004144
4145 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004146 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004147 self->parameter->flags,
4148 self->parameter->width,
4149 self->parameter->precision,
4150 self->parameter->base);
4151}
4152
4153/*************************************************************************
4154 * trio_print_uint [public]
4155 */
4156void
4157trio_print_uint(void *ref,
4158 unsigned int number)
4159{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004160 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004161
4162 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004163 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004164 self->parameter->flags | FLAGS_UNSIGNED,
4165 self->parameter->width,
4166 self->parameter->precision,
4167 self->parameter->base);
4168}
4169
4170/*************************************************************************
4171 * trio_print_double [public]
4172 */
4173void
4174trio_print_double(void *ref,
4175 double number)
4176{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004177 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004178
4179 TrioWriteDouble(self->data,
4180 number,
4181 self->parameter->flags,
4182 self->parameter->width,
4183 self->parameter->precision,
4184 self->parameter->base);
4185}
4186
4187/*************************************************************************
4188 * trio_print_string [public]
4189 */
4190void
4191trio_print_string(void *ref,
4192 char *string)
4193{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004194 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004195
4196 TrioWriteString(self->data,
4197 string,
4198 self->parameter->flags,
4199 self->parameter->width,
4200 self->parameter->precision);
4201}
4202
4203/*************************************************************************
4204 * trio_print_pointer [public]
4205 */
4206void
4207trio_print_pointer(void *ref,
4208 void *pointer)
4209{
Bjorn Reese026d29f2002-01-19 15:40:18 +00004210 trio_reference_t *self = (trio_reference_t *)ref;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004211 unsigned long flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004212 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004213
4214 if (NULL == pointer)
4215 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004216 TRIO_CONST char *string = internalNullString;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004217 while (*string)
4218 self->data->OutStream(self->data, *string++);
4219 }
4220 else
4221 {
4222 /*
4223 * The subtraction of the null pointer is a workaround
4224 * to avoid a compiler warning. The performance overhead
4225 * is negligible (and likely to be removed by an
Bjorn Reese026d29f2002-01-19 15:40:18 +00004226 * optimising compiler). The (char *) casting is done
Bjorn Reese70a9da52001-04-21 16:57:29 +00004227 * to please ANSI C++.
4228 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004229 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004230 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004231 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004232 flags = self->parameter->flags;
4233 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4234 FLAGS_NILPADDING);
4235 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004236 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004237 flags,
4238 POINTER_WIDTH,
4239 NO_PRECISION,
4240 BASE_HEX);
4241 }
4242}
4243
4244/*************************************************************************
4245 * trio_print_ref [public]
4246 */
4247int
4248trio_print_ref(void *ref,
Bjorn Reese026d29f2002-01-19 15:40:18 +00004249 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004250 ...)
4251{
4252 int status;
4253 va_list arglist;
4254
4255 assert(VALID(format));
4256
4257 va_start(arglist, format);
Bjorn Reese026d29f2002-01-19 15:40:18 +00004258 status = TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004259 va_end(arglist);
4260 return status;
4261}
4262
4263/*************************************************************************
4264 * trio_vprint_ref [public]
4265 */
4266int
4267trio_vprint_ref(void *ref,
Bjorn Reese026d29f2002-01-19 15:40:18 +00004268 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004269 va_list arglist)
4270{
4271 assert(VALID(format));
4272
Bjorn Reese026d29f2002-01-19 15:40:18 +00004273 return TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004274}
4275
4276/*************************************************************************
4277 * trio_printv_ref [public]
4278 */
4279int
4280trio_printv_ref(void *ref,
Bjorn Reese026d29f2002-01-19 15:40:18 +00004281 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004282 void **argarray)
4283{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004284 va_list dummy;
4285
Bjorn Reese70a9da52001-04-21 16:57:29 +00004286 assert(VALID(format));
4287
Bjorn Reese026d29f2002-01-19 15:40:18 +00004288 return TrioFormatRef((trio_reference_t *)ref, format, dummy, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004289}
4290
Bjorn Reese026d29f2002-01-19 15:40:18 +00004291/** @} End of UserDefined documentation module */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004292
4293/*************************************************************************
4294 *
Bjorn Reese026d29f2002-01-19 15:40:18 +00004295 * SCANNING
Bjorn Reese70a9da52001-04-21 16:57:29 +00004296 *
4297 ************************************************************************/
4298
Daniel Veillard92ad2102001-03-27 12:47:33 +00004299
4300/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004301 * TrioSkipWhitespaces
Daniel Veillard92ad2102001-03-27 12:47:33 +00004302 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004303TRIO_PRIVATE int
4304TrioSkipWhitespaces(trio_class_t *self)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004305{
4306 int ch;
4307
4308 ch = self->current;
4309 while (isspace(ch))
4310 {
4311 self->InStream(self, &ch);
4312 }
4313 return ch;
4314}
4315
4316/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004317 * TrioGetCollation
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004318 */
4319#if TRIO_EXTENSION
Bjorn Reese026d29f2002-01-19 15:40:18 +00004320TRIO_PRIVATE void
4321TrioGetCollation(void)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004322{
4323 int i;
4324 int j;
4325 int k;
4326 char first[2];
4327 char second[2];
4328
4329 /* This is computational expensive */
4330 first[1] = NIL;
4331 second[1] = NIL;
4332 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4333 {
4334 k = 0;
4335 first[0] = (char)i;
4336 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
4337 {
4338 second[0] = (char)j;
Bjorn Reese026d29f2002-01-19 15:40:18 +00004339 if (trio_equal_locale(first, second))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004340 internalCollationArray[i][k++] = (char)j;
4341 }
4342 internalCollationArray[i][k] = NIL;
4343 }
4344}
4345#endif
4346
4347/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004348 * TrioGetCharacterClass
Daniel Veillard92ad2102001-03-27 12:47:33 +00004349 *
4350 * FIXME:
4351 * multibyte
4352 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004353TRIO_PRIVATE int
4354TrioGetCharacterClass(TRIO_CONST char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004355 int *indexPointer,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004356 unsigned long *flagsPointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004357 int *characterclass)
4358{
4359 int index = *indexPointer;
4360 int i;
4361 char ch;
4362 char range_begin;
4363 char range_end;
4364
4365 *flagsPointer &= ~FLAGS_EXCLUDE;
4366
4367 if (format[index] == QUALIFIER_CIRCUMFLEX)
4368 {
4369 *flagsPointer |= FLAGS_EXCLUDE;
4370 index++;
4371 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004372 /*
4373 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004374 * it will be part of the class, and a second ungroup character
4375 * must follow to end the group.
4376 */
4377 if (format[index] == SPECIFIER_UNGROUP)
4378 {
4379 characterclass[(int)SPECIFIER_UNGROUP]++;
4380 index++;
4381 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004382 /*
4383 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004384 * it must be at the beginning of the list
4385 */
4386 if (format[index] == QUALIFIER_MINUS)
4387 {
4388 characterclass[(int)QUALIFIER_MINUS]++;
4389 index++;
4390 }
4391 /* Collect characters */
4392 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004393 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004394 ch = format[++index])
4395 {
4396 switch (ch)
4397 {
4398 case QUALIFIER_MINUS: /* Scanlist ranges */
4399
Bjorn Reese70a9da52001-04-21 16:57:29 +00004400 /*
4401 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00004402 * defined.
4403 *
4404 * We support the following behaviour (although this may
4405 * change as we become wiser)
4406 * - only increasing ranges, ie. [a-b] but not [b-a]
4407 * - transitive ranges, ie. [a-b-c] == [a-c]
4408 * - trailing minus, ie. [a-] is interpreted as an 'a'
4409 * and a '-'
4410 * - duplicates (although we can easily convert these
4411 * into errors)
4412 */
4413 range_begin = format[index - 1];
4414 range_end = format[++index];
4415 if (range_end == SPECIFIER_UNGROUP)
4416 {
4417 /* Trailing minus is included */
4418 characterclass[(int)ch]++;
4419 ch = range_end;
4420 break; /* for */
4421 }
4422 if (range_end == NIL)
4423 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4424 if (range_begin > range_end)
4425 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
4426
4427 for (i = (int)range_begin; i <= (int)range_end; i++)
4428 characterclass[i]++;
4429
4430 ch = range_end;
4431 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004432
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004433#if TRIO_EXTENSION
4434
4435 case SPECIFIER_GROUP:
4436
4437 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004438 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004439 case QUALIFIER_DOT: /* Collating symbol */
4440 /*
4441 * FIXME: This will be easier to implement when multibyte
4442 * characters have been implemented. Until now, we ignore
4443 * this feature.
4444 */
4445 for (i = index + 2; ; i++)
4446 {
4447 if (format[i] == NIL)
4448 /* Error in syntax */
4449 return -1;
4450 else if (format[i] == QUALIFIER_DOT)
4451 break; /* for */
4452 }
4453 if (format[++i] != SPECIFIER_UNGROUP)
4454 return -1;
4455
4456 index = i;
4457 break;
4458
4459 case QUALIFIER_EQUAL: /* Equivalence class expressions */
4460 {
4461 unsigned int j;
4462 unsigned int k;
4463
4464 if (internalCollationUnconverted)
4465 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00004466 /* Lazy evalutation of collation array */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004467 TrioGetCollation();
4468 internalCollationUnconverted = FALSE;
4469 }
4470 for (i = index + 2; ; i++)
4471 {
4472 if (format[i] == NIL)
4473 /* Error in syntax */
4474 return -1;
4475 else if (format[i] == QUALIFIER_EQUAL)
4476 break; /* for */
4477 else
4478 {
4479 /* Mark any equivalent character */
4480 k = (unsigned int)format[i];
4481 for (j = 0; internalCollationArray[k][j] != NIL; j++)
4482 characterclass[(int)internalCollationArray[k][j]]++;
4483 }
4484 }
4485 if (format[++i] != SPECIFIER_UNGROUP)
4486 return -1;
4487
4488 index = i;
4489 }
4490 break;
4491
4492 case QUALIFIER_COLON: /* Character class expressions */
4493
Bjorn Reese026d29f2002-01-19 15:40:18 +00004494 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
4495 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004496 {
4497 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4498 if (isalnum(i))
4499 characterclass[i]++;
4500 index += sizeof(CLASS_ALNUM) - 1;
4501 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004502 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
4503 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004504 {
4505 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4506 if (isalpha(i))
4507 characterclass[i]++;
4508 index += sizeof(CLASS_ALPHA) - 1;
4509 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004510 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
4511 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004512 {
4513 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4514 if (iscntrl(i))
4515 characterclass[i]++;
4516 index += sizeof(CLASS_CNTRL) - 1;
4517 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004518 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
4519 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004520 {
4521 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4522 if (isdigit(i))
4523 characterclass[i]++;
4524 index += sizeof(CLASS_DIGIT) - 1;
4525 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004526 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
4527 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004528 {
4529 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4530 if (isgraph(i))
4531 characterclass[i]++;
4532 index += sizeof(CLASS_GRAPH) - 1;
4533 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004534 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
4535 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004536 {
4537 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4538 if (islower(i))
4539 characterclass[i]++;
4540 index += sizeof(CLASS_LOWER) - 1;
4541 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004542 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
4543 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004544 {
4545 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4546 if (isprint(i))
4547 characterclass[i]++;
4548 index += sizeof(CLASS_PRINT) - 1;
4549 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004550 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
4551 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004552 {
4553 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4554 if (ispunct(i))
4555 characterclass[i]++;
4556 index += sizeof(CLASS_PUNCT) - 1;
4557 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004558 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
4559 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004560 {
4561 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4562 if (isspace(i))
4563 characterclass[i]++;
4564 index += sizeof(CLASS_SPACE) - 1;
4565 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004566 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
4567 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004568 {
4569 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4570 if (isupper(i))
4571 characterclass[i]++;
4572 index += sizeof(CLASS_UPPER) - 1;
4573 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00004574 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
4575 &format[index]))
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004576 {
4577 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4578 if (isxdigit(i))
4579 characterclass[i]++;
4580 index += sizeof(CLASS_XDIGIT) - 1;
4581 }
4582 else
4583 {
4584 characterclass[(int)ch]++;
4585 }
4586 break;
4587
4588 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004589 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004590 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004591 }
4592 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004593
4594#endif /* TRIO_EXTENSION */
4595
Daniel Veillard92ad2102001-03-27 12:47:33 +00004596 default:
4597 characterclass[(int)ch]++;
4598 break;
4599 }
4600 }
4601 return 0;
4602}
4603
4604/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004605 * TrioReadNumber
Daniel Veillard92ad2102001-03-27 12:47:33 +00004606 *
4607 * We implement our own number conversion in preference of strtol and
4608 * strtoul, because we must handle 'long long' and thousand separators.
4609 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004610TRIO_PRIVATE BOOLEAN_T
4611TrioReadNumber(trio_class_t *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004612 trio_uintmax_t *target,
4613 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004614 int width,
4615 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004616{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004617 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004618 int digit;
4619 int count;
4620 BOOLEAN_T isNegative = FALSE;
4621 int j;
4622
4623 assert(VALID(self));
4624 assert(VALID(self->InStream));
4625 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
4626
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004627 if (internalDigitsUnconverted)
4628 {
4629 /* Lazy evaluation of digits array */
4630 memset(internalDigitArray, -1, sizeof(internalDigitArray));
4631 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
4632 {
4633 internalDigitArray[(int)internalDigitsLower[j]] = j;
4634 internalDigitArray[(int)internalDigitsUpper[j]] = j;
4635 }
4636 internalDigitsUnconverted = FALSE;
4637 }
4638
Daniel Veillard92ad2102001-03-27 12:47:33 +00004639 TrioSkipWhitespaces(self);
4640
4641 if (!(flags & FLAGS_UNSIGNED))
4642 {
4643 /* Leading sign */
4644 if (self->current == '+')
4645 {
4646 self->InStream(self, NULL);
4647 }
4648 else if (self->current == '-')
4649 {
4650 self->InStream(self, NULL);
4651 isNegative = TRUE;
4652 }
4653 }
4654
4655 count = self->processed;
4656
4657 if (flags & FLAGS_ALTERNATIVE)
4658 {
4659 switch (base)
4660 {
4661 case NO_BASE:
4662 case BASE_OCTAL:
4663 case BASE_HEX:
4664 case BASE_BINARY:
4665 if (self->current == '0')
4666 {
4667 self->InStream(self, NULL);
4668 if (self->current)
4669 {
4670 if ((base == BASE_HEX) &&
4671 (toupper(self->current) == 'X'))
4672 {
4673 self->InStream(self, NULL);
4674 }
4675 else if ((base == BASE_BINARY) &&
4676 (toupper(self->current) == 'B'))
4677 {
4678 self->InStream(self, NULL);
4679 }
4680 }
4681 }
4682 else
4683 return FALSE;
4684 break;
4685 default:
4686 break;
4687 }
4688 }
4689
4690 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
4691 (! ((self->current == EOF) || isspace(self->current))))
4692 {
4693 if (isascii(self->current))
4694 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004695 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00004696 /* Abort if digit is not allowed in the specified base */
4697 if ((digit == -1) || (digit >= base))
4698 break;
4699 }
4700 else if (flags & FLAGS_QUOTE)
4701 {
4702 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004703 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004704 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004705 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004706 break;
4707
4708 self->InStream(self, NULL);
4709 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004710 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004711 break; /* Mismatch */
4712 else
4713 continue; /* Match */
4714 }
4715 else
4716 break;
4717
4718 number *= base;
4719 number += digit;
4720
4721 self->InStream(self, NULL);
4722 }
4723
4724 /* Was anything read at all? */
4725 if (self->processed == count)
4726 return FALSE;
4727
4728 if (target)
4729 *target = (isNegative) ? -number : number;
4730 return TRUE;
4731}
4732
4733/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004734 * TrioReadChar
Daniel Veillard92ad2102001-03-27 12:47:33 +00004735 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004736TRIO_PRIVATE int
4737TrioReadChar(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004738 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004739 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004740 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004741{
4742 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004743 char ch;
4744 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004745
4746 assert(VALID(self));
4747 assert(VALID(self->InStream));
4748
4749 for (i = 0;
4750 (self->current != EOF) && (i < width);
4751 i++)
4752 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004753 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004754 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004755 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
4756 {
4757 switch (self->current)
4758 {
4759 case '\\': ch = '\\'; break;
4760 case 'a': ch = '\007'; break;
4761 case 'b': ch = '\b'; break;
4762 case 'f': ch = '\f'; break;
4763 case 'n': ch = '\n'; break;
4764 case 'r': ch = '\r'; break;
4765 case 't': ch = '\t'; break;
4766 case 'v': ch = '\v'; break;
4767 default:
4768 if (isdigit(self->current))
4769 {
4770 /* Read octal number */
4771 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
4772 return 0;
4773 ch = (char)number;
4774 }
4775 else if (toupper(self->current) == 'X')
4776 {
4777 /* Read hexadecimal number */
4778 self->InStream(self, NULL);
4779 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
4780 return 0;
4781 ch = (char)number;
4782 }
4783 else
4784 {
4785 ch = (char)self->current;
4786 }
4787 break;
4788 }
4789 }
4790
4791 if (target)
4792 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004793 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004794 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004795}
4796
4797/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004798 * TrioReadString
Daniel Veillard92ad2102001-03-27 12:47:33 +00004799 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004800TRIO_PRIVATE BOOLEAN_T
4801TrioReadString(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004802 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004803 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004804 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004805{
4806 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004807
4808 assert(VALID(self));
4809 assert(VALID(self->InStream));
4810
4811 TrioSkipWhitespaces(self);
4812
Bjorn Reese70a9da52001-04-21 16:57:29 +00004813 /*
4814 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004815 * or width is exceeded
4816 */
4817 for (i = 0;
4818 ((width == NO_WIDTH) || (i < width)) &&
4819 (! ((self->current == EOF) || isspace(self->current)));
4820 i++)
4821 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004822 if (TrioReadChar(self, &target[i], flags, 1) == 0)
4823 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004824 }
4825 if (target)
4826 target[i] = NIL;
4827 return TRUE;
4828}
4829
4830/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004831 * TrioReadWideChar
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004832 */
4833#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00004834TRIO_PRIVATE int
4835TrioReadWideChar(trio_class_t *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004836 wchar_t *target,
4837 unsigned long flags,
4838 int width)
4839{
4840 int i;
4841 int j;
4842 int size;
4843 int amount = 0;
4844 wchar_t wch;
4845 char buffer[MB_LEN_MAX + 1];
4846
4847 assert(VALID(self));
4848 assert(VALID(self->InStream));
4849
4850 for (i = 0;
4851 (self->current != EOF) && (i < width);
4852 i++)
4853 {
4854 if (isascii(self->current))
4855 {
4856 if (TrioReadChar(self, buffer, flags, 1) == 0)
4857 return 0;
4858 buffer[1] = NIL;
4859 }
4860 else
4861 {
4862 /*
4863 * Collect a multibyte character, by enlarging buffer until
4864 * it contains a fully legal multibyte character, or the
4865 * buffer is full.
4866 */
4867 j = 0;
4868 do
4869 {
4870 buffer[j++] = (char)self->current;
4871 buffer[j] = NIL;
4872 self->InStream(self, NULL);
4873 }
4874 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
4875 }
4876 if (target)
4877 {
4878 size = mbtowc(&wch, buffer, sizeof(buffer));
4879 if (size > 0)
4880 target[i] = wch;
4881 }
4882 amount += size;
4883 self->InStream(self, NULL);
4884 }
4885 return amount;
4886}
4887#endif /* TRIO_WIDECHAR */
4888
4889/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004890 * TrioReadWideString
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004891 */
4892#if TRIO_WIDECHAR
Bjorn Reese026d29f2002-01-19 15:40:18 +00004893TRIO_PRIVATE BOOLEAN_T
4894TrioReadWideString(trio_class_t *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004895 wchar_t *target,
4896 unsigned long flags,
4897 int width)
4898{
4899 int i;
4900 int size;
4901
4902 assert(VALID(self));
4903 assert(VALID(self->InStream));
4904
4905 TrioSkipWhitespaces(self);
4906
4907#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
4908 mblen(NULL, 0);
4909#endif
4910
4911 /*
4912 * Continue until end of string is reached, a whitespace is encountered,
4913 * or width is exceeded
4914 */
4915 for (i = 0;
4916 ((width == NO_WIDTH) || (i < width)) &&
4917 (! ((self->current == EOF) || isspace(self->current)));
4918 )
4919 {
4920 size = TrioReadWideChar(self, &target[i], flags, 1);
4921 if (size == 0)
4922 break; /* for */
4923
4924 i += size;
4925 }
4926 if (target)
Bjorn Reese026d29f2002-01-19 15:40:18 +00004927 target[i] = WCONST('\0');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004928 return TRUE;
4929}
4930#endif /* TRIO_WIDECHAR */
4931
4932/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004933 * TrioReadGroup
Daniel Veillard92ad2102001-03-27 12:47:33 +00004934 *
4935 * FIXME: characterclass does not work with multibyte characters
4936 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004937TRIO_PRIVATE BOOLEAN_T
4938TrioReadGroup(trio_class_t *self,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004939 char *target,
4940 int *characterclass,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004941 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004942 int width)
4943{
Bjorn Reese70a9da52001-04-21 16:57:29 +00004944 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004945 int i;
4946
4947 assert(VALID(self));
4948 assert(VALID(self->InStream));
4949
4950 ch = self->current;
4951 for (i = 0;
4952 ((width == NO_WIDTH) || (i < width)) &&
4953 (! ((ch == EOF) ||
4954 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
4955 i++)
4956 {
4957 if (target)
4958 target[i] = (char)ch;
4959 self->InStream(self, &ch);
4960 }
4961
4962 if (target)
4963 target[i] = NIL;
4964 return TRUE;
4965}
4966
4967/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00004968 * TrioReadDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +00004969 *
4970 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004971 * add long double
4972 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00004973TRIO_PRIVATE BOOLEAN_T
4974TrioReadDouble(trio_class_t *self,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004975 double *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004976 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004977 int width)
4978{
4979 int ch;
4980 char doubleString[512] = "";
4981 int index = 0;
4982 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004983 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004984 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004985
Bjorn Reese70a9da52001-04-21 16:57:29 +00004986 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004987 width = sizeof(doubleString) - 1;
4988
4989 TrioSkipWhitespaces(self);
4990
Bjorn Reese70a9da52001-04-21 16:57:29 +00004991 /*
Bjorn Reese026d29f2002-01-19 15:40:18 +00004992 * Read entire double number from stream. trio_to_double requires
4993 * a string as input, but InStream can be anything, so we have to
Daniel Veillard92ad2102001-03-27 12:47:33 +00004994 * collect all characters.
4995 */
4996 ch = self->current;
4997 if ((ch == '+') || (ch == '-'))
4998 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004999 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005000 self->InStream(self, &ch);
5001 width--;
5002 }
5003
5004 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005005 switch (ch)
5006 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00005007 case 'n':
5008 case 'N':
5009 /* Not-a-number */
5010 if (index != 0)
5011 break;
5012 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005013 case 'i':
5014 case 'I':
5015 /* Infinity */
5016 while (isalpha(ch) && (index - start < width))
5017 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005018 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005019 self->InStream(self, &ch);
5020 }
5021 doubleString[index] = NIL;
5022
Daniel Veillard92ad2102001-03-27 12:47:33 +00005023 /* Case insensitive string comparison */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005024 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5025 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005026 {
5027 *target = ((start == 1 && doubleString[0] == '-'))
Bjorn Reese45029602001-08-21 09:23:53 +00005028 ? trio_ninf()
5029 : trio_pinf();
Daniel Veillard92ad2102001-03-27 12:47:33 +00005030 return TRUE;
5031 }
Bjorn Reese026d29f2002-01-19 15:40:18 +00005032 if (trio_equal(doubleString, NAN_UPPER))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005033 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005034 /* NaN must not have a preceeding + nor - */
Bjorn Reese45029602001-08-21 09:23:53 +00005035 *target = trio_nan();
Daniel Veillard92ad2102001-03-27 12:47:33 +00005036 return TRUE;
5037 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005038 return FALSE;
5039
5040 default:
5041 break;
5042 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005043
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005044 if (ch == '0')
5045 {
5046 doubleString[index++] = (char)ch;
5047 self->InStream(self, &ch);
5048 if (toupper(ch) == 'X')
5049 {
5050 isHex = TRUE;
5051 doubleString[index++] = (char)ch;
5052 self->InStream(self, &ch);
5053 }
5054 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005055 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005056 {
5057 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005058 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00005059 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005060 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005061 self->InStream(self, &ch);
5062 }
5063 else if (flags & FLAGS_QUOTE)
5064 {
5065 /* Compare with thousands separator */
5066 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5067 {
5068 if (internalThousandSeparator[j] != self->current)
5069 break;
5070
5071 self->InStream(self, &ch);
5072 }
5073 if (internalThousandSeparator[j])
5074 break; /* Mismatch */
5075 else
5076 continue; /* Match */
5077 }
5078 else
5079 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005080 }
5081 if (ch == '.')
5082 {
5083 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005084 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005085 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005086 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5087 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005088 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005089 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005090 self->InStream(self, &ch);
5091 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005092 if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005093 {
5094 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005095 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005096 self->InStream(self, &ch);
5097 if ((ch == '+') || (ch == '-'))
5098 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005099 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005100 self->InStream(self, &ch);
5101 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005102 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5103 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005104 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005105 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005106 self->InStream(self, &ch);
5107 }
5108 }
5109 }
5110
5111 if ((index == start) || (*doubleString == NIL))
5112 return FALSE;
5113
5114 if (flags & FLAGS_LONGDOUBLE)
Bjorn Reese026d29f2002-01-19 15:40:18 +00005115/* *longdoublePointer = trio_to_long_double()*/
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005116 return FALSE; /* FIXME: Remove when long double is implemented */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005117 else
5118 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005119 *target = trio_to_double(doubleString, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005120 }
5121 return TRUE;
5122}
5123
5124/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005125 * TrioReadPointer
Daniel Veillard92ad2102001-03-27 12:47:33 +00005126 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005127TRIO_PRIVATE BOOLEAN_T
5128TrioReadPointer(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005129 void **target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005130 unsigned long flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005131{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005132 trio_uintmax_t number;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005133 char buffer[sizeof(internalNullString)];
Daniel Veillard92ad2102001-03-27 12:47:33 +00005134
5135 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5136
5137 if (TrioReadNumber(self,
5138 &number,
5139 flags,
5140 POINTER_WIDTH,
5141 BASE_HEX))
5142 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005143 /*
5144 * The strange assignment of number is a workaround for a compiler
5145 * warning
5146 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005147 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005148 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005149 return TRUE;
5150 }
5151 else if (TrioReadString(self,
5152 (flags & FLAGS_IGNORE)
5153 ? NULL
5154 : buffer,
5155 0,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005156 sizeof(internalNullString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005157 {
Bjorn Reese026d29f2002-01-19 15:40:18 +00005158 if (trio_equal_case(buffer, internalNullString))
Daniel Veillard92ad2102001-03-27 12:47:33 +00005159 {
5160 if (target)
5161 *target = NULL;
5162 return TRUE;
5163 }
5164 }
5165 return FALSE;
5166}
5167
5168/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005169 * TrioScanProcess
Daniel Veillard92ad2102001-03-27 12:47:33 +00005170 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005171TRIO_PRIVATE int
5172TrioScanProcess(trio_class_t *data,
5173 TRIO_CONST char *format,
5174 trio_parameter_t *parameters)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005175{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005176#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005177 int charlen;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005178 int cnt;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005179#endif
5180 int assignment;
5181 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005182 int index; /* Index of format string */
5183 int i; /* Index of current parameter */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005184 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005185 int width;
5186 int base;
5187 void *pointer;
5188
Daniel Veillard92ad2102001-03-27 12:47:33 +00005189 assignment = 0;
5190 i = 0;
5191 index = 0;
5192 data->InStream(data, &ch);
5193
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005194#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005195 mblen(NULL, 0);
5196#endif
5197
5198 while (format[index])
5199 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005200#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005201 if (! isascii(format[index]))
5202 {
5203 charlen = mblen(&format[index], MB_LEN_MAX);
5204 /* Compare multibyte characters in format string */
5205 for (cnt = 0; cnt < charlen - 1; cnt++)
5206 {
5207 if (ch != format[index + cnt])
5208 {
5209 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5210 }
5211 data->InStream(data, &ch);
5212 }
5213 continue; /* while */
5214 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005215#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005216 if (EOF == ch)
5217 return EOF;
5218
5219 if (CHAR_IDENTIFIER == format[index])
5220 {
5221 if (CHAR_IDENTIFIER == format[index + 1])
5222 {
5223 /* Two % in format matches one % in input stream */
5224 if (CHAR_IDENTIFIER == ch)
5225 {
5226 data->InStream(data, &ch);
5227 index += 2;
5228 continue; /* while format chars left */
5229 }
5230 else
5231 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5232 }
5233
5234 /* Skip the parameter entries */
5235 while (parameters[i].type == FORMAT_PARAMETER)
5236 i++;
5237
5238 flags = parameters[i].flags;
5239 /* Find width */
5240 width = parameters[i].width;
5241 if (flags & FLAGS_WIDTH_PARAMETER)
5242 {
5243 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005244 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005245 }
5246 /* Find base */
5247 base = parameters[i].base;
5248 if (flags & FLAGS_BASE_PARAMETER)
5249 {
5250 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005251 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005252 }
5253
5254 switch (parameters[i].type)
5255 {
5256 case FORMAT_INT:
5257 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005258 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005259
5260 if (0 == base)
5261 base = BASE_DECIMAL;
5262
5263 if (!TrioReadNumber(data,
5264 &number,
5265 flags,
5266 width,
5267 base))
5268 return assignment;
5269 assignment++;
5270
5271 if (!(flags & FLAGS_IGNORE))
5272 {
5273 pointer = parameters[i].data.pointer;
5274#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5275 if (flags & FLAGS_SIZE_T)
5276 *(size_t *)pointer = (size_t)number;
5277 else
5278#endif
5279#if defined(QUALIFIER_PTRDIFF_T)
5280 if (flags & FLAGS_PTRDIFF_T)
5281 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
5282 else
5283#endif
5284#if defined(QUALIFIER_INTMAX_T)
5285 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005286 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005287 else
5288#endif
5289 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005290 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005291 else if (flags & FLAGS_LONG)
5292 *(long int *)pointer = (long int)number;
5293 else if (flags & FLAGS_SHORT)
5294 *(short int *)pointer = (short int)number;
5295 else
5296 *(int *)pointer = (int)number;
5297 }
5298 }
5299 break; /* FORMAT_INT */
5300
5301 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005302#if TRIO_WIDECHAR
5303 if (flags & FLAGS_WIDECHAR)
5304 {
5305 if (!TrioReadWideString(data,
5306 (flags & FLAGS_IGNORE)
5307 ? NULL
5308 : parameters[i].data.wstring,
5309 flags,
5310 width))
5311 return assignment;
5312 }
5313 else
5314#endif
5315 {
5316 if (!TrioReadString(data,
5317 (flags & FLAGS_IGNORE)
5318 ? NULL
5319 : parameters[i].data.string,
5320 flags,
5321 width))
5322 return assignment;
5323 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005324 assignment++;
5325 break; /* FORMAT_STRING */
5326
5327 case FORMAT_DOUBLE:
5328 if (!TrioReadDouble(data,
5329 (flags & FLAGS_IGNORE)
5330 ? NULL
5331 : parameters[i].data.doublePointer,
5332 flags,
5333 width))
5334 return assignment;
5335 assignment++;
5336 break; /* FORMAT_DOUBLE */
5337
5338 case FORMAT_GROUP:
5339 {
5340 int characterclass[MAX_CHARACTER_CLASS + 1];
5341 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005342
5343 /* Skip over modifiers */
5344 while (format[index] != SPECIFIER_GROUP)
5345 {
5346 index++;
5347 }
5348 /* Skip over group specifier */
5349 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005350
Daniel Veillard92ad2102001-03-27 12:47:33 +00005351 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005352 rc = TrioGetCharacterClass(format,
5353 &index,
5354 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005355 characterclass);
5356 if (rc < 0)
5357 return rc;
5358
5359 if (!TrioReadGroup(data,
5360 (flags & FLAGS_IGNORE)
5361 ? NULL
5362 : parameters[i].data.string,
5363 characterclass,
5364 flags,
5365 parameters[i].width))
5366 return assignment;
5367 assignment++;
5368 }
5369 break; /* FORMAT_GROUP */
5370
5371 case FORMAT_COUNT:
5372 pointer = parameters[i].data.pointer;
5373 if (NULL != pointer)
5374 {
5375#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5376 if (flags & FLAGS_SIZE_T)
5377 *(size_t *)pointer = (size_t)data->committed;
5378 else
5379#endif
5380#if defined(QUALIFIER_PTRDIFF_T)
5381 if (flags & FLAGS_PTRDIFF_T)
5382 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
5383 else
5384#endif
5385#if defined(QUALIFIER_INTMAX_T)
5386 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005387 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005388 else
5389#endif
5390 if (flags & FLAGS_QUAD)
5391 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005392 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005393 }
5394 else if (flags & FLAGS_LONG)
5395 {
5396 *(long int *)pointer = (long int)data->committed;
5397 }
5398 else if (flags & FLAGS_SHORT)
5399 {
5400 *(short int *)pointer = (short int)data->committed;
5401 }
5402 else
5403 {
5404 *(int *)pointer = (int)data->committed;
5405 }
5406 }
5407 break; /* FORMAT_COUNT */
5408
5409 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005410#if TRIO_WIDECHAR
5411 if (flags & FLAGS_WIDECHAR)
5412 {
5413 if (TrioReadWideChar(data,
5414 (flags & FLAGS_IGNORE)
5415 ? NULL
5416 : parameters[i].data.wstring,
5417 flags,
5418 (width == NO_WIDTH) ? 1 : width) > 0)
5419 return assignment;
5420 }
5421 else
5422#endif
5423 {
5424 if (TrioReadChar(data,
5425 (flags & FLAGS_IGNORE)
5426 ? NULL
5427 : parameters[i].data.string,
5428 flags,
5429 (width == NO_WIDTH) ? 1 : width) > 0)
5430 return assignment;
5431 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005432 assignment++;
5433 break; /* FORMAT_CHAR */
5434
5435 case FORMAT_POINTER:
5436 if (!TrioReadPointer(data,
5437 (flags & FLAGS_IGNORE)
5438 ? NULL
Bjorn Reese70a9da52001-04-21 16:57:29 +00005439 : (void **)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005440 flags))
5441 return assignment;
5442 assignment++;
5443 break; /* FORMAT_POINTER */
5444
5445 case FORMAT_PARAMETER:
5446 break; /* FORMAT_PARAMETER */
5447
5448 default:
5449 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5450 }
5451 ch = data->current;
5452 index = parameters[i].indexAfterSpecifier;
5453 i++;
5454 }
5455 else /* Not an % identifier */
5456 {
5457 if (isspace((int)format[index]))
5458 {
5459 /* Whitespaces may match any amount of whitespaces */
5460 ch = TrioSkipWhitespaces(data);
5461 }
5462 else if (ch == format[index])
5463 {
5464 data->InStream(data, &ch);
5465 }
5466 else
Bjorn Reese026d29f2002-01-19 15:40:18 +00005467 return assignment;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005468
5469 index++;
5470 }
5471 }
5472 return assignment;
5473}
5474
5475/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005476 * TrioScan
Daniel Veillard92ad2102001-03-27 12:47:33 +00005477 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005478TRIO_PRIVATE int
5479TrioScan(TRIO_CONST void *source,
5480 size_t sourceSize,
5481 void (*InStream)(trio_class_t *, int *),
5482 TRIO_CONST char *format,
5483 va_list arglist,
5484 void **argarray)
5485{
5486 int status;
5487 trio_parameter_t parameters[MAX_PARAMETERS];
5488 trio_class_t data;
5489
5490 assert(VALID(InStream));
5491 assert(VALID(format));
5492
5493 memset(&data, 0, sizeof(data));
5494 data.InStream = InStream;
5495 data.location = (void *)source;
5496 data.max = sourceSize;
5497 data.error = 0;
5498
5499#if defined(USE_LOCALE)
5500 if (NULL == internalLocaleValues)
5501 {
5502 TrioSetLocale();
5503 }
5504#endif
5505
5506 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
5507 if (status < 0)
5508 return status;
5509
5510 status = TrioScanProcess(&data, format, parameters);
5511 if (data.error != 0)
5512 {
5513 status = data.error;
5514 }
5515 return status;
5516}
5517
5518/*************************************************************************
5519 * TrioInStreamFile
5520 */
5521TRIO_PRIVATE void
5522TrioInStreamFile(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005523 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005524{
5525 FILE *file = (FILE *)self->location;
5526
5527 assert(VALID(self));
5528 assert(VALID(file));
5529
5530 self->current = fgetc(file);
Bjorn Reese026d29f2002-01-19 15:40:18 +00005531 if (self->current == EOF)
5532 {
5533 self->error = (ferror(file))
5534 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
5535 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
5536 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005537 self->processed++;
5538 self->committed++;
5539
5540 if (VALID(intPointer))
5541 {
5542 *intPointer = self->current;
5543 }
5544}
5545
5546/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005547 * TrioInStreamFileDescriptor
Daniel Veillard92ad2102001-03-27 12:47:33 +00005548 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005549TRIO_PRIVATE void
5550TrioInStreamFileDescriptor(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005551 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005552{
5553 int fd = *((int *)self->location);
5554 int size;
5555 unsigned char input;
5556
5557 assert(VALID(self));
5558
5559 size = read(fd, &input, sizeof(char));
Bjorn Reese026d29f2002-01-19 15:40:18 +00005560 if (size == -1)
5561 {
5562 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
5563 self->current = EOF;
5564 }
5565 else
5566 {
5567 self->current = (size == 0) ? EOF : input;
5568 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005569 self->committed++;
Bjorn Reese026d29f2002-01-19 15:40:18 +00005570 self->processed++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005571
5572 if (VALID(intPointer))
5573 {
5574 *intPointer = self->current;
5575 }
5576}
5577
5578/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005579 * TrioInStreamString
Daniel Veillard92ad2102001-03-27 12:47:33 +00005580 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005581TRIO_PRIVATE void
5582TrioInStreamString(trio_class_t *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005583 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005584{
5585 unsigned char **buffer;
5586
5587 assert(VALID(self));
5588 assert(VALID(self->InStream));
5589 assert(VALID(self->location));
5590
5591 buffer = (unsigned char **)self->location;
5592 self->current = (*buffer)[0];
5593 if (self->current == NIL)
5594 self->current = EOF;
5595 (*buffer)++;
5596 self->processed++;
5597 self->committed++;
5598
5599 if (VALID(intPointer))
5600 {
5601 *intPointer = self->current;
5602 }
5603}
5604
5605/*************************************************************************
Bjorn Reese026d29f2002-01-19 15:40:18 +00005606 *
5607 * Formatted scanning functions
5608 *
5609 ************************************************************************/
5610
5611#if defined(TRIO_DOCUMENTATION)
5612# include "doc/doc_scanf.h"
5613#endif
5614/** @addtogroup Scanf
5615 @{
5616*/
5617
5618/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00005619 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00005620 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005621
5622/**
5623 Scan characters from standard input stream.
5624
5625 @param format Formatting string.
5626 @param ... Arguments.
5627 @return Number of scanned characters.
5628 */
5629TRIO_PUBLIC int
5630trio_scanf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005631 ...)
5632{
5633 int status;
5634 va_list args;
5635
5636 assert(VALID(format));
5637
5638 va_start(args, format);
5639 status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5640 va_end(args);
5641 return status;
5642}
5643
Bjorn Reese026d29f2002-01-19 15:40:18 +00005644TRIO_PUBLIC int
5645trio_vscanf(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005646 va_list args)
5647{
5648 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005649
5650 return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5651}
5652
Bjorn Reese026d29f2002-01-19 15:40:18 +00005653TRIO_PUBLIC int
5654trio_scanfv(TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005655 void **args)
5656{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005657 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005658
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005659 assert(VALID(format));
5660
5661 return TrioScan(stdin, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005662}
5663
5664/*************************************************************************
5665 * fscanf
5666 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005667TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005668trio_fscanf(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005669 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005670 ...)
5671{
5672 int status;
5673 va_list args;
5674
5675 assert(VALID(file));
5676 assert(VALID(format));
5677
5678 va_start(args, format);
5679 status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5680 va_end(args);
5681 return status;
5682}
5683
Bjorn Reese026d29f2002-01-19 15:40:18 +00005684TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005685trio_vfscanf(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005686 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005687 va_list args)
5688{
5689 assert(VALID(file));
5690 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005691
5692 return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5693}
5694
Bjorn Reese026d29f2002-01-19 15:40:18 +00005695TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005696trio_fscanfv(FILE *file,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005697 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005698 void **args)
5699{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005700 va_list dummy;
5701
Bjorn Reese70a9da52001-04-21 16:57:29 +00005702 assert(VALID(file));
5703 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005704
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005705 return TrioScan(file, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005706}
5707
5708/*************************************************************************
5709 * dscanf
5710 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005711TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005712trio_dscanf(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005713 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005714 ...)
5715{
5716 int status;
5717 va_list args;
5718
5719 assert(VALID(format));
5720
5721 va_start(args, format);
5722 status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5723 va_end(args);
5724 return status;
5725}
5726
Bjorn Reese026d29f2002-01-19 15:40:18 +00005727TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005728trio_vdscanf(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005729 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005730 va_list args)
5731{
5732 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005733
5734 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5735}
5736
Bjorn Reese026d29f2002-01-19 15:40:18 +00005737TRIO_PUBLIC int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005738trio_dscanfv(int fd,
Bjorn Reese026d29f2002-01-19 15:40:18 +00005739 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005740 void **args)
5741{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005742 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005743
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005744 assert(VALID(format));
5745
5746 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005747}
5748
5749/*************************************************************************
5750 * sscanf
5751 */
Bjorn Reese026d29f2002-01-19 15:40:18 +00005752TRIO_PUBLIC int
5753trio_sscanf(TRIO_CONST char *buffer,
5754 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005755 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005756{
5757 int status;
5758 va_list args;
5759
5760 assert(VALID(buffer));
5761 assert(VALID(format));
5762
5763 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005764 status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005765 va_end(args);
5766 return status;
5767}
5768
Bjorn Reese026d29f2002-01-19 15:40:18 +00005769TRIO_PUBLIC int
5770trio_vsscanf(TRIO_CONST char *buffer,
5771 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005772 va_list args)
5773{
5774 assert(VALID(buffer));
5775 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005776
5777 return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
5778}
5779
Bjorn Reese026d29f2002-01-19 15:40:18 +00005780TRIO_PUBLIC int
5781trio_sscanfv(TRIO_CONST char *buffer,
5782 TRIO_CONST char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005783 void **args)
5784{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005785 va_list dummy;
5786
Bjorn Reese70a9da52001-04-21 16:57:29 +00005787 assert(VALID(buffer));
5788 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005789
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005790 return TrioScan(&buffer, 0, TrioInStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005791}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005792
Bjorn Reese026d29f2002-01-19 15:40:18 +00005793/** @} End of Scanf documentation module */