blob: ea772bac6869ecc50ea852ec1144af7bc2d9e4b0 [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
44static const char rcsid[] = "@(#)$Id$";
45
Daniel Veillard92ad2102001-03-27 12:47:33 +000046/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +000047 * Trio include files
Daniel Veillard92ad2102001-03-27 12:47:33 +000048 */
Daniel Veillard92ad2102001-03-27 12:47:33 +000049#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000050#include "triop.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000051#include "strio.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
Daniel Veillard92ad2102001-03-27 12:47:33 +000063
Bjorn Reese906ec8a2001-06-05 12:46:33 +000064/*************************************************************************
65 * Platform and compiler support detection
66 */
67#if defined(unix) || defined(__xlC__) || defined(_AIX) || defined(__QNX__)
68# define PLATFORM_UNIX
69#elif defined(AMIGA) && defined(__GNUC__)
70# define PLATFORM_UNIX
71#elif defined(WIN32) || defined(_WIN32) || defined(_MSC_VER)
72# define PLATFORM_WIN32
73# define TRIO_MSVC_5 1100
Daniel Veillard92ad2102001-03-27 12:47:33 +000074#endif
75
Bjorn Reese906ec8a2001-06-05 12:46:33 +000076#if defined(__STDC__) && defined(__STDC_VERSION__)
77# if (__STDC_VERSION__ >= 199409L)
78# define TRIO_COMPILER_SUPPORTS_ISO94
79# endif
80# if (__STDC_VERSION__ >= 199901L)
81# define TRIO_COMPILER_SUPPORTS_C99
82# endif
83#endif
84
85#if defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED)
86# define TRIO_COMPILER_SUPPORTS_UNIX98
87#endif
88
89#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
90# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
91# if !defined(MB_LEN_MAX)
92# define MB_LEN_MAX 6
93# endif
94#endif
95
96
97/*************************************************************************
98 * Generic definitions
99 */
100
101#if !(defined(DEBUG) || defined(NDEBUG))
102# define NDEBUG
103#endif
104#include <assert.h>
105#include <ctype.h>
106#if !defined(TRIO_COMPILER_SUPPORTS_C99)
107# define isblank(x) (((x)==32) || ((x)==9))
108#endif
109#include <math.h>
110#include <limits.h>
111#include <float.h>
112#include <stdarg.h>
113#include <stddef.h>
114#include <errno.h>
115
116#ifndef NULL
117# define NULL 0
118#endif
119#define NIL ((char)0)
120#ifndef FALSE
121# define FALSE (1 == 0)
122# define TRUE (! FALSE)
123#endif
124#define BOOLEAN_T int
125
126/* mincore() can be used for debugging purposes */
127#define VALID(x) (NULL != (x))
128
129/* xlC crashes on log10(0) */
130#define guarded_log10(x) (((x) == 0.0) ? -HUGE_VAL : log10(x))
131#define guarded_log16(x) (guarded_log10(x) / log10(16.0))
132
133
134/*************************************************************************
135 * Platform specific definitions
136 */
137#if defined(PLATFORM_UNIX)
138# include <unistd.h>
139# include <signal.h>
140# include <locale.h>
141# define USE_LOCALE
142#endif /* PLATFORM_UNIX */
143#if defined(PLATFORM_WIN32)
144# include <io.h>
145# define read _read
146# define write _write
147#endif /* PLATFORM_WIN32 */
148
149#if TRIO_WIDECHAR
150# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
151# include <wchar.h>
152# include <wctype.h>
153# else
154typedef char wchar_t;
155typedef int wint_t;
156# define WEOF EOF
157# define iswalnum(x) isalnum(x)
158# define iswalpha(x) isalpha(x)
159# define iswblank(x) isblank(x)
160# define iswcntrl(x) iscntrl(x)
161# define iswdigit(x) isdigit(x)
162# define iswgraph(x) isgraph(x)
163# define iswlower(x) islower(x)
164# define iswprint(x) isprint(x)
165# define iswpunct(x) ispunct(x)
166# define iswspace(x) isspace(x)
167# define iswupper(x) isupper(x)
168# define iswxdigit(x) isxdigit(x)
169# endif
170#endif
171
172
173/*************************************************************************
174 * Compiler dependent definitions
175 */
176
177/* Support for long long */
178#ifndef __cplusplus
179# if !defined(USE_LONGLONG)
180# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
181# define USE_LONGLONG
182# elif defined(__SUNPRO_C)
183# define USE_LONGLONG
184# elif defined(_LONG_LONG) || defined(_LONGLONG)
185# define USE_LONGLONG
186# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000187# endif
188#endif
189
190/* The extra long numbers */
191#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000192typedef signed long long int trio_longlong_t;
193typedef unsigned long long int trio_ulonglong_t;
194#elif defined(_MSC_VER)
195# if (_MSC_VER >= TRIO_MSVC_5)
196typedef signed __int64 trio_longlong_t;
197typedef unsigned __int64 trio_ulonglong_t;
198# else
199typedef signed long int trio_longlong_t;
200typedef unsigned long int trio_ulonglong_t;
201# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000202#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000203typedef signed long int trio_longlong_t;
204typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000205#endif
206
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000207/* Maximal and fixed integer types */
208#if defined(TRIO_COMPILER_SUPPORTS_C99)
209# include <stdint.h>
210typedef intmax_t trio_intmax_t;
211typedef uintmax_t trio_uintmax_t;
212typedef int8_t trio_int8_t;
213typedef int16_t trio_int16_t;
214typedef int32_t trio_int32_t;
215typedef int64_t trio_int64_t;
216#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
217# include <inttypes.h>
218typedef intmax_t trio_intmax_t;
219typedef uintmax_t trio_uintmax_t;
220typedef int8_t trio_int8_t;
221typedef int16_t trio_int16_t;
222typedef int32_t trio_int32_t;
223typedef int64_t trio_int64_t;
224#elif defined(_MSC_VER) && (_MSC_VER >= TRIO_MSVC_5)
225typedef trio_longlong_t trio_intmax_t;
226typedef trio_ulonglong_t trio_uintmax_t;
227typedef __int8 trio_int8_t;
228typedef __int16 trio_int16_t;
229typedef __int32 trio_int32_t;
230typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000231#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000232typedef trio_longlong_t trio_intmax_t;
233typedef trio_ulonglong_t trio_uintmax_t;
234# if defined(TRIO_INT8_T)
235typedef TRIO_INT8_T trio_int8_t;
236# else
237typedef signed char trio_int8_t;
238# endif
239# if defined(TRIO_INT16_T)
240typedef TRIO_INT16_T trio_int16_t;
241# else
242typedef signed short trio_int16_t;
243# endif
244# if defined(TRIO_INT32_T)
245typedef TRIO_INT32_T trio_int32_t;
246# else
247typedef signed int trio_int32_t;
248# endif
249# if defined(TRIO_INT64_T)
250typedef TRIO_INT64_T trio_int64_t;
251# else
252typedef trio_longlong_t trio_int64_t;
253# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000254#endif
255
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000256
257/*************************************************************************
258 * Internal definitions
259 */
260
261/* Long double sizes */
262#ifdef LDBL_DIG
263# define MAX_MANTISSA_DIGITS LDBL_DIG
264# define MAX_EXPONENT_DIGITS 4
265#else
266# define MAX_MANTISSA_DIGITS DBL_DIG
267# define MAX_EXPONENT_DIGITS 3
268#endif
269
270/* The maximal number of digits is for base 2 */
271#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000272/* The width of a pointer. The number of bits in a hex digit is 4 */
273#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
274
275/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000276#define INFINITE_LOWER "inf"
277#define INFINITE_UPPER "INF"
278#define LONG_INFINITE_LOWER "infinite"
279#define LONG_INFINITE_UPPER "INFINITE"
280#define NAN_LOWER "nan"
281#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000282
283/* Various constants */
284enum {
285 TYPE_PRINT = 1,
286 TYPE_SCAN = 2,
287
288 /* Flags. Use maximum 32 */
289 FLAGS_NEW = 0,
290 FLAGS_STICKY = 1,
291 FLAGS_SPACE = 2 * FLAGS_STICKY,
292 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
293 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
294 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
295 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
296 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
297 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
298 FLAGS_QUAD = 2 * FLAGS_LONG,
299 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
300 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
301 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
302 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
303 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
304 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
305 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
306 FLAGS_WIDTH = 2 * FLAGS_UPPER,
307 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
308 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
309 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
310 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
311 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
312 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
313 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
314 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
315 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
316 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
317 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
318 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000319 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
320 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000321 /* Reused flags */
322 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000323 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000324 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000325 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000326 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000327
328 NO_POSITION = -1,
329 NO_WIDTH = 0,
330 NO_PRECISION = -1,
331 NO_SIZE = -1,
332
333 NO_BASE = -1,
334 MIN_BASE = 2,
335 MAX_BASE = 36,
336 BASE_BINARY = 2,
337 BASE_OCTAL = 8,
338 BASE_DECIMAL = 10,
339 BASE_HEX = 16,
340
341 /* Maximal number of allowed parameters */
342 MAX_PARAMETERS = 64,
343 /* Maximal number of characters in class */
344 MAX_CHARACTER_CLASS = UCHAR_MAX,
345
Bjorn Reese70a9da52001-04-21 16:57:29 +0000346 /* Maximal string lengths for user-defined specifiers */
347 MAX_USER_NAME = 64,
348 MAX_USER_DATA = 256,
349
Daniel Veillard92ad2102001-03-27 12:47:33 +0000350 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000351 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000352 /* Maximal number of integers in grouping */
Daniel Veillard5792e162001-04-30 17:44:45 +0000353 MAX_LOCALE_GROUPS = 64
Daniel Veillard92ad2102001-03-27 12:47:33 +0000354};
355
356#define NO_GROUPING ((int)CHAR_MAX)
357
358/* Fundamental formatting parameter types */
359#define FORMAT_UNKNOWN 0
360#define FORMAT_INT 1
361#define FORMAT_DOUBLE 2
362#define FORMAT_CHAR 3
363#define FORMAT_STRING 4
364#define FORMAT_POINTER 5
365#define FORMAT_COUNT 6
366#define FORMAT_PARAMETER 7
367#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000368#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000369# define FORMAT_ERRNO 9
370#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000371#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000372# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000373#endif
374
375/* Character constants */
376#define CHAR_IDENTIFIER '%'
377#define CHAR_BACKSLASH '\\'
378#define CHAR_QUOTE '\"'
379#define CHAR_ADJUST ' '
380
381/* Character class expressions */
382#define CLASS_ALNUM ":alnum:"
383#define CLASS_ALPHA ":alpha:"
384#define CLASS_CNTRL ":cntrl:"
385#define CLASS_DIGIT ":digit:"
386#define CLASS_GRAPH ":graph:"
387#define CLASS_LOWER ":lower:"
388#define CLASS_PRINT ":print:"
389#define CLASS_PUNCT ":punct:"
390#define CLASS_SPACE ":space:"
391#define CLASS_UPPER ":upper:"
392#define CLASS_XDIGIT ":xdigit:"
393
394/*
395 * SPECIFIERS:
396 *
397 *
398 * a Hex-float
399 * A Hex-float
400 * c Character
401 * C Widechar character (wint_t)
402 * d Decimal
403 * e Float
404 * E Float
405 * F Float
406 * F Float
407 * g Float
408 * G Float
409 * i Integer
410 * m Error message
411 * n Count
412 * o Octal
413 * p Pointer
414 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000415 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000416 * u Unsigned
417 * x Hex
418 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000419 * [] Group
420 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000421 *
422 * Reserved:
423 *
424 * D Binary Coded Decimal %D(length,precision) (OS/390)
425 */
426#define SPECIFIER_CHAR 'c'
427#define SPECIFIER_STRING 's'
428#define SPECIFIER_DECIMAL 'd'
429#define SPECIFIER_INTEGER 'i'
430#define SPECIFIER_UNSIGNED 'u'
431#define SPECIFIER_OCTAL 'o'
432#define SPECIFIER_HEX 'x'
433#define SPECIFIER_HEX_UPPER 'X'
434#define SPECIFIER_FLOAT_E 'e'
435#define SPECIFIER_FLOAT_E_UPPER 'E'
436#define SPECIFIER_FLOAT_F 'f'
437#define SPECIFIER_FLOAT_F_UPPER 'F'
438#define SPECIFIER_FLOAT_G 'g'
439#define SPECIFIER_FLOAT_G_UPPER 'G'
440#define SPECIFIER_POINTER 'p'
441#define SPECIFIER_GROUP '['
442#define SPECIFIER_UNGROUP ']'
443#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000444#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000445# define SPECIFIER_CHAR_UPPER 'C'
446# define SPECIFIER_STRING_UPPER 'S'
447#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000448#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000449# define SPECIFIER_HEXFLOAT 'a'
450# define SPECIFIER_HEXFLOAT_UPPER 'A'
451#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000452#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000453# define SPECIFIER_ERRNO 'm'
454#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000455#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000456# define SPECIFIER_BINARY 'b'
457# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000458# define SPECIFIER_USER_DEFINED_BEGIN '<'
459# define SPECIFIER_USER_DEFINED_END '>'
460# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000461#endif
462
463/*
464 * QUALIFIERS:
465 *
466 *
467 * Numbers = d,i,o,u,x,X
468 * Float = a,A,e,E,f,F,g,G
469 * String = s
470 * Char = c
471 *
472 *
473 * 9$ Position
474 * Use the 9th parameter. 9 can be any number between 1 and
475 * the maximal argument
476 *
477 * 9 Width
478 * Set width to 9. 9 can be any number, but must not be postfixed
479 * by '$'
480 *
481 * h Short
482 * Numbers:
483 * (unsigned) short int
484 *
485 * hh Short short
486 * Numbers:
487 * (unsigned) char
488 *
489 * l Long
490 * Numbers:
491 * (unsigned) long int
492 * String:
493 * as the S specifier
494 * Char:
495 * as the C specifier
496 *
497 * ll Long Long
498 * Numbers:
499 * (unsigned) long long int
500 *
501 * L Long Double
502 * Float
503 * long double
504 *
505 * # Alternative
506 * Float:
507 * Decimal-point is always present
508 * String:
509 * non-printable characters are handled as \number
510 *
511 * Spacing
512 *
513 * + Sign
514 *
515 * - Alignment
516 *
517 * . Precision
518 *
519 * * Parameter
520 * print: use parameter
521 * scan: no parameter (ignore)
522 *
523 * q Quad
524 *
525 * Z size_t
526 *
527 * w Widechar
528 *
529 * ' Thousands/quote
530 * Numbers:
531 * Integer part grouped in thousands
532 * Binary numbers:
533 * Number grouped in nibbles (4 bits)
534 * String:
535 * Quoted string
536 *
537 * j intmax_t
538 * t prtdiff_t
539 * z size_t
540 *
541 * ! Sticky
542 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000543 *
544 * I n-bit Integer
545 * Numbers:
546 * The following options exists
547 * I8 = 8-bit integer
548 * I16 = 16-bit integer
549 * I32 = 32-bit integer
550 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000551 */
552#define QUALIFIER_POSITION '$'
553#define QUALIFIER_SHORT 'h'
554#define QUALIFIER_LONG 'l'
555#define QUALIFIER_LONG_UPPER 'L'
556#define QUALIFIER_ALTERNATIVE '#'
557#define QUALIFIER_SPACE ' '
558#define QUALIFIER_PLUS '+'
559#define QUALIFIER_MINUS '-'
560#define QUALIFIER_DOT '.'
561#define QUALIFIER_STAR '*'
562#define QUALIFIER_CIRCUMFLEX '^'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000563#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000564# define QUALIFIER_SIZE_T 'z'
565# define QUALIFIER_PTRDIFF_T 't'
566# define QUALIFIER_INTMAX_T 'j'
567#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000568#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000569# define QUALIFIER_QUAD 'q'
570#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000571#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000572# define QUALIFIER_SIZE_T_UPPER 'Z'
573#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000574#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000575# define QUALIFIER_WIDECHAR 'w'
576#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000577#if TRIO_MICROSOFT
578# define QUALIFIER_FIXED_SIZE 'I'
579#endif
580#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000581# define QUALIFIER_QUOTE '\''
582# define QUALIFIER_STICKY '!'
583# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
584# define QUALIFIER_PARAM '@' /* Experimental */
585# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000586# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000587#endif
588
Bjorn Reese70a9da52001-04-21 16:57:29 +0000589
590/*************************************************************************
591 * Internal structures
592 */
593
594/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000595typedef struct {
596 int type;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000597 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000598 int width;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000599 int precision;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000600 int base;
601 int varsize;
602 int indexAfterSpecifier;
603 union {
604 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000605#if TRIO_WIDECHAR
606 wchar_t *wstring;
607#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000608 void *pointer;
609 union {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000610 trio_uintmax_t as_signed;
611 trio_intmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000612 } number;
613 double doubleNumber;
614 double *doublePointer;
615 long double longdoubleNumber;
616 long double *longdoublePointer;
617 int errorNumber;
618 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000619 /* For the user-defined specifier */
620 char user_name[MAX_USER_NAME];
621 char user_data[MAX_USER_DATA];
Daniel Veillard92ad2102001-03-27 12:47:33 +0000622} parameter_T;
623
Bjorn Reese70a9da52001-04-21 16:57:29 +0000624/* General trio "class" */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000625typedef struct _trio_T {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000626 void *location;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000627 void (*OutStream)(struct _trio_T *, int);
628 void (*InStream)(struct _trio_T *, int *);
Bjorn Reese70a9da52001-04-21 16:57:29 +0000629 /*
630 * The number of characters that would have been written/read if
Daniel Veillard92ad2102001-03-27 12:47:33 +0000631 * there had been sufficient space.
632 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000633 int processed;
634 /*
635 * The number of characters that are actually written/read.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000636 * Processed and committed with only differ for the *nprintf
637 * and *nscanf functions.
638 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000639 int committed;
640 int max;
641 int current;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000642} trio_T;
643
Bjorn Reese70a9da52001-04-21 16:57:29 +0000644/* References (for user-defined callbacks) */
645typedef struct _reference_T {
646 trio_T *data;
647 parameter_T *parameter;
648} reference_T;
649
650/* Registered entries (for user-defined callbacks) */
651typedef struct _userdef_T {
652 struct _userdef_T *next;
653 trio_callback_t callback;
654 char *name;
655} userdef_T;
656
Daniel Veillard92ad2102001-03-27 12:47:33 +0000657
658/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000659 * Internal variables
Daniel Veillard92ad2102001-03-27 12:47:33 +0000660 */
661
662#if defined(PLATFORM_UNIX)
663extern int errno;
664#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000665static const char null[] = "(nil)";
666
Bjorn Reese70a9da52001-04-21 16:57:29 +0000667#if defined(USE_LOCALE)
668static struct lconv *internalLocaleValues = NULL;
669#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000670
Bjorn Reese70a9da52001-04-21 16:57:29 +0000671/*
672 * UNIX98 says "in a locale where the radix character is not defined,
673 * the radix character defaults to a period (.)"
674 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000675static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
676static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000677static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
678
679static const char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
680static const char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000681static BOOLEAN_T internalDigitsUnconverted = TRUE;
682static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000683#if TRIO_EXTENSION
684static BOOLEAN_T internalCollationUnconverted = TRUE;
685static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
686#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000687
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000688static volatile trio_callback_t internalEnterCriticalRegion = NULL;
689static volatile trio_callback_t internalLeaveCriticalRegion = NULL;
690static userdef_T *internalUserDef = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000691
692
693/*************************************************************************
694 * trio_strerror [public]
695 */
696const char *trio_strerror(int errorcode)
697{
698 /* Textual versions of the error codes */
699 switch (TRIO_ERROR_CODE(errorcode))
700 {
701 case TRIO_EOF:
702 return "End of file";
703 case TRIO_EINVAL:
704 return "Invalid argument";
705 case TRIO_ETOOMANY:
706 return "Too many arguments";
707 case TRIO_EDBLREF:
708 return "Double reference";
709 case TRIO_EGAP:
710 return "Reference gap";
711 case TRIO_ENOMEM:
712 return "Out of memory";
713 case TRIO_ERANGE:
714 return "Invalid range";
715 default:
716 return "Unknown";
717 }
718}
Daniel Veillard92ad2102001-03-27 12:47:33 +0000719
720/*************************************************************************
721 * TrioIsQualifier [private]
722 *
723 * Description:
724 * Remember to add all new qualifiers to this function.
725 * QUALIFIER_POSITION must not be added.
726 */
727static BOOLEAN_T
728TrioIsQualifier(const char ch)
729{
730 /* QUALIFIER_POSITION is not included */
731 switch (ch)
732 {
733 case '0': case '1': case '2': case '3': case '4':
734 case '5': case '6': case '7': case '8': case '9':
735 case QUALIFIER_PLUS:
736 case QUALIFIER_MINUS:
737 case QUALIFIER_SPACE:
738 case QUALIFIER_DOT:
739 case QUALIFIER_STAR:
740 case QUALIFIER_ALTERNATIVE:
741 case QUALIFIER_SHORT:
742 case QUALIFIER_LONG:
743 case QUALIFIER_LONG_UPPER:
744 case QUALIFIER_CIRCUMFLEX:
745#if defined(QUALIFIER_SIZE_T)
746 case QUALIFIER_SIZE_T:
747#endif
748#if defined(QUALIFIER_PTRDIFF_T)
749 case QUALIFIER_PTRDIFF_T:
750#endif
751#if defined(QUALIFIER_INTMAX_T)
752 case QUALIFIER_INTMAX_T:
753#endif
754#if defined(QUALIFIER_QUAD)
755 case QUALIFIER_QUAD:
756#endif
757#if defined(QUALIFIER_SIZE_T_UPPER)
758 case QUALIFIER_SIZE_T_UPPER:
759#endif
760#if defined(QUALIFIER_WIDECHAR)
761 case QUALIFIER_WIDECHAR:
762#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000763#if defined(QUALIFIER_QUOTE)
764 case QUALIFIER_QUOTE:
765#endif
766#if defined(QUALIFIER_STICKY)
767 case QUALIFIER_STICKY:
768#endif
769#if defined(QUALIFIER_VARSIZE)
770 case QUALIFIER_VARSIZE:
771#endif
772#if defined(QUALIFIER_PARAM)
773 case QUALIFIER_PARAM:
774#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000775#if defined(QUALIFIER_FIXED_SIZE)
776 case QUALIFIER_FIXED_SIZE:
777#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000778 return TRUE;
779 default:
780 return FALSE;
781 }
782}
783
784/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000785 * TrioGenerateNan [private]
786 *
787 * Calculating NaN portably is difficult. Some compilers will emit
788 * warnings about divide by zero, and others will simply fail to
789 * generate a NaN.
790 */
791static double
792TrioGenerateNaN(void)
793{
794#if defined(TRIO_COMPILER_SUPPORTS_C99)
795 return nan(NULL);
796#elif defined(DBL_QNAN)
797 return DBL_QNAN;
798#elif defined(PLATFORM_UNIX)
799 double value;
800 void (*signal_handler)(int);
801
802 signal_handler = signal(SIGFPE, SIG_IGN);
803 value = 0.0 / 0.0;
804 signal(SIGFPE, signal_handler);
805 return value;
806#else
807 return 0.0 / 0.0;
808#endif
809}
810
811/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000812 * TrioIsNan [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +0000813 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000814static int
815TrioIsNan(double number)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000816{
Bjorn Reese70a9da52001-04-21 16:57:29 +0000817#ifdef isnan
818 /* C99 defines isnan() as a macro */
819 return isnan(number);
820#else
821 double integral, fraction;
822
823 return (/* NaN is the only number which does not compare to itself */
824 (number != number) ||
825 /* Fallback solution if NaN compares to NaN */
826 ((number != 0.0) &&
827 (fraction = modf(number, &integral),
828 integral == fraction)));
Daniel Veillard92ad2102001-03-27 12:47:33 +0000829#endif
830}
831
832/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000833 * TrioIsInfinite [private]
834 */
835static int
836TrioIsInfinite(double number)
837{
838#ifdef isinf
839 /* C99 defines isinf() as a macro */
840 return isinf(number);
841#else
842 return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));
843#endif
844}
845
846/*************************************************************************
847 * TrioSetLocale [private]
848 */
849#if defined(USE_LOCALE)
850static void
851TrioSetLocale(void)
852{
853 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000854 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000855 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000856 if ((internalLocaleValues->decimal_point) &&
857 (internalLocaleValues->decimal_point[0] != NIL))
858 {
859 StrCopyMax(internalDecimalPoint,
860 sizeof(internalDecimalPoint),
861 internalLocaleValues->decimal_point);
862 }
863 if ((internalLocaleValues->thousands_sep) &&
864 (internalLocaleValues->thousands_sep[0] != NIL))
865 {
866 StrCopyMax(internalThousandSeparator,
867 sizeof(internalThousandSeparator),
868 internalLocaleValues->thousands_sep);
869 }
870 if ((internalLocaleValues->grouping) &&
871 (internalLocaleValues->grouping[0] != NIL))
872 {
873 StrCopyMax(internalGrouping,
874 sizeof(internalGrouping),
875 internalLocaleValues->grouping);
876 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000877 }
878}
879#endif /* defined(USE_LOCALE) */
880
881/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000882 * TrioGetPosition [private]
883 *
884 * Get the %n$ position.
885 */
886static int
Bjorn Reese70a9da52001-04-21 16:57:29 +0000887TrioGetPosition(const char *format,
888 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000889{
890 char *tmpformat;
891 int number = 0;
892 int index = *indexPointer;
893
894 number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
895 index = (int)(tmpformat - format);
896 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
897 {
898 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000899 /*
900 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000901 * the array it is indexing starts from 0.
902 */
903 return number - 1;
904 }
905 return NO_POSITION;
906}
907
908/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000909 * TrioFindNamespace [private]
910 *
911 * Find registered user-defined specifier.
912 * The prev argument is used for optimisation only.
913 */
914static userdef_T *
915TrioFindNamespace(const char *name, userdef_T **prev)
916{
917 userdef_T *def;
918
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000919 if (internalEnterCriticalRegion)
920 (void)internalEnterCriticalRegion(NULL);
921
Bjorn Reese70a9da52001-04-21 16:57:29 +0000922 for (def = internalUserDef; def; def = def->next)
923 {
924 /* Case-sensitive string comparison */
925 if (StrEqualCase(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000926 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000927
928 if (prev)
929 *prev = def;
930 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000931
932 if (internalLeaveCriticalRegion)
933 (void)internalLeaveCriticalRegion(NULL);
934
Bjorn Reese70a9da52001-04-21 16:57:29 +0000935 return def;
936}
937
938/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000939 * TrioPreprocess [private]
940 *
941 * Description:
942 * Parse the format string
943 */
944static int
945TrioPreprocess(int type,
946 const char *format,
947 parameter_T *parameters,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000948 va_list arglist,
949 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000950{
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000951#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +0000952 /* Count the number of times a parameter is referenced */
953 unsigned short usedEntries[MAX_PARAMETERS];
954#endif
955 /* Parameter counters */
956 int parameterPosition;
957 int currentParam;
958 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000959 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000960 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000961 int width;
962 int precision;
963 int varsize;
964 int base;
965 int index; /* Index into formatting string */
966 int dots; /* Count number of dots in modifier part */
967 BOOLEAN_T positional; /* Does the specifier have a positional? */
968 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000969 /*
970 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +0000971 * read from the va_args (this is necessary to handle positionals)
972 */
973 int indices[MAX_PARAMETERS];
974 int pos = 0;
975 /* Various variables */
976 char ch;
977 int charlen;
978 int i = -1;
979 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000980 char *tmpformat;
981
982
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000983#if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +0000984 /*
985 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +0000986 * know which entries we have used.
987 */
988 memset(usedEntries, 0, sizeof(usedEntries));
989#endif
990
991 index = 0;
992 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000993#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000994 mblen(NULL, 0);
995#endif
996
997 while (format[index])
998 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000999#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001000 if (! isascii(format[index]))
1001 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001002 /*
1003 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001004 * modifiers, so we skip over them.
1005 */
1006 charlen = mblen(&format[index], MB_LEN_MAX);
1007 index += (charlen > 0) ? charlen : 1;
1008 continue; /* while */
1009 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001010#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001011 if (CHAR_IDENTIFIER == format[index++])
1012 {
1013 if (CHAR_IDENTIFIER == format[index])
1014 {
1015 index++;
1016 continue; /* while */
1017 }
1018
1019 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001020 dots = 0;
1021 currentParam = TrioGetPosition(format, &index);
1022 positional = (NO_POSITION != currentParam);
1023 if (!positional)
1024 {
1025 /* We have no positional, get the next counter */
1026 currentParam = parameterPosition;
1027 }
1028 if(currentParam >= MAX_PARAMETERS)
1029 {
1030 /* Bail out completely to make the error more obvious */
1031 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1032 }
1033
1034 if (currentParam > maxParam)
1035 maxParam = currentParam;
1036
1037 /* Default values */
1038 width = NO_WIDTH;
1039 precision = NO_PRECISION;
1040 base = NO_BASE;
1041 varsize = NO_SIZE;
1042
Bjorn Reese70a9da52001-04-21 16:57:29 +00001043 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001044 {
1045 ch = format[index++];
1046
Daniel Veillard92ad2102001-03-27 12:47:33 +00001047 switch (ch)
1048 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001049 case QUALIFIER_SPACE:
1050 flags |= FLAGS_SPACE;
1051 break;
1052
1053 case QUALIFIER_PLUS:
1054 flags |= FLAGS_SHOWSIGN;
1055 break;
1056
1057 case QUALIFIER_MINUS:
1058 flags |= FLAGS_LEFTADJUST;
1059 flags &= ~FLAGS_NILPADDING;
1060 break;
1061
1062 case QUALIFIER_ALTERNATIVE:
1063 flags |= FLAGS_ALTERNATIVE;
1064 break;
1065
1066 case QUALIFIER_DOT:
1067 if (dots == 0) /* Precision */
1068 {
1069 dots++;
1070
1071 /* Skip if no precision */
1072 if (QUALIFIER_DOT == format[index])
1073 break;
1074
1075 /* After the first dot we have the precision */
1076 flags |= FLAGS_PRECISION;
1077 if ((QUALIFIER_STAR == format[index]) ||
1078 (QUALIFIER_PARAM == format[index]))
1079 {
1080 index++;
1081 flags |= FLAGS_PRECISION_PARAMETER;
1082
1083 precision = TrioGetPosition(format, &index);
1084 if (precision == NO_POSITION)
1085 {
1086 parameterPosition++;
1087 if (positional)
1088 precision = parameterPosition;
1089 else
1090 {
1091 precision = currentParam;
1092 currentParam = precision + 1;
1093 }
1094 }
1095 else
1096 {
1097 if (! positional)
1098 currentParam = precision + 1;
1099 if (width > maxParam)
1100 maxParam = precision;
1101 }
1102 if (currentParam > maxParam)
1103 maxParam = currentParam;
1104 }
1105 else
1106 {
1107 precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1108 index = (int)(tmpformat - format);
1109 }
1110 }
1111 else if (dots == 1) /* Base */
1112 {
1113 dots++;
1114
1115 /* After the second dot we have the base */
1116 flags |= FLAGS_BASE;
1117 if ((QUALIFIER_STAR == format[index]) ||
1118 (QUALIFIER_PARAM == format[index]))
1119 {
1120 index++;
1121 flags |= FLAGS_BASE_PARAMETER;
1122 base = TrioGetPosition(format, &index);
1123 if (base == NO_POSITION)
1124 {
1125 parameterPosition++;
1126 if (positional)
1127 base = parameterPosition;
1128 else
1129 {
1130 base = currentParam;
1131 currentParam = base + 1;
1132 }
1133 }
1134 else
1135 {
1136 if (! positional)
1137 currentParam = base + 1;
1138 if (base > maxParam)
1139 maxParam = base;
1140 }
1141 if (currentParam > maxParam)
1142 maxParam = currentParam;
1143 }
1144 else
1145 {
1146 base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1147 if (base > MAX_BASE)
1148 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1149 index = (int)(tmpformat - format);
1150 }
1151 }
1152 else
1153 {
1154 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1155 }
1156 break; /* QUALIFIER_DOT */
1157
1158 case QUALIFIER_PARAM:
1159 type = TYPE_PRINT;
1160 /* FALLTHROUGH */
1161 case QUALIFIER_STAR:
1162 /* This has different meanings for print and scan */
1163 if (TYPE_PRINT == type)
1164 {
1165 /* Read with from parameter */
1166 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1167 width = TrioGetPosition(format, &index);
1168 if (width == NO_POSITION)
1169 {
1170 parameterPosition++;
1171 if (positional)
1172 width = parameterPosition;
1173 else
1174 {
1175 width = currentParam;
1176 currentParam = width + 1;
1177 }
1178 }
1179 else
1180 {
1181 if (! positional)
1182 currentParam = width + 1;
1183 if (width > maxParam)
1184 maxParam = width;
1185 }
1186 if (currentParam > maxParam)
1187 maxParam = currentParam;
1188 }
1189 else
1190 {
1191 /* Scan, but do not store result */
1192 flags |= FLAGS_IGNORE;
1193 }
1194
1195 break; /* QUALIFIER_STAR */
1196
1197 case '0':
1198 if (! (flags & FLAGS_LEFTADJUST))
1199 flags |= FLAGS_NILPADDING;
1200 /* FALLTHROUGH */
1201 case '1': case '2': case '3': case '4':
1202 case '5': case '6': case '7': case '8': case '9':
1203 flags |= FLAGS_WIDTH;
1204 /* &format[index - 1] is used to "rewind" the read
1205 * character from format
1206 */
1207 width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
1208 index = (int)(tmpformat - format);
1209 break;
1210
1211 case QUALIFIER_SHORT:
1212 if (flags & FLAGS_SHORTSHORT)
1213 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1214 else if (flags & FLAGS_SHORT)
1215 flags |= FLAGS_SHORTSHORT;
1216 else
1217 flags |= FLAGS_SHORT;
1218 break;
1219
1220 case QUALIFIER_LONG:
1221 if (flags & FLAGS_QUAD)
1222 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1223 else if (flags & FLAGS_LONG)
1224 flags |= FLAGS_QUAD;
1225 else
1226 flags |= FLAGS_LONG;
1227 break;
1228
1229 case QUALIFIER_LONG_UPPER:
1230 flags |= FLAGS_LONGDOUBLE;
1231 break;
1232
1233#if defined(QUALIFIER_SIZE_T)
1234 case QUALIFIER_SIZE_T:
1235 flags |= FLAGS_SIZE_T;
1236 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001237 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001238 flags |= FLAGS_QUAD;
1239 else if (sizeof(size_t) == sizeof(long))
1240 flags |= FLAGS_LONG;
1241 break;
1242#endif
1243
1244#if defined(QUALIFIER_PTRDIFF_T)
1245 case QUALIFIER_PTRDIFF_T:
1246 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001247 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001248 flags |= FLAGS_QUAD;
1249 else if (sizeof(ptrdiff_t) == sizeof(long))
1250 flags |= FLAGS_LONG;
1251 break;
1252#endif
1253
1254#if defined(QUALIFIER_INTMAX_T)
1255 case QUALIFIER_INTMAX_T:
1256 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001257 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001258 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001259 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001260 flags |= FLAGS_LONG;
1261 break;
1262#endif
1263
1264#if defined(QUALIFIER_QUAD)
1265 case QUALIFIER_QUAD:
1266 flags |= FLAGS_QUAD;
1267 break;
1268#endif
1269
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001270#if defined(QUALIFIER_FIXED_SIZE)
1271 case QUALIFIER_FIXED_SIZE:
1272 if (flags & FLAGS_FIXED_SIZE)
1273 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1274
1275 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1276 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1277 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1278
1279 if ((format[index] == '6') &&
1280 (format[index + 1] == '4'))
1281 {
1282 varsize = sizeof(trio_int64_t);
1283 index += 2;
1284 }
1285 else if ((format[index] == '3') &&
1286 (format[index + 1] == '2'))
1287 {
1288 varsize = sizeof(trio_int32_t);
1289 index += 2;
1290 }
1291 else if ((format[index] == '1') &&
1292 (format[index + 1] == '6'))
1293 {
1294 varsize = sizeof(trio_int16_t);
1295 index += 2;
1296 }
1297 else if (format[index] == '8')
1298 {
1299 varsize = sizeof(trio_int8_t);
1300 index++;
1301 }
1302 else
1303 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1304
1305 flags |= FLAGS_FIXED_SIZE;
1306 break;
1307#endif
1308
Daniel Veillard92ad2102001-03-27 12:47:33 +00001309#if defined(QUALIFIER_WIDECHAR)
1310 case QUALIFIER_WIDECHAR:
1311 flags |= FLAGS_WIDECHAR;
1312 break;
1313#endif
1314
1315#if defined(QUALIFIER_SIZE_T_UPPER)
1316 case QUALIFIER_SIZE_T_UPPER:
1317 break;
1318#endif
1319
1320#if defined(QUALIFIER_QUOTE)
1321 case QUALIFIER_QUOTE:
1322 flags |= FLAGS_QUOTE;
1323 break;
1324#endif
1325
1326#if defined(QUALIFIER_STICKY)
1327 case QUALIFIER_STICKY:
1328 flags |= FLAGS_STICKY;
1329 got_sticky = TRUE;
1330 break;
1331#endif
1332
1333#if defined(QUALIFIER_VARSIZE)
1334 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001335 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001336 parameterPosition++;
1337 if (positional)
1338 varsize = parameterPosition;
1339 else
1340 {
1341 varsize = currentParam;
1342 currentParam = varsize + 1;
1343 }
1344 if (currentParam > maxParam)
1345 maxParam = currentParam;
1346 break;
1347#endif
1348
1349 default:
1350 /* Bail out completely to make the error more obvious */
1351 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1352 }
1353 } /* while qualifier */
1354
Bjorn Reese70a9da52001-04-21 16:57:29 +00001355 /*
1356 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001357 * read later.
1358 */
1359 if (flags & FLAGS_WIDTH_PARAMETER)
1360 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001361#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001362 usedEntries[width] += 1;
1363#endif
1364 parameters[pos].type = FORMAT_PARAMETER;
1365 indices[width] = pos;
1366 width = pos++;
1367 }
1368 if (flags & FLAGS_PRECISION_PARAMETER)
1369 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001370#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001371 usedEntries[precision] += 1;
1372#endif
1373 parameters[pos].type = FORMAT_PARAMETER;
1374 indices[precision] = pos;
1375 precision = pos++;
1376 }
1377 if (flags & FLAGS_BASE_PARAMETER)
1378 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001379#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001380 usedEntries[base] += 1;
1381#endif
1382 parameters[pos].type = FORMAT_PARAMETER;
1383 indices[base] = pos;
1384 base = pos++;
1385 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001386 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001387 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001388#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001389 usedEntries[varsize] += 1;
1390#endif
1391 parameters[pos].type = FORMAT_PARAMETER;
1392 indices[varsize] = pos;
1393 varsize = pos++;
1394 }
1395
1396 indices[currentParam] = pos;
1397
1398 switch (format[index++])
1399 {
1400#if defined(SPECIFIER_CHAR_UPPER)
1401 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001402 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001403 /* FALLTHROUGH */
1404#endif
1405 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001406 if (flags & FLAGS_LONG)
1407 flags |= FLAGS_WIDECHAR;
1408 else if (flags & FLAGS_SHORT)
1409 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001410 parameters[pos].type = FORMAT_CHAR;
1411 break;
1412
1413#if defined(SPECIFIER_STRING_UPPER)
1414 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001415 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001416 /* FALLTHROUGH */
1417#endif
1418 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001419 if (flags & FLAGS_LONG)
1420 flags |= FLAGS_WIDECHAR;
1421 else if (flags & FLAGS_SHORT)
1422 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001423 parameters[pos].type = FORMAT_STRING;
1424 break;
1425
1426 case SPECIFIER_GROUP:
1427 if (TYPE_SCAN == type)
1428 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001429 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001430 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001431 if (format[index] == QUALIFIER_CIRCUMFLEX)
1432 index++;
1433 if (format[index] == SPECIFIER_UNGROUP)
1434 index++;
1435 if (format[index] == QUALIFIER_MINUS)
1436 index++;
1437 /* Skip nested brackets */
1438 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001439 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001440 if (format[index] == SPECIFIER_GROUP)
1441 {
1442 depth++;
1443 }
1444 else if (format[index] == SPECIFIER_UNGROUP)
1445 {
1446 if (--depth <= 0)
1447 {
1448 index++;
1449 break;
1450 }
1451 }
1452 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001453 }
1454 }
1455 break;
1456
1457 case SPECIFIER_INTEGER:
1458 parameters[pos].type = FORMAT_INT;
1459 break;
1460
1461 case SPECIFIER_UNSIGNED:
1462 flags |= FLAGS_UNSIGNED;
1463 parameters[pos].type = FORMAT_INT;
1464 break;
1465
1466 case SPECIFIER_DECIMAL:
1467 /* Disable base modifier */
1468 flags &= ~FLAGS_BASE_PARAMETER;
1469 base = BASE_DECIMAL;
1470 parameters[pos].type = FORMAT_INT;
1471 break;
1472
1473 case SPECIFIER_OCTAL:
1474 flags &= ~FLAGS_BASE_PARAMETER;
1475 base = BASE_OCTAL;
1476 parameters[pos].type = FORMAT_INT;
1477 break;
1478
1479#if defined(SPECIFIER_BINARY)
1480 case SPECIFIER_BINARY_UPPER:
1481 flags |= FLAGS_UPPER;
1482 /* FALLTHROUGH */
1483 case SPECIFIER_BINARY:
1484 flags |= FLAGS_NILPADDING;
1485 flags &= ~FLAGS_BASE_PARAMETER;
1486 base = BASE_BINARY;
1487 parameters[pos].type = FORMAT_INT;
1488 break;
1489#endif
1490
1491 case SPECIFIER_HEX_UPPER:
1492 flags |= FLAGS_UPPER;
1493 /* FALLTHROUGH */
1494 case SPECIFIER_HEX:
1495 flags |= FLAGS_UNSIGNED;
1496 flags &= ~FLAGS_BASE_PARAMETER;
1497 base = BASE_HEX;
1498 parameters[pos].type = FORMAT_INT;
1499 break;
1500
1501 case SPECIFIER_FLOAT_E_UPPER:
1502 flags |= FLAGS_UPPER;
1503 /* FALLTHROUGH */
1504 case SPECIFIER_FLOAT_E:
1505 flags |= FLAGS_FLOAT_E;
1506 parameters[pos].type = FORMAT_DOUBLE;
1507 break;
1508
1509 case SPECIFIER_FLOAT_G_UPPER:
1510 flags |= FLAGS_UPPER;
1511 /* FALLTHROUGH */
1512 case SPECIFIER_FLOAT_G:
1513 flags |= FLAGS_FLOAT_G;
1514 parameters[pos].type = FORMAT_DOUBLE;
1515 break;
1516
1517 case SPECIFIER_FLOAT_F_UPPER:
1518 flags |= FLAGS_UPPER;
1519 /* FALLTHROUGH */
1520 case SPECIFIER_FLOAT_F:
1521 parameters[pos].type = FORMAT_DOUBLE;
1522 break;
1523
1524 case SPECIFIER_POINTER:
1525 parameters[pos].type = FORMAT_POINTER;
1526 break;
1527
1528 case SPECIFIER_COUNT:
1529 parameters[pos].type = FORMAT_COUNT;
1530 break;
1531
1532#if defined(SPECIFIER_HEXFLOAT)
1533# if defined(SPECIFIER_HEXFLOAT_UPPER)
1534 case SPECIFIER_HEXFLOAT_UPPER:
1535 flags |= FLAGS_UPPER;
1536 /* FALLTHROUGH */
1537# endif
1538 case SPECIFIER_HEXFLOAT:
1539 base = BASE_HEX;
1540 parameters[pos].type = FORMAT_DOUBLE;
1541 break;
1542#endif
1543
1544#if defined(FORMAT_ERRNO)
1545 case SPECIFIER_ERRNO:
1546 parameters[pos].type = FORMAT_ERRNO;
1547 break;
1548#endif
1549
Bjorn Reese70a9da52001-04-21 16:57:29 +00001550#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1551 case SPECIFIER_USER_DEFINED_BEGIN:
1552 {
1553 unsigned int max;
1554 int without_namespace = TRUE;
1555
1556 parameters[pos].type = FORMAT_USER_DEFINED;
1557 parameters[pos].user_name[0] = NIL;
1558 tmpformat = (char *)&format[index];
1559
1560 while ((ch = format[index]))
1561 {
1562 index++;
1563 if (ch == SPECIFIER_USER_DEFINED_END)
1564 {
1565 if (without_namespace)
1566 {
1567 /* We must get the handle first */
1568 parameters[pos].type = FORMAT_PARAMETER;
1569 parameters[pos].indexAfterSpecifier = index;
1570 parameters[pos].flags = FLAGS_USER_DEFINED;
1571 /* Adjust parameters for insertion of new one */
1572 pos++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001573# if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +00001574 usedEntries[currentParam] += 1;
1575# endif
1576 parameters[pos].type = FORMAT_USER_DEFINED;
1577 currentParam++;
1578 indices[currentParam] = pos;
1579 if (currentParam > maxParam)
1580 maxParam = currentParam;
1581 }
1582 /* Copy the user data */
1583 max = (unsigned int)(&format[index] - tmpformat);
1584 if (max > MAX_USER_DATA)
1585 max = MAX_USER_DATA;
1586 StrCopyMax(parameters[pos].user_data,
1587 max,
1588 tmpformat);
1589 break; /* while */
1590 }
1591 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1592 {
1593 without_namespace = FALSE;
1594 /* Copy the namespace for later looking-up */
1595 max = (int)(&format[index] - tmpformat);
1596 if (max > MAX_USER_NAME)
1597 max = MAX_USER_NAME;
1598 StrCopyMax(parameters[pos].user_name,
1599 max,
1600 tmpformat);
1601 tmpformat = (char *)&format[index];
1602 }
1603 }
1604 if (ch != SPECIFIER_USER_DEFINED_END)
1605 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1606 }
1607 break;
1608#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1609
Daniel Veillard92ad2102001-03-27 12:47:33 +00001610 default:
1611 /* Bail out completely to make the error more obvious */
1612 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1613 }
1614
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001615#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001616 /* Count the number of times this entry has been used */
1617 usedEntries[currentParam] += 1;
1618#endif
1619
1620 /* Find last sticky parameters */
1621 if (got_sticky && !(flags & FLAGS_STICKY))
1622 {
1623 for (i = pos - 1; i >= 0; i--)
1624 {
1625 if (parameters[i].type == FORMAT_PARAMETER)
1626 continue;
1627 if ((parameters[i].flags & FLAGS_STICKY) &&
1628 (parameters[i].type == parameters[pos].type))
1629 {
1630 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001631 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001632 if (width == NO_WIDTH)
1633 width = parameters[i].width;
1634 if (precision == NO_PRECISION)
1635 precision = parameters[i].precision;
1636 if (base == NO_BASE)
1637 base = parameters[i].base;
1638 break;
1639 }
1640 }
1641 }
1642
1643 parameters[pos].indexAfterSpecifier = index;
1644 parameters[pos].flags = flags;
1645 parameters[pos].width = width;
1646 parameters[pos].precision = precision;
1647 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1648 parameters[pos].varsize = varsize;
1649 pos++;
1650
Bjorn Reese70a9da52001-04-21 16:57:29 +00001651 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001652 parameterPosition++;
1653
1654 } /* if identifier */
1655
1656 } /* while format characters left */
1657
1658 for (num = 0; num <= maxParam; num++)
1659 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001660#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001661 if (usedEntries[num] != 1)
1662 {
1663 if (usedEntries[num] == 0) /* gap detected */
1664 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1665 else /* double references detected */
1666 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1667 }
1668#endif
1669
1670 i = indices[num];
1671
Bjorn Reese70a9da52001-04-21 16:57:29 +00001672 /*
1673 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001674 * so it makes no sense to check the ignore flag (besides,
1675 * the flags variable is not set for that particular type)
1676 */
1677 if ((parameters[i].type != FORMAT_PARAMETER) &&
1678 (parameters[i].flags & FLAGS_IGNORE))
1679 continue; /* for all arguments */
1680
Bjorn Reese70a9da52001-04-21 16:57:29 +00001681 /*
1682 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001683 * default argument promotions:
1684 *
1685 * char = int
1686 * short = int
1687 * unsigned char = unsigned int
1688 * unsigned short = unsigned int
1689 * float = double
1690 *
1691 * In addition to the ANSI C89 these types are read (the
1692 * default argument promotions of C99 has not been
1693 * considered yet)
1694 *
1695 * long long
1696 * long double
1697 * size_t
1698 * ptrdiff_t
1699 * intmax_t
1700 */
1701 switch (parameters[i].type)
1702 {
1703 case FORMAT_GROUP:
1704 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001705#if TRIO_WIDECHAR
1706 if (flags & FLAGS_WIDECHAR)
1707 {
1708 parameters[i].data.wstring = (argarray == NULL)
1709 ? va_arg(arglist, wchar_t *)
1710 : (wchar_t *)(argarray[num]);
1711 }
1712 else
1713#endif
1714 {
1715 parameters[i].data.string = (argarray == NULL)
1716 ? va_arg(arglist, char *)
1717 : (char *)(argarray[num]);
1718 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001719 break;
1720
1721 case FORMAT_POINTER:
1722 case FORMAT_COUNT:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001723 case FORMAT_USER_DEFINED:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001724 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001725 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001726 ? va_arg(arglist, void *)
1727 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001728 break;
1729
1730 case FORMAT_CHAR:
1731 case FORMAT_INT:
1732 if (TYPE_SCAN == type)
1733 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001734 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001735 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001736 (trio_uintmax_t *)va_arg(arglist, void *);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001737 else
1738 {
1739 if (parameters[i].type == FORMAT_CHAR)
1740 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001741 (trio_uintmax_t *)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001742 else if (parameters[i].flags & FLAGS_SHORT)
1743 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001744 (trio_uintmax_t *)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001745 else
1746 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001747 (trio_uintmax_t *)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001748 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001749 }
1750 else
1751 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001752#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
1753 if ((parameters[i].flags & FLAGS_VARSIZE_PARAMETER) ||
1754 (parameters[i].flags & FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001755 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001756 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1757 {
1758 /*
1759 * Variable sizes are mapped onto the fixed sizes, in
1760 * accordance with integer promotion.
1761 *
1762 * Please note that this may not be portable, as we
1763 * only guess the size, not the layout of the numbers.
1764 * For example, if int is little-endian, and long is
1765 * big-endian, then this will fail.
1766 */
1767 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1768 }
1769 else
1770 {
1771 /* Used for the I<bits> modifiers */
1772 varsize = parameters[i].varsize;
1773 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001774 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001775
Daniel Veillard92ad2102001-03-27 12:47:33 +00001776 if (varsize <= (int)sizeof(int))
1777 ;
1778 else if (varsize <= (int)sizeof(long))
1779 parameters[i].flags |= FLAGS_LONG;
1780#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001781 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001782 parameters[i].flags |= FLAGS_QUAD;
1783 else
1784 parameters[i].flags |= FLAGS_INTMAX_T;
1785#else
1786 else
1787 parameters[i].flags |= FLAGS_QUAD;
1788#endif
1789 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001790#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001791#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1792 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001793 parameters[i].data.number.as_unsigned = (argarray == NULL)
1794 ? (trio_uintmax_t)va_arg(arglist, size_t)
1795 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001796 else
1797#endif
1798#if defined(QUALIFIER_PTRDIFF_T)
1799 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001800 parameters[i].data.number.as_unsigned = (argarray == NULL)
1801 ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
1802 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001803 else
1804#endif
1805#if defined(QUALIFIER_INTMAX_T)
1806 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001807 parameters[i].data.number.as_unsigned = (argarray == NULL)
1808 ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
1809 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001810 else
1811#endif
1812 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001813 parameters[i].data.number.as_unsigned = (argarray == NULL)
1814 ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
1815 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001816 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001817 parameters[i].data.number.as_unsigned = (argarray == NULL)
1818 ? (trio_uintmax_t)va_arg(arglist, long)
1819 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001820 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001821 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001822 if (argarray == NULL)
1823 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001824 else
1825 {
1826 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001827 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001828 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001829 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001830 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001831 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001832 }
1833 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001834 }
1835 break;
1836
1837 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001838 /*
1839 * The parameter for the user-defined specifier is a pointer,
1840 * whereas the rest (width, precision, base) uses an integer.
1841 */
1842 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001843 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001844 ? va_arg(arglist, void *)
1845 : argarray[num];
1846 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001847 parameters[i].data.number.as_unsigned = (argarray == NULL)
1848 ? (trio_uintmax_t)va_arg(arglist, int)
1849 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001850 break;
1851
1852 case FORMAT_DOUBLE:
1853 if (TYPE_SCAN == type)
1854 {
1855 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001856 parameters[i].data.longdoublePointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001857 ? va_arg(arglist, long double *)
1858 : (long double *)((long double *)argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001859 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001860 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001861 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001862 parameters[i].data.doublePointer =
1863 va_arg(arglist, double *);
1864 else
1865 {
1866 if (parameters[i].flags & FLAGS_SHORT)
1867 parameters[i].data.doublePointer =
1868 (double *)((float *)argarray[num]);
1869 else
1870 parameters[i].data.doublePointer =
1871 (double *)((double *)argarray[num]);
1872 }
1873 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001874 }
1875 else
1876 {
1877 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001878 parameters[i].data.longdoubleNumber = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001879 ? va_arg(arglist, long double)
1880 : (long double)(*((long double *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001881 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001882 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001883 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001884 parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
1885 else
1886 {
1887 if (parameters[i].flags & FLAGS_SHORT)
1888 parameters[i].data.longdoubleNumber = (long double)(*((float *)argarray[num]));
1889 else
1890 parameters[i].data.longdoubleNumber = (long double)(long double)(*((double *)argarray[num]));
1891 }
1892 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001893 }
1894 break;
1895
1896#if defined(FORMAT_ERRNO)
1897 case FORMAT_ERRNO:
1898 parameters[i].data.errorNumber = errno;
1899 break;
1900#endif
1901
1902 default:
1903 break;
1904 }
1905 } /* for all specifiers */
1906 return num;
1907}
1908
1909
1910/*************************************************************************
1911 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00001912 * @FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00001913 *
1914 ************************************************************************/
1915
1916
1917/*************************************************************************
1918 * TrioWriteNumber [private]
1919 *
1920 * Description:
1921 * Output a number.
1922 * The complexity of this function is a result of the complexity
1923 * of the dependencies of the flags.
1924 */
1925static void
1926TrioWriteNumber(trio_T *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001927 trio_uintmax_t number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001928 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001929 int width,
1930 int precision,
1931 int base)
1932{
1933 BOOLEAN_T isNegative;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001934 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001935 char *bufferend;
1936 char *pointer;
1937 const char *digits;
1938 int i;
1939 int length;
1940 char *p;
1941 int charsPerThousand;
1942 int groupingIndex;
1943 int count;
1944
1945 assert(VALID(self));
1946 assert(VALID(self->OutStream));
1947 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
1948
Bjorn Reese70a9da52001-04-21 16:57:29 +00001949 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001950
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001951 isNegative = (flags & FLAGS_UNSIGNED)
1952 ? FALSE
1953 : ((trio_intmax_t)number < 0);
1954 if (isNegative)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001955 number = -number;
1956
1957 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001958 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001959 else if (flags & FLAGS_LONG)
1960 number &= (unsigned long)-1;
1961 else
1962 number &= (unsigned int)-1;
1963
1964 /* Build number */
1965 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1966 *pointer-- = NIL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001967 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001968 groupingIndex = 1;
1969 for (i = 1; i < (int)sizeof(buffer); i++)
1970 {
1971 *pointer-- = digits[number % base];
1972 number /= base;
1973 if (number == 0)
1974 break;
1975
1976 if ((flags & FLAGS_QUOTE)
1977 && (charsPerThousand != NO_GROUPING)
1978 && (i % charsPerThousand == 0))
1979 {
1980 /*
1981 * We are building the number from the least significant
1982 * to the most significant digit, so we have to copy the
1983 * thousand separator backwards
1984 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001985 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001986 if (((int)(pointer - buffer) - length) > 0)
1987 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001988 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001989 while (length-- > 0)
1990 *pointer-- = *p--;
1991 }
1992
1993 /* Advance to next grouping number */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001994 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00001995 {
1996 case CHAR_MAX: /* Disable grouping */
1997 charsPerThousand = NO_GROUPING;
1998 break;
1999 case 0: /* Repeat last group */
2000 break;
2001 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002002 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002003 break;
2004 }
2005 }
2006 }
2007
2008 /* Adjust width */
2009 width -= (bufferend - pointer) - 1;
2010
2011 /* Adjust precision */
2012 if (NO_PRECISION != precision)
2013 {
2014 precision -= (bufferend - pointer) - 1;
2015 if (precision < 0)
2016 precision = 0;
2017 flags |= FLAGS_NILPADDING;
2018 }
2019
2020 /* Adjust width further */
2021 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2022 width--;
2023 if (flags & FLAGS_ALTERNATIVE)
2024 {
2025 switch (base)
2026 {
2027 case BASE_BINARY:
2028 case BASE_HEX:
2029 width -= 2;
2030 break;
2031 case BASE_OCTAL:
2032 width--;
2033 break;
2034 default:
2035 break;
2036 }
2037 }
2038
2039 /* Output prefixes spaces if needed */
2040 if (! ((flags & FLAGS_LEFTADJUST) ||
2041 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2042 {
2043 count = (precision == NO_PRECISION) ? 0 : precision;
2044 while (width-- > count)
2045 self->OutStream(self, CHAR_ADJUST);
2046 }
2047
2048 /* width has been adjusted for signs and alternatives */
2049 if (isNegative)
2050 self->OutStream(self, '-');
2051 else if (flags & FLAGS_SHOWSIGN)
2052 self->OutStream(self, '+');
2053 else if (flags & FLAGS_SPACE)
2054 self->OutStream(self, ' ');
2055
2056 if (flags & FLAGS_ALTERNATIVE)
2057 {
2058 switch (base)
2059 {
2060 case BASE_BINARY:
2061 self->OutStream(self, '0');
2062 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2063 break;
2064
2065 case BASE_OCTAL:
2066 self->OutStream(self, '0');
2067 break;
2068
2069 case BASE_HEX:
2070 self->OutStream(self, '0');
2071 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2072 break;
2073
2074 default:
2075 break;
2076 } /* switch base */
2077 }
2078
2079 /* Output prefixed zero padding if needed */
2080 if (flags & FLAGS_NILPADDING)
2081 {
2082 if (precision == NO_PRECISION)
2083 precision = width;
2084 while (precision-- > 0)
2085 {
2086 self->OutStream(self, '0');
2087 width--;
2088 }
2089 }
2090
2091 /* Output the number itself */
2092 while (*(++pointer))
2093 {
2094 self->OutStream(self, *pointer);
2095 }
2096
2097 /* Output trailing spaces if needed */
2098 if (flags & FLAGS_LEFTADJUST)
2099 {
2100 while (width-- > 0)
2101 self->OutStream(self, CHAR_ADJUST);
2102 }
2103}
2104
2105/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002106 * TrioWriteStringCharacter [private]
2107 *
2108 * Description:
2109 * Output a single character of a string
2110 */
2111static void
2112TrioWriteStringCharacter(trio_T *self,
2113 int ch,
2114 unsigned long flags)
2115{
2116 if (flags & FLAGS_ALTERNATIVE)
2117 {
2118 if (! (isprint(ch) || isspace(ch)))
2119 {
2120 /*
2121 * Non-printable characters are converted to C escapes or
2122 * \number, if no C escape exists.
2123 */
2124 self->OutStream(self, CHAR_BACKSLASH);
2125 switch (ch)
2126 {
2127 case '\007': self->OutStream(self, 'a'); break;
2128 case '\b': self->OutStream(self, 'b'); break;
2129 case '\f': self->OutStream(self, 'f'); break;
2130 case '\n': self->OutStream(self, 'n'); break;
2131 case '\r': self->OutStream(self, 'r'); break;
2132 case '\t': self->OutStream(self, 't'); break;
2133 case '\v': self->OutStream(self, 'v'); break;
2134 case '\\': self->OutStream(self, '\\'); break;
2135 default:
2136 self->OutStream(self, 'x');
2137 TrioWriteNumber(self, (trio_intmax_t)ch,
2138 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2139 2, 2, BASE_HEX);
2140 break;
2141 }
2142 }
2143 else if (ch == CHAR_BACKSLASH)
2144 {
2145 self->OutStream(self, CHAR_BACKSLASH);
2146 self->OutStream(self, CHAR_BACKSLASH);
2147 }
2148 else
2149 {
2150 self->OutStream(self, ch);
2151 }
2152 }
2153 else
2154 {
2155 self->OutStream(self, ch);
2156 }
2157}
2158
2159/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002160 * TrioWriteString [private]
2161 *
2162 * Description:
2163 * Output a string
2164 */
2165static void
2166TrioWriteString(trio_T *self,
2167 const char *string,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002168 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002169 int width,
2170 int precision)
2171{
2172 int length;
2173 int ch;
2174
2175 assert(VALID(self));
2176 assert(VALID(self->OutStream));
2177
2178 if (string == NULL)
2179 {
2180 string = null;
2181 length = sizeof(null) - 1;
2182 /* Disable quoting for the null pointer */
2183 flags &= (~FLAGS_QUOTE);
2184 width = 0;
2185 }
2186 else
2187 {
2188 length = StrLength(string);
2189 }
2190 if ((NO_PRECISION != precision) &&
2191 (precision < length))
2192 {
2193 length = precision;
2194 }
2195 width -= length;
2196
2197 if (flags & FLAGS_QUOTE)
2198 self->OutStream(self, CHAR_QUOTE);
2199
2200 if (! (flags & FLAGS_LEFTADJUST))
2201 {
2202 while (width-- > 0)
2203 self->OutStream(self, CHAR_ADJUST);
2204 }
2205
2206 while (length-- > 0)
2207 {
2208 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002209 ch = (int)((unsigned char)(*string++));
2210 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002211 }
2212
2213 if (flags & FLAGS_LEFTADJUST)
2214 {
2215 while (width-- > 0)
2216 self->OutStream(self, CHAR_ADJUST);
2217 }
2218 if (flags & FLAGS_QUOTE)
2219 self->OutStream(self, CHAR_QUOTE);
2220}
2221
2222/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002223 * TrioWriteWideStringCharacter [private]
2224 *
2225 * Description:
2226 * Output a wide string as a multi-byte sequence
2227 */
2228#if TRIO_WIDECHAR
2229static int
2230TrioWriteWideStringCharacter(trio_T *self,
2231 wchar_t wch,
2232 unsigned long flags,
2233 int width)
2234{
2235 int size;
2236 int i;
2237 int ch;
2238 char *string;
2239 char buffer[MB_LEN_MAX + 1];
2240
2241 if (width == NO_WIDTH)
2242 width = sizeof(buffer);
2243
2244 size = wctomb(buffer, wch);
2245 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2246 return 0;
2247
2248 string = buffer;
2249 i = size;
2250 while ((width >= i) && (width-- > 0) && (i-- > 0))
2251 {
2252 /* The ctype parameters must be an unsigned char (or EOF) */
2253 ch = (int)((unsigned char)(*string++));
2254 TrioWriteStringCharacter(self, ch, flags);
2255 }
2256 return size;
2257}
2258#endif /* TRIO_WIDECHAR */
2259
2260/*************************************************************************
2261 * TrioWriteString [private]
2262 *
2263 * Description:
2264 * Output a wide character string as a multi-byte string
2265 */
2266#if TRIO_WIDECHAR
2267static void
2268TrioWriteWideString(trio_T *self,
2269 const wchar_t *wstring,
2270 unsigned long flags,
2271 int width,
2272 int precision)
2273{
2274 int length;
2275 int size;
2276
2277 assert(VALID(self));
2278 assert(VALID(self->OutStream));
2279
2280#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2281 mblen(NULL, 0);
2282#endif
2283
2284 if (wstring == NULL)
2285 {
2286 TrioWriteString(self, NULL, flags, width, precision);
2287 return;
2288 }
2289
2290 if (NO_PRECISION == precision)
2291 {
2292 length = INT_MAX;
2293 }
2294 else
2295 {
2296 length = precision;
2297 width -= length;
2298 }
2299
2300 if (flags & FLAGS_QUOTE)
2301 self->OutStream(self, CHAR_QUOTE);
2302
2303 if (! (flags & FLAGS_LEFTADJUST))
2304 {
2305 while (width-- > 0)
2306 self->OutStream(self, CHAR_ADJUST);
2307 }
2308
2309 while (length > 0)
2310 {
2311 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2312 if (size == 0)
2313 break; /* while */
2314 length -= size;
2315 }
2316
2317 if (flags & FLAGS_LEFTADJUST)
2318 {
2319 while (width-- > 0)
2320 self->OutStream(self, CHAR_ADJUST);
2321 }
2322 if (flags & FLAGS_QUOTE)
2323 self->OutStream(self, CHAR_QUOTE);
2324}
2325#endif /* TRIO_WIDECHAR */
2326
2327/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002328 * TrioWriteDouble [private]
2329 */
2330static void
2331TrioWriteDouble(trio_T *self,
2332 long double longdoubleNumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002333 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002334 int width,
2335 int precision,
2336 int base)
2337{
2338 int charsPerThousand;
2339 int length;
2340 double number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002341 double workNumber;
2342 int integerDigits;
2343 int fractionDigits;
2344 int exponentDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002345 int expectedWidth;
2346 int exponent;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002347 unsigned int uExponent = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002348 double dblBase;
2349 BOOLEAN_T isNegative;
2350 BOOLEAN_T isExponentNegative = FALSE;
2351 BOOLEAN_T isHex;
2352 const char *digits;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002353 char numberBuffer[MAX_MANTISSA_DIGITS
2354 * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002355 char *numberPointer;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002356 char exponentBuffer[MAX_EXPONENT_DIGITS + 1];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002357 char *exponentPointer = NULL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002358 int groupingIndex;
2359 char *work;
2360 int i;
2361 BOOLEAN_T onlyzero;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002362 int zeroes = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002363
2364 assert(VALID(self));
2365 assert(VALID(self->OutStream));
2366 assert(base == BASE_DECIMAL || base == BASE_HEX);
2367
2368 number = (double)longdoubleNumber;
2369
Bjorn Reese70a9da52001-04-21 16:57:29 +00002370 /* Look for infinite numbers and non-a-number first */
2371 switch (TrioIsInfinite(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002372 {
2373 case 1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002374 /* Positive infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002375 TrioWriteString(self,
2376 (flags & FLAGS_UPPER)
2377 ? INFINITE_UPPER
2378 : INFINITE_LOWER,
2379 flags, width, precision);
2380 return;
2381
2382 case -1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002383 /* Negative infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002384 TrioWriteString(self,
2385 (flags & FLAGS_UPPER)
2386 ? "-" INFINITE_UPPER
2387 : "-" INFINITE_LOWER,
2388 flags, width, precision);
2389 return;
2390
2391 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002392 /* Finitude */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002393 break;
2394 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002395 if (TrioIsNan(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002396 {
2397 TrioWriteString(self,
2398 (flags & FLAGS_UPPER)
2399 ? NAN_UPPER
2400 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002401 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002402 return;
2403 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002404
2405 /* Normal numbers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002406 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002407 isHex = (base == BASE_HEX);
2408 dblBase = (double)base;
2409
2410 if (precision == NO_PRECISION)
2411 precision = FLT_DIG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002412
2413 isNegative = (number < 0.0);
2414 if (isNegative)
2415 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002416
Daniel Veillard92ad2102001-03-27 12:47:33 +00002417 if ((flags & FLAGS_FLOAT_G) || isHex)
2418 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002419 if (precision == 0)
2420 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002421
2422 if ((number < 1.0e-4) || (number > pow(10.0, (double)precision)))
2423 {
2424 /* Use scientific notation */
2425 flags |= FLAGS_FLOAT_E;
2426 }
2427 else if (number < 1.0)
2428 {
2429 /*
2430 * Use normal notation. If the integer part of the number is
2431 * zero, then adjust the precision to include leading fractional
2432 * zeros.
2433 */
2434 workNumber = fabs(guarded_log10(number));
2435 if (workNumber - floor(workNumber) < 0.001)
2436 workNumber--;
2437 zeroes = (int)floor(workNumber);
2438 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002439 }
2440
2441 if (flags & FLAGS_FLOAT_E)
2442 {
2443 /* Scale the number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002444 workNumber = guarded_log10(number);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002445 if (workNumber == -HUGE_VAL)
2446 {
2447 exponent = 0;
2448 /* Undo setting */
2449 if (flags & FLAGS_FLOAT_G)
2450 flags &= ~FLAGS_FLOAT_E;
2451 }
2452 else
2453 {
2454 exponent = (int)floor(workNumber);
2455 number /= pow(10.0, (double)exponent);
2456 isExponentNegative = (exponent < 0);
2457 uExponent = (isExponentNegative) ? -exponent : exponent;
2458 /* No thousand separators */
2459 flags &= ~FLAGS_QUOTE;
2460 }
2461 }
2462
2463 /*
2464 * Truncated number.
2465 *
2466 * precision is number of significant digits for FLOAT_G
2467 * and number of fractional digits for others
2468 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002469 integerDigits = (floor(number) > DBL_EPSILON)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002470 ? 1 + (int)guarded_log10(floor(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002471 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002472 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002473 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002474 : zeroes + precision;
2475
2476 number = floor(0.5 + number * pow(dblBase, (double)fractionDigits));
2477 workNumber = (isHex
2478 ? guarded_log16(0.5 + number)
2479 : guarded_log10(0.5 + number));
2480 if ((int)workNumber + 1 > integerDigits + fractionDigits)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002481 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002482 if (flags & FLAGS_FLOAT_E)
2483 {
2484 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2485 exponent--;
2486 uExponent -= (isExponentNegative) ? 1 : -1;
2487 number /= dblBase;
2488 }
2489 else
2490 {
2491 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2492 integerDigits++;
2493 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002494 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002495
2496 /* Build the fraction part */
2497 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
2498 *numberPointer = NIL;
2499 onlyzero = TRUE;
2500 for (i = 0; i < fractionDigits; i++)
2501 {
2502 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2503 number = floor(number / dblBase);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002504
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002505 if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE))
2506 {
2507 /* Prune trailing zeroes */
2508 if (numberPointer[0] != digits[0])
2509 onlyzero = FALSE;
2510 else if (onlyzero && (numberPointer[0] == digits[0]))
2511 numberPointer++;
2512 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002513 else
2514 onlyzero = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002515 }
2516
2517 /* Insert decimal point */
2518 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
2519 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002520 i = StrLength(internalDecimalPoint);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002521 while (i> 0)
2522 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002523 *(--numberPointer) = internalDecimalPoint[--i];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002524 }
2525 }
2526 /* Insert the integer part and thousand separators */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002527 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002528 groupingIndex = 1;
2529 for (i = 1; i < integerDigits + 1; i++)
2530 {
2531 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2532 number = floor(number / dblBase);
2533 if (number < DBL_EPSILON)
2534 break;
2535
2536 if ((i > 0)
2537 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2538 && (charsPerThousand != NO_GROUPING)
2539 && (i % charsPerThousand == 0))
2540 {
2541 /*
2542 * We are building the number from the least significant
2543 * to the most significant digit, so we have to copy the
2544 * thousand separator backwards
2545 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002546 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002547 integerDigits += length;
2548 if (((int)(numberPointer - numberBuffer) - length) > 0)
2549 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002550 work = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002551 while (length-- > 0)
2552 *(--numberPointer) = *work--;
2553 }
2554
2555 /* Advance to next grouping number */
2556 if (charsPerThousand != NO_GROUPING)
2557 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002558 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002559 {
2560 case CHAR_MAX: /* Disable grouping */
2561 charsPerThousand = NO_GROUPING;
2562 break;
2563 case 0: /* Repeat last group */
2564 break;
2565 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002566 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002567 break;
2568 }
2569 }
2570 }
2571 }
2572
2573 /* Build the exponent */
2574 exponentDigits = 0;
2575 if (flags & FLAGS_FLOAT_E)
2576 {
2577 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2578 *exponentPointer-- = NIL;
2579 do {
2580 *exponentPointer-- = digits[uExponent % base];
2581 uExponent /= base;
2582 exponentDigits++;
2583 } while (uExponent);
2584 }
2585
Bjorn Reese70a9da52001-04-21 16:57:29 +00002586 /*
2587 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002588 * sign + integer part + thousands separators + decimal point
2589 * + fraction + exponent
2590 */
2591 expectedWidth = StrLength(numberPointer);
2592 if (isNegative || (flags & FLAGS_SHOWSIGN))
2593 expectedWidth += sizeof("-") - 1;
2594 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002595 expectedWidth += exponentDigits +
2596 ((exponentDigits > 1) ? sizeof("E+") : sizeof("E+0")) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002597 if (isHex)
2598 expectedWidth += sizeof("0X") - 1;
2599
2600 /* Output prefixing */
2601 if (flags & FLAGS_NILPADDING)
2602 {
2603 /* Leading zeros must be after sign */
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 if (!(flags & FLAGS_LEFTADJUST))
2614 {
2615 for (i = expectedWidth; i < width; i++)
2616 {
2617 self->OutStream(self, '0');
2618 }
2619 }
2620 }
2621 else
2622 {
2623 /* Leading spaces must be before sign */
2624 if (!(flags & FLAGS_LEFTADJUST))
2625 {
2626 for (i = expectedWidth; i < width; i++)
2627 {
2628 self->OutStream(self, CHAR_ADJUST);
2629 }
2630 }
2631 if (isNegative)
2632 self->OutStream(self, '-');
2633 else if (flags & FLAGS_SHOWSIGN)
2634 self->OutStream(self, '+');
2635 if (isHex)
2636 {
2637 self->OutStream(self, '0');
2638 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2639 }
2640 }
2641 /* Output number */
2642 for (i = 0; numberPointer[i]; i++)
2643 {
2644 self->OutStream(self, numberPointer[i]);
2645 }
2646 /* Output exponent */
2647 if (exponentDigits > 0)
2648 {
2649 self->OutStream(self,
2650 isHex
2651 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2652 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2653 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002654
2655 /* The exponent must contain at least two digits */
2656 if (exponentDigits == 1)
2657 self->OutStream(self, '0');
2658
Daniel Veillard92ad2102001-03-27 12:47:33 +00002659 for (i = 0; i < exponentDigits; i++)
2660 {
2661 self->OutStream(self, exponentPointer[i + 1]);
2662 }
2663 }
2664 /* Output trailing spaces */
2665 if (flags & FLAGS_LEFTADJUST)
2666 {
2667 for (i = expectedWidth; i < width; i++)
2668 {
2669 self->OutStream(self, CHAR_ADJUST);
2670 }
2671 }
2672}
2673
2674/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002675 * TrioFormatProcess [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +00002676 */
2677static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002678TrioFormatProcess(trio_T *data,
2679 const char *format,
2680 parameter_T *parameters)
2681
Daniel Veillard92ad2102001-03-27 12:47:33 +00002682{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002683#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002684 int charlen;
2685#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00002686 int i;
2687 const char *string;
2688 void *pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002689 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002690 int width;
2691 int precision;
2692 int base;
2693 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002694
Daniel Veillard92ad2102001-03-27 12:47:33 +00002695 index = 0;
2696 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002697#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002698 mblen(NULL, 0);
2699#endif
2700
2701 while (format[index])
2702 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002703#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002704 if (! isascii(format[index]))
2705 {
2706 charlen = mblen(&format[index], MB_LEN_MAX);
2707 while (charlen-- > 0)
2708 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002709 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002710 }
2711 continue; /* while */
2712 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002713#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002714 if (CHAR_IDENTIFIER == format[index])
2715 {
2716 if (CHAR_IDENTIFIER == format[index + 1])
2717 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002718 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002719 index += 2;
2720 }
2721 else
2722 {
2723 /* Skip the parameter entries */
2724 while (parameters[i].type == FORMAT_PARAMETER)
2725 i++;
2726
2727 flags = parameters[i].flags;
2728
2729 /* Find width */
2730 width = parameters[i].width;
2731 if (flags & FLAGS_WIDTH_PARAMETER)
2732 {
2733 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002734 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002735 }
2736
2737 /* Find precision */
2738 if (flags & FLAGS_PRECISION)
2739 {
2740 precision = parameters[i].precision;
2741 if (flags & FLAGS_PRECISION_PARAMETER)
2742 {
2743 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002744 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002745 }
2746 }
2747 else
2748 {
2749 precision = NO_PRECISION;
2750 }
2751
2752 /* Find base */
2753 base = parameters[i].base;
2754 if (flags & FLAGS_BASE_PARAMETER)
2755 {
2756 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002757 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002758 }
2759
2760 switch (parameters[i].type)
2761 {
2762 case FORMAT_CHAR:
2763 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002764 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002765 if (! (flags & FLAGS_LEFTADJUST))
2766 {
2767 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002768 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002769 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002770#if TRIO_WIDECHAR
2771 if (flags & FLAGS_WIDECHAR)
2772 {
2773 TrioWriteWideStringCharacter(data,
2774 (wchar_t)parameters[i].data.number.as_signed,
2775 flags,
2776 NO_WIDTH);
2777 }
2778 else
2779#endif
2780 TrioWriteStringCharacter(data,
2781 (int)parameters[i].data.number.as_signed,
2782 flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002783
2784 if (flags & FLAGS_LEFTADJUST)
2785 {
2786 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002787 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002788 }
2789 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002790 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002791
2792 break; /* FORMAT_CHAR */
2793
2794 case FORMAT_INT:
2795 if (base == NO_BASE)
2796 base = BASE_DECIMAL;
2797
2798 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002799 parameters[i].data.number.as_signed,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002800 flags,
2801 width,
2802 precision,
2803 base);
2804
2805 break; /* FORMAT_INT */
2806
2807 case FORMAT_DOUBLE:
2808 TrioWriteDouble(data,
2809 parameters[i].data.longdoubleNumber,
2810 flags,
2811 width,
2812 precision,
2813 base);
2814 break; /* FORMAT_DOUBLE */
2815
2816 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002817#if TRIO_WIDECHAR
2818 if (flags & FLAGS_WIDECHAR)
2819 {
2820 TrioWriteWideString(data,
2821 parameters[i].data.wstring,
2822 flags,
2823 width,
2824 precision);
2825 }
2826 else
2827#endif
2828 {
2829 TrioWriteString(data,
2830 parameters[i].data.string,
2831 flags,
2832 width,
2833 precision);
2834 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002835 break; /* FORMAT_STRING */
2836
2837 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002838 {
2839 reference_T reference;
2840
2841 reference.data = data;
2842 reference.parameter = &parameters[i];
2843 trio_print_pointer(&reference, parameters[i].data.pointer);
2844 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002845 break; /* FORMAT_POINTER */
2846
2847 case FORMAT_COUNT:
2848 pointer = parameters[i].data.pointer;
2849 if (NULL != pointer)
2850 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002851 /*
2852 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00002853 * characters written to the output stream so far by
2854 * this call", which is data->committed
2855 */
2856#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2857 if (flags & FLAGS_SIZE_T)
2858 *(size_t *)pointer = (size_t)data->committed;
2859 else
2860#endif
2861#if defined(QUALIFIER_PTRDIFF_T)
2862 if (flags & FLAGS_PTRDIFF_T)
2863 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2864 else
2865#endif
2866#if defined(QUALIFIER_INTMAX_T)
2867 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002868 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002869 else
2870#endif
2871 if (flags & FLAGS_QUAD)
2872 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002873 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 }
2875 else if (flags & FLAGS_LONG)
2876 {
2877 *(long int *)pointer = (long int)data->committed;
2878 }
2879 else if (flags & FLAGS_SHORT)
2880 {
2881 *(short int *)pointer = (short int)data->committed;
2882 }
2883 else
2884 {
2885 *(int *)pointer = (int)data->committed;
2886 }
2887 }
2888 break; /* FORMAT_COUNT */
2889
2890 case FORMAT_PARAMETER:
2891 break; /* FORMAT_PARAMETER */
2892
2893#if defined(FORMAT_ERRNO)
2894 case FORMAT_ERRNO:
2895 string = StrError(parameters[i].data.errorNumber);
2896 if (string)
2897 {
2898 TrioWriteString(data,
2899 string,
2900 flags,
2901 width,
2902 precision);
2903 }
2904 else
2905 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002906 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002907 TrioWriteNumber(data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002908 (trio_intmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002909 flags,
2910 width,
2911 precision,
2912 BASE_DECIMAL);
2913 }
2914 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002915#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002916
Bjorn Reese70a9da52001-04-21 16:57:29 +00002917#if defined(FORMAT_USER_DEFINED)
2918 case FORMAT_USER_DEFINED:
2919 {
2920 reference_T reference;
2921 userdef_T *def = NULL;
2922
2923 if (parameters[i].user_name[0] == NIL)
2924 {
2925 /* Use handle */
2926 if ((i > 0) ||
2927 (parameters[i - 1].type == FORMAT_PARAMETER))
2928 def = (userdef_T *)parameters[i - 1].data.pointer;
2929 }
2930 else
2931 {
2932 /* Look up namespace */
2933 def = TrioFindNamespace(parameters[i].user_name, NULL);
2934 }
2935 if (def) {
2936 reference.data = data;
2937 reference.parameter = &parameters[i];
2938 def->callback(&reference);
2939 }
2940 }
2941 break;
2942#endif /* defined(FORMAT_USER_DEFINED) */
2943
Daniel Veillard92ad2102001-03-27 12:47:33 +00002944 default:
2945 break;
2946 } /* switch parameter type */
2947
2948 /* Prepare for next */
2949 index = parameters[i].indexAfterSpecifier;
2950 i++;
2951 }
2952 }
2953 else /* not identifier */
2954 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002955 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002956 }
2957 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002958 return data->processed;
2959}
2960
2961/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002962 * TrioFormatRef [private]
2963 */
2964static int
2965TrioFormatRef(reference_T *reference,
2966 const char *format,
2967 va_list arglist,
2968 void **argarray)
2969{
2970 int status;
2971 parameter_T parameters[MAX_PARAMETERS];
2972
2973 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2974 if (status < 0)
2975 return status;
2976
2977 return TrioFormatProcess(reference->data, format, parameters);
2978}
2979
2980/*************************************************************************
2981 * TrioFormat [private]
2982 *
2983 * Description:
2984 * This is the main engine for formatting output
2985 */
2986static int
2987TrioFormat(void *destination,
2988 size_t destinationSize,
2989 void (*OutStream)(trio_T *, int),
2990 const char *format,
2991 va_list arglist,
2992 void **argarray)
2993{
2994 int status;
2995 trio_T data;
2996 parameter_T parameters[MAX_PARAMETERS];
2997
2998 assert(VALID(OutStream));
2999 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003000
3001 memset(&data, 0, sizeof(data));
3002 data.OutStream = OutStream;
3003 data.location = destination;
3004 data.max = destinationSize;
3005
3006#if defined(USE_LOCALE)
3007 if (NULL == internalLocaleValues)
3008 {
3009 TrioSetLocale();
3010 }
3011#endif
3012
3013 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
3014 if (status < 0)
3015 return status;
3016
3017 return TrioFormatProcess(&data, format, parameters);
3018}
3019
3020/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00003021 * TrioOutStreamFile [private]
3022 */
3023static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003024TrioOutStreamFile(trio_T *self,
3025 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003026{
3027 FILE *file = (FILE *)self->location;
3028
3029 assert(VALID(self));
3030 assert(VALID(file));
3031
3032 self->processed++;
3033 self->committed++;
3034 (void)fputc(output, file);
3035}
3036
3037/*************************************************************************
3038 * TrioOutStreamFileDescriptor [private]
3039 */
3040static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003041TrioOutStreamFileDescriptor(trio_T *self,
3042 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003043{
3044 int fd = *((int *)self->location);
3045 char ch;
3046
3047 assert(VALID(self));
3048
3049 ch = (char)output;
3050 (void)write(fd, &ch, sizeof(char));
3051 self->processed++;
3052 self->committed++;
3053}
3054
3055/*************************************************************************
3056 * TrioOutStreamString [private]
3057 */
3058static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003059TrioOutStreamString(trio_T *self,
3060 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003061{
3062 char **buffer = (char **)self->location;
3063
3064 assert(VALID(self));
3065 assert(VALID(buffer));
3066
3067 **buffer = (char)output;
3068 (*buffer)++;
3069 self->processed++;
3070 self->committed++;
3071}
3072
3073/*************************************************************************
3074 * TrioOutStreamStringMax [private]
3075 */
3076static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003077TrioOutStreamStringMax(trio_T *self,
3078 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003079{
3080 char **buffer;
3081
3082 assert(VALID(self));
3083 buffer = (char **)self->location;
3084 assert(VALID(buffer));
3085
3086 if (self->processed < self->max)
3087 {
3088 **buffer = (char)output;
3089 (*buffer)++;
3090 self->committed++;
3091 }
3092 self->processed++;
3093}
3094
3095/*************************************************************************
3096 * TrioOutStreamStringDynamic [private]
3097 */
3098#define DYNAMIC_START_SIZE 32
3099struct dynamicBuffer {
3100 char *buffer;
3101 size_t length;
3102 size_t allocated;
3103};
3104
3105static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003106TrioOutStreamStringDynamic(trio_T *self,
3107 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003108{
3109 struct dynamicBuffer *infop;
3110
3111 assert(VALID(self));
3112 assert(VALID(self->location));
3113
3114 infop = (struct dynamicBuffer *)self->location;
3115
3116 if (infop->buffer == NULL)
3117 {
3118 /* Start with a reasonable size */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003119 infop->buffer = (char *)TRIO_MALLOC(DYNAMIC_START_SIZE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003120 if (infop->buffer == NULL)
3121 return; /* fail */
3122
3123 infop->allocated = DYNAMIC_START_SIZE;
3124 self->processed = 0;
3125 self->committed = 0;
3126 }
3127 else if (self->committed + sizeof(NIL) >= infop->allocated)
3128 {
3129 char *newptr;
3130
3131 /* Allocate increasing chunks */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003132 newptr = (char *)TRIO_REALLOC(infop->buffer, infop->allocated * 2);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003133
3134 if (newptr == NULL)
3135 return;
3136
3137 infop->buffer = newptr;
3138 infop->allocated *= 2;
3139 }
3140
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003141 infop->buffer[self->committed] = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003142 self->committed++;
3143 self->processed++;
3144
3145 infop->length = self->committed;
3146}
3147
Daniel Veillard92ad2102001-03-27 12:47:33 +00003148/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003149 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003150 */
3151int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003152trio_printf(const char *format,
3153 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003154{
3155 int status;
3156 va_list args;
3157
3158 assert(VALID(format));
3159
3160 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003161 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003162 va_end(args);
3163 return status;
3164}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003165
Bjorn Reese70a9da52001-04-21 16:57:29 +00003166int
3167trio_vprintf(const char *format,
3168 va_list args)
3169{
3170 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003171
3172 return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
3173}
3174
3175int
3176trio_printfv(const char *format,
3177 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 */
3189int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003190trio_fprintf(FILE *file,
3191 const char *format,
3192 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003193{
3194 int status;
3195 va_list args;
3196
3197 assert(VALID(file));
3198 assert(VALID(format));
3199
3200 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003201 status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003202 va_end(args);
3203 return status;
3204}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003205
Daniel Veillard92ad2102001-03-27 12:47:33 +00003206int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003207trio_vfprintf(FILE *file,
3208 const char *format,
3209 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003210{
3211 assert(VALID(file));
3212 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003213
Bjorn Reese70a9da52001-04-21 16:57:29 +00003214 return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003215}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003216
Bjorn Reese70a9da52001-04-21 16:57:29 +00003217int
3218trio_fprintfv(FILE *file,
3219 const char *format,
3220 void ** args)
3221{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003222 va_list dummy;
3223
Bjorn Reese70a9da52001-04-21 16:57:29 +00003224 assert(VALID(file));
3225 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003226
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003227 return TrioFormat(file, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003228}
3229
Daniel Veillard92ad2102001-03-27 12:47:33 +00003230/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003231 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003232 */
3233int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003234trio_dprintf(int fd,
3235 const char *format,
3236 ...)
3237{
3238 int status;
3239 va_list args;
3240
3241 assert(VALID(format));
3242
3243 va_start(args, format);
3244 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3245 va_end(args);
3246 return status;
3247}
3248
3249int
3250trio_vdprintf(int fd,
3251 const char *format,
3252 va_list args)
3253{
3254 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003255
3256 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3257}
3258
3259int
3260trio_dprintfv(int fd,
3261 const char *format,
3262 void **args)
3263{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003264 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003265
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003266 assert(VALID(format));
3267
3268 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003269}
3270
3271/*************************************************************************
3272 * sprintf
3273 */
3274int
3275trio_sprintf(char *buffer,
3276 const char *format,
3277 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003278{
3279 int status;
3280 va_list args;
3281
3282 assert(VALID(buffer));
3283 assert(VALID(format));
3284
3285 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003286 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003287 *buffer = NIL; /* Terminate with NIL character */
3288 va_end(args);
3289 return status;
3290}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003291
Daniel Veillard92ad2102001-03-27 12:47:33 +00003292int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003293trio_vsprintf(char *buffer,
3294 const char *format,
3295 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003296{
3297 int status;
3298
3299 assert(VALID(buffer));
3300 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003301
Bjorn Reese70a9da52001-04-21 16:57:29 +00003302 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003303 *buffer = NIL;
3304 return status;
3305}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003306
Bjorn Reese70a9da52001-04-21 16:57:29 +00003307int
3308trio_sprintfv(char *buffer,
3309 const char *format,
3310 void **args)
3311{
3312 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003313 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003314
3315 assert(VALID(buffer));
3316 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003317
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003318 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003319 *buffer = NIL;
3320 return status;
3321}
3322
Daniel Veillard92ad2102001-03-27 12:47:33 +00003323/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003324 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003325 */
3326int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003327trio_snprintf(char *buffer,
3328 size_t bufferSize,
3329 const char *format,
3330 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003331{
3332 int status;
3333 va_list args;
3334
3335 assert(VALID(buffer));
3336 assert(VALID(format));
3337
3338 va_start(args, format);
3339 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003340 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003341 if (bufferSize > 0)
3342 *buffer = NIL;
3343 va_end(args);
3344 return status;
3345}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003346
Daniel Veillard92ad2102001-03-27 12:47:33 +00003347int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003348trio_vsnprintf(char *buffer,
3349 size_t bufferSize,
3350 const char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003351 va_list args)
3352{
3353 int status;
3354
3355 assert(VALID(buffer));
3356 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003357
3358 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003359 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003360 if (bufferSize > 0)
3361 *buffer = NIL;
3362 return status;
3363}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003364
3365int
3366trio_snprintfv(char *buffer,
3367 size_t bufferSize,
3368 const char *format,
3369 void **args)
3370{
3371 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003372 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003373
3374 assert(VALID(buffer));
3375 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003376
3377 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003378 TrioOutStreamStringMax, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003379 if (bufferSize > 0)
3380 *buffer = NIL;
3381 return status;
3382}
3383
3384/*************************************************************************
3385 * snprintfcat
3386 * Appends the new string to the buffer string overwriting the '\0'
3387 * character at the end of buffer.
3388 */
3389int
3390trio_snprintfcat(char *buffer,
3391 size_t bufferSize,
3392 const char *format,
3393 ...)
3394{
3395 int status;
3396 va_list args;
3397 size_t buf_len;
3398
3399 va_start(args, format);
3400
3401 assert(VALID(buffer));
3402 assert(VALID(format));
3403
3404 buf_len = strlen(buffer);
3405 buffer = &buffer[buf_len];
3406
3407 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3408 TrioOutStreamStringMax, format, args, NULL);
3409 va_end(args);
3410 *buffer = NIL;
3411 return status;
3412}
3413
3414int
3415trio_vsnprintfcat(char *buffer,
3416 size_t bufferSize,
3417 const char *format,
3418 va_list args)
3419{
3420 int status;
3421 size_t buf_len;
3422 assert(VALID(buffer));
3423 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003424
3425 buf_len = strlen(buffer);
3426 buffer = &buffer[buf_len];
3427 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3428 TrioOutStreamStringMax, format, args, NULL);
3429 *buffer = NIL;
3430 return status;
3431}
3432
3433/*************************************************************************
3434 * trio_aprintf
3435 */
3436
3437/* Deprecated */
3438char *
3439trio_aprintf(const char *format,
3440 ...)
3441{
3442 va_list args;
3443 struct dynamicBuffer info;
3444
3445 assert(VALID(format));
3446
3447 info.buffer = NULL;
3448 info.length = 0;
3449 info.allocated = 0;
3450
3451 va_start(args, format);
3452 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3453 va_end(args);
3454 if (info.length) {
3455 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3456 return info.buffer;
3457 }
3458 else
3459 return NULL;
3460}
3461
3462/* Deprecated */
3463char *
3464trio_vaprintf(const char *format,
3465 va_list args)
3466{
3467 struct dynamicBuffer info;
3468
3469 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003470
3471 info.buffer = NULL;
3472 info.length = 0;
3473 info.allocated = 0;
3474
3475 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3476 if (info.length) {
3477 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3478 return info.buffer;
3479 }
3480 else
3481 return NULL;
3482}
3483
3484int
3485trio_asprintf(char **result,
3486 const char *format,
3487 ...)
3488{
3489 va_list args;
3490 int status;
3491 struct dynamicBuffer info;
3492
3493 assert(VALID(format));
3494
3495 info.buffer = NULL;
3496 info.length = 0;
3497 info.allocated = 0;
3498
3499 va_start(args, format);
3500 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3501 va_end(args);
3502 if (status < 0) {
3503 *result = NULL;
3504 return status;
3505 }
3506 if (info.length == 0) {
3507 /*
3508 * If the length is zero, no characters have been written and therefore
3509 * no memory has been allocated, but we must to allocate and return an
3510 * empty string.
3511 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003512 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003513 if (info.buffer == NULL) {
3514 *result = NULL;
3515 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3516 }
3517 }
3518 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3519 *result = info.buffer;
3520
3521 return status;
3522}
3523
3524int
3525trio_vasprintf(char **result,
3526 const char *format,
3527 va_list args)
3528{
3529 int status;
3530 struct dynamicBuffer info;
3531
3532 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003533
3534 info.buffer = NULL;
3535 info.length = 0;
3536 info.allocated = 0;
3537
3538 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3539 if (status < 0) {
3540 *result = NULL;
3541 return status;
3542 }
3543 if (info.length == 0) {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003544 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003545 if (info.buffer == NULL) {
3546 *result = NULL;
3547 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3548 }
3549 }
3550 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3551 *result = info.buffer;
3552
3553 return status;
3554}
3555
Daniel Veillard92ad2102001-03-27 12:47:33 +00003556
3557/*************************************************************************
3558 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003559 * @CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00003560 *
3561 ************************************************************************/
3562
Bjorn Reese70a9da52001-04-21 16:57:29 +00003563
3564/*************************************************************************
3565 * trio_register [public]
3566 */
3567void *
3568trio_register(trio_callback_t callback,
3569 const char *name)
3570{
3571 userdef_T *def;
3572 userdef_T *prev = NULL;
3573
3574 if (callback == NULL)
3575 return NULL;
3576
3577 if (name)
3578 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003579 /* Handle built-in namespaces */
3580 if (name[0] == ':')
3581 {
3582 if (StrEqual(name, ":enter"))
3583 {
3584 internalEnterCriticalRegion = callback;
3585 }
3586 else if (StrEqual(name, ":leave"))
3587 {
3588 internalLeaveCriticalRegion = callback;
3589 }
3590 return NULL;
3591 }
3592
Bjorn Reese70a9da52001-04-21 16:57:29 +00003593 /* Bail out if namespace is too long */
3594 if (StrLength(name) >= MAX_USER_NAME)
3595 return NULL;
3596
3597 /* Bail out if namespace already is registered */
3598 def = TrioFindNamespace(name, &prev);
3599 if (def)
3600 return NULL;
3601 }
3602
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003603 def = (userdef_T *)TRIO_MALLOC(sizeof(userdef_T));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003604 if (def)
3605 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003606 if (internalEnterCriticalRegion)
3607 (void)internalEnterCriticalRegion(NULL);
3608
Bjorn Reese70a9da52001-04-21 16:57:29 +00003609 if (name)
3610 {
3611 /* Link into internal list */
3612 if (prev == NULL)
3613 internalUserDef = def;
3614 else
3615 prev->next = def;
3616 }
3617 /* Initialize */
3618 def->callback = callback;
3619 def->name = (name == NULL)
3620 ? NULL
3621 : StrDuplicate(name);
3622 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003623
3624 if (internalLeaveCriticalRegion)
3625 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003626 }
3627 return def;
3628}
3629
3630/*************************************************************************
3631 * trio_unregister [public]
3632 */
3633void
3634trio_unregister(void *handle)
3635{
3636 userdef_T *self = (userdef_T *)handle;
3637 userdef_T *def;
3638 userdef_T *prev = NULL;
3639
3640 assert(VALID(self));
3641
3642 if (self->name)
3643 {
3644 def = TrioFindNamespace(self->name, &prev);
3645 if (def)
3646 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003647 if (internalEnterCriticalRegion)
3648 (void)internalEnterCriticalRegion(NULL);
3649
Bjorn Reese70a9da52001-04-21 16:57:29 +00003650 if (prev == NULL)
3651 internalUserDef = NULL;
3652 else
3653 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003654
3655 if (internalLeaveCriticalRegion)
3656 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003657 }
3658 StrFree(self->name);
3659 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003660 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003661}
3662
3663/*************************************************************************
3664 * trio_get_format [public]
3665 */
3666const char *
3667trio_get_format(void *ref)
3668{
3669 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3670
3671 return (((reference_T *)ref)->parameter->user_data);
3672}
3673
3674/*************************************************************************
3675 * trio_get_argument [public]
3676 */
3677void *
3678trio_get_argument(void *ref)
3679{
3680 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3681
3682 return ((reference_T *)ref)->parameter->data.pointer;
3683}
3684
3685/*************************************************************************
3686 * trio_get_width / trio_set_width [public]
3687 */
3688int
3689trio_get_width(void *ref)
3690{
3691 return ((reference_T *)ref)->parameter->width;
3692}
3693
3694void
3695trio_set_width(void *ref,
3696 int width)
3697{
3698 ((reference_T *)ref)->parameter->width = width;
3699}
3700
3701/*************************************************************************
3702 * trio_get_precision / trio_set_precision [public]
3703 */
3704int
3705trio_get_precision(void *ref)
3706{
3707 return (((reference_T *)ref)->parameter->precision);
3708}
3709
3710void
3711trio_set_precision(void *ref,
3712 int precision)
3713{
3714 ((reference_T *)ref)->parameter->precision = precision;
3715}
3716
3717/*************************************************************************
3718 * trio_get_base / trio_set_base [public]
3719 */
3720int
3721trio_get_base(void *ref)
3722{
3723 return (((reference_T *)ref)->parameter->base);
3724}
3725
3726void
3727trio_set_base(void *ref,
3728 int base)
3729{
3730 ((reference_T *)ref)->parameter->base = base;
3731}
3732
3733/*************************************************************************
3734 * trio_get_long / trio_set_long [public]
3735 */
3736int
3737trio_get_long(void *ref)
3738{
3739 return (((reference_T *)ref)->parameter->flags & FLAGS_LONG);
3740}
3741
3742void
3743trio_set_long(void *ref,
3744 int is_long)
3745{
3746 if (is_long)
3747 ((reference_T *)ref)->parameter->flags |= FLAGS_LONG;
3748 else
3749 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONG;
3750}
3751
3752/*************************************************************************
3753 * trio_get_longlong / trio_set_longlong [public]
3754 */
3755int
3756trio_get_longlong(void *ref)
3757{
3758 return (((reference_T *)ref)->parameter->flags & FLAGS_QUAD);
3759}
3760
3761void
3762trio_set_longlong(void *ref,
3763 int is_longlong)
3764{
3765 if (is_longlong)
3766 ((reference_T *)ref)->parameter->flags |= FLAGS_QUAD;
3767 else
3768 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUAD;
3769}
3770
3771/*************************************************************************
3772 * trio_get_longdouble / trio_set_longdouble [public]
3773 */
3774int
3775trio_get_longdouble(void *ref)
3776{
3777 return (((reference_T *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
3778}
3779
3780void
3781trio_set_longdouble(void *ref,
3782 int is_longdouble)
3783{
3784 if (is_longdouble)
3785 ((reference_T *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
3786 else
3787 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
3788}
3789
3790/*************************************************************************
3791 * trio_get_short / trio_set_short [public]
3792 */
3793int
3794trio_get_short(void *ref)
3795{
3796 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORT);
3797}
3798
3799void
3800trio_set_short(void *ref,
3801 int is_short)
3802{
3803 if (is_short)
3804 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORT;
3805 else
3806 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORT;
3807}
3808
3809/*************************************************************************
3810 * trio_get_shortshort / trio_set_shortshort [public]
3811 */
3812int
3813trio_get_shortshort(void *ref)
3814{
3815 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORTSHORT);
3816}
3817
3818void
3819trio_set_shortshort(void *ref,
3820 int is_shortshort)
3821{
3822 if (is_shortshort)
3823 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
3824 else
3825 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
3826}
3827
3828/*************************************************************************
3829 * trio_get_alternative / trio_set_alternative [public]
3830 */
3831int
3832trio_get_alternative(void *ref)
3833{
3834 return (((reference_T *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
3835}
3836
3837void
3838trio_set_alternative(void *ref,
3839 int is_alternative)
3840{
3841 if (is_alternative)
3842 ((reference_T *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
3843 else
3844 ((reference_T *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
3845}
3846
3847/*************************************************************************
3848 * trio_get_alignment / trio_set_alignment [public]
3849 */
3850int
3851trio_get_alignment(void *ref)
3852{
3853 return (((reference_T *)ref)->parameter->flags & FLAGS_LEFTADJUST);
3854}
3855
3856void
3857trio_set_alignment(void *ref,
3858 int is_leftaligned)
3859{
3860 if (is_leftaligned)
3861 ((reference_T *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
3862 else
3863 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
3864}
3865
3866/*************************************************************************
3867 * trio_get_spacing /trio_set_spacing [public]
3868 */
3869int
3870trio_get_spacing(void *ref)
3871{
3872 return (((reference_T *)ref)->parameter->flags & FLAGS_SPACE);
3873}
3874
3875void
3876trio_set_spacing(void *ref,
3877 int is_space)
3878{
3879 if (is_space)
3880 ((reference_T *)ref)->parameter->flags |= FLAGS_SPACE;
3881 else
3882 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SPACE;
3883}
3884
3885/*************************************************************************
3886 * trio_get_sign / trio_set_sign [public]
3887 */
3888int
3889trio_get_sign(void *ref)
3890{
3891 return (((reference_T *)ref)->parameter->flags & FLAGS_SHOWSIGN);
3892}
3893
3894void
3895trio_set_sign(void *ref,
3896 int is_sign)
3897{
3898 if (is_sign)
3899 ((reference_T *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
3900 else
3901 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
3902}
3903
3904/*************************************************************************
3905 * trio_get_padding / trio_set_padding [public]
3906 */
3907int
3908trio_get_padding(void *ref)
3909{
3910 return (((reference_T *)ref)->parameter->flags & FLAGS_NILPADDING);
3911}
3912
3913void
3914trio_set_padding(void *ref,
3915 int is_padding)
3916{
3917 if (is_padding)
3918 ((reference_T *)ref)->parameter->flags |= FLAGS_NILPADDING;
3919 else
3920 ((reference_T *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
3921}
3922
3923/*************************************************************************
3924 * trio_get_quote / trio_set_quote [public]
3925 */
3926int
3927trio_get_quote(void *ref)
3928{
3929 return (((reference_T *)ref)->parameter->flags & FLAGS_QUOTE);
3930}
3931
3932void
3933trio_set_quote(void *ref,
3934 int is_quote)
3935{
3936 if (is_quote)
3937 ((reference_T *)ref)->parameter->flags |= FLAGS_QUOTE;
3938 else
3939 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUOTE;
3940}
3941
3942/*************************************************************************
3943 * trio_get_upper / trio_set_upper [public]
3944 */
3945int
3946trio_get_upper(void *ref)
3947{
3948 return (((reference_T *)ref)->parameter->flags & FLAGS_UPPER);
3949}
3950
3951void
3952trio_set_upper(void *ref,
3953 int is_upper)
3954{
3955 if (is_upper)
3956 ((reference_T *)ref)->parameter->flags |= FLAGS_UPPER;
3957 else
3958 ((reference_T *)ref)->parameter->flags &= ~FLAGS_UPPER;
3959}
3960
3961/*************************************************************************
3962 * trio_get_largest / trio_set_largest [public]
3963 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003964#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00003965int
3966trio_get_largest(void *ref)
3967{
3968 return (((reference_T *)ref)->parameter->flags & FLAGS_INTMAX_T);
3969}
3970
3971void
3972trio_set_largest(void *ref,
3973 int is_largest)
3974{
3975 if (is_largest)
3976 ((reference_T *)ref)->parameter->flags |= FLAGS_INTMAX_T;
3977 else
3978 ((reference_T *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
3979}
3980#endif
3981
3982/*************************************************************************
3983 * trio_get_ptrdiff / trio_set_ptrdiff [public]
3984 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003985int
3986trio_get_ptrdiff(void *ref)
3987{
3988 return (((reference_T *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
3989}
3990
3991void
3992trio_set_ptrdiff(void *ref,
3993 int is_ptrdiff)
3994{
3995 if (is_ptrdiff)
3996 ((reference_T *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
3997 else
3998 ((reference_T *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
3999}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004000
4001/*************************************************************************
4002 * trio_get_size / trio_set_size [public]
4003 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004004#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004005int
4006trio_get_size(void *ref)
4007{
4008 return (((reference_T *)ref)->parameter->flags & FLAGS_SIZE_T);
4009}
4010
4011void
4012trio_set_size(void *ref,
4013 int is_size)
4014{
4015 if (is_size)
4016 ((reference_T *)ref)->parameter->flags |= FLAGS_SIZE_T;
4017 else
4018 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4019}
4020#endif
4021
4022/*************************************************************************
4023 * trio_print_int [public]
4024 */
4025void
4026trio_print_int(void *ref,
4027 int number)
4028{
4029 reference_T *self = (reference_T *)ref;
4030
4031 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004032 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004033 self->parameter->flags,
4034 self->parameter->width,
4035 self->parameter->precision,
4036 self->parameter->base);
4037}
4038
4039/*************************************************************************
4040 * trio_print_uint [public]
4041 */
4042void
4043trio_print_uint(void *ref,
4044 unsigned int number)
4045{
4046 reference_T *self = (reference_T *)ref;
4047
4048 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004049 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004050 self->parameter->flags | FLAGS_UNSIGNED,
4051 self->parameter->width,
4052 self->parameter->precision,
4053 self->parameter->base);
4054}
4055
4056/*************************************************************************
4057 * trio_print_double [public]
4058 */
4059void
4060trio_print_double(void *ref,
4061 double number)
4062{
4063 reference_T *self = (reference_T *)ref;
4064
4065 TrioWriteDouble(self->data,
4066 number,
4067 self->parameter->flags,
4068 self->parameter->width,
4069 self->parameter->precision,
4070 self->parameter->base);
4071}
4072
4073/*************************************************************************
4074 * trio_print_string [public]
4075 */
4076void
4077trio_print_string(void *ref,
4078 char *string)
4079{
4080 reference_T *self = (reference_T *)ref;
4081
4082 TrioWriteString(self->data,
4083 string,
4084 self->parameter->flags,
4085 self->parameter->width,
4086 self->parameter->precision);
4087}
4088
4089/*************************************************************************
4090 * trio_print_pointer [public]
4091 */
4092void
4093trio_print_pointer(void *ref,
4094 void *pointer)
4095{
4096 reference_T *self = (reference_T *)ref;
4097 unsigned long flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004098 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004099
4100 if (NULL == pointer)
4101 {
4102 const char *string = null;
4103 while (*string)
4104 self->data->OutStream(self->data, *string++);
4105 }
4106 else
4107 {
4108 /*
4109 * The subtraction of the null pointer is a workaround
4110 * to avoid a compiler warning. The performance overhead
4111 * is negligible (and likely to be removed by an
4112 * optimising compiler). The (char *) casting is done
4113 * to please ANSI C++.
4114 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004115 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004116 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004117 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004118 flags = self->parameter->flags;
4119 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4120 FLAGS_NILPADDING);
4121 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004122 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004123 flags,
4124 POINTER_WIDTH,
4125 NO_PRECISION,
4126 BASE_HEX);
4127 }
4128}
4129
4130/*************************************************************************
4131 * trio_print_ref [public]
4132 */
4133int
4134trio_print_ref(void *ref,
4135 const char *format,
4136 ...)
4137{
4138 int status;
4139 va_list arglist;
4140
4141 assert(VALID(format));
4142
4143 va_start(arglist, format);
4144 status = TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4145 va_end(arglist);
4146 return status;
4147}
4148
4149/*************************************************************************
4150 * trio_vprint_ref [public]
4151 */
4152int
4153trio_vprint_ref(void *ref,
4154 const char *format,
4155 va_list arglist)
4156{
4157 assert(VALID(format));
4158
4159 return TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4160}
4161
4162/*************************************************************************
4163 * trio_printv_ref [public]
4164 */
4165int
4166trio_printv_ref(void *ref,
4167 const char *format,
4168 void **argarray)
4169{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004170 va_list dummy;
4171
Bjorn Reese70a9da52001-04-21 16:57:29 +00004172 assert(VALID(format));
4173
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004174 return TrioFormatRef((reference_T *)ref, format, dummy, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004175}
4176
4177
4178/*************************************************************************
4179 *
4180 * @SCANNING
4181 *
4182 ************************************************************************/
4183
Daniel Veillard92ad2102001-03-27 12:47:33 +00004184
4185/*************************************************************************
4186 * TrioSkipWhitespaces [private]
4187 */
4188static int
4189TrioSkipWhitespaces(trio_T *self)
4190{
4191 int ch;
4192
4193 ch = self->current;
4194 while (isspace(ch))
4195 {
4196 self->InStream(self, &ch);
4197 }
4198 return ch;
4199}
4200
4201/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004202 * TrioGetCollation [private]
4203 */
4204#if TRIO_EXTENSION
4205static void
4206TrioGetCollation()
4207{
4208 int i;
4209 int j;
4210 int k;
4211 char first[2];
4212 char second[2];
4213
4214 /* This is computational expensive */
4215 first[1] = NIL;
4216 second[1] = NIL;
4217 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4218 {
4219 k = 0;
4220 first[0] = (char)i;
4221 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
4222 {
4223 second[0] = (char)j;
4224 if (StrEqualLocale(first, second))
4225 internalCollationArray[i][k++] = (char)j;
4226 }
4227 internalCollationArray[i][k] = NIL;
4228 }
4229}
4230#endif
4231
4232/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004233 * TrioGetCharacterClass [private]
4234 *
4235 * FIXME:
4236 * multibyte
4237 */
4238static int
4239TrioGetCharacterClass(const char *format,
4240 int *indexPointer,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004241 unsigned long *flagsPointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004242 int *characterclass)
4243{
4244 int index = *indexPointer;
4245 int i;
4246 char ch;
4247 char range_begin;
4248 char range_end;
4249
4250 *flagsPointer &= ~FLAGS_EXCLUDE;
4251
4252 if (format[index] == QUALIFIER_CIRCUMFLEX)
4253 {
4254 *flagsPointer |= FLAGS_EXCLUDE;
4255 index++;
4256 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004257 /*
4258 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004259 * it will be part of the class, and a second ungroup character
4260 * must follow to end the group.
4261 */
4262 if (format[index] == SPECIFIER_UNGROUP)
4263 {
4264 characterclass[(int)SPECIFIER_UNGROUP]++;
4265 index++;
4266 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004267 /*
4268 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004269 * it must be at the beginning of the list
4270 */
4271 if (format[index] == QUALIFIER_MINUS)
4272 {
4273 characterclass[(int)QUALIFIER_MINUS]++;
4274 index++;
4275 }
4276 /* Collect characters */
4277 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004278 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004279 ch = format[++index])
4280 {
4281 switch (ch)
4282 {
4283 case QUALIFIER_MINUS: /* Scanlist ranges */
4284
Bjorn Reese70a9da52001-04-21 16:57:29 +00004285 /*
4286 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00004287 * defined.
4288 *
4289 * We support the following behaviour (although this may
4290 * change as we become wiser)
4291 * - only increasing ranges, ie. [a-b] but not [b-a]
4292 * - transitive ranges, ie. [a-b-c] == [a-c]
4293 * - trailing minus, ie. [a-] is interpreted as an 'a'
4294 * and a '-'
4295 * - duplicates (although we can easily convert these
4296 * into errors)
4297 */
4298 range_begin = format[index - 1];
4299 range_end = format[++index];
4300 if (range_end == SPECIFIER_UNGROUP)
4301 {
4302 /* Trailing minus is included */
4303 characterclass[(int)ch]++;
4304 ch = range_end;
4305 break; /* for */
4306 }
4307 if (range_end == NIL)
4308 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4309 if (range_begin > range_end)
4310 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
4311
4312 for (i = (int)range_begin; i <= (int)range_end; i++)
4313 characterclass[i]++;
4314
4315 ch = range_end;
4316 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004317
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004318#if TRIO_EXTENSION
4319
4320 case SPECIFIER_GROUP:
4321
4322 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004323 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004324 case QUALIFIER_DOT: /* Collating symbol */
4325 /*
4326 * FIXME: This will be easier to implement when multibyte
4327 * characters have been implemented. Until now, we ignore
4328 * this feature.
4329 */
4330 for (i = index + 2; ; i++)
4331 {
4332 if (format[i] == NIL)
4333 /* Error in syntax */
4334 return -1;
4335 else if (format[i] == QUALIFIER_DOT)
4336 break; /* for */
4337 }
4338 if (format[++i] != SPECIFIER_UNGROUP)
4339 return -1;
4340
4341 index = i;
4342 break;
4343
4344 case QUALIFIER_EQUAL: /* Equivalence class expressions */
4345 {
4346 unsigned int j;
4347 unsigned int k;
4348
4349 if (internalCollationUnconverted)
4350 {
4351 /* Lazy evalutation of collation array */
4352 TrioGetCollation();
4353 internalCollationUnconverted = FALSE;
4354 }
4355 for (i = index + 2; ; i++)
4356 {
4357 if (format[i] == NIL)
4358 /* Error in syntax */
4359 return -1;
4360 else if (format[i] == QUALIFIER_EQUAL)
4361 break; /* for */
4362 else
4363 {
4364 /* Mark any equivalent character */
4365 k = (unsigned int)format[i];
4366 for (j = 0; internalCollationArray[k][j] != NIL; j++)
4367 characterclass[(int)internalCollationArray[k][j]]++;
4368 }
4369 }
4370 if (format[++i] != SPECIFIER_UNGROUP)
4371 return -1;
4372
4373 index = i;
4374 }
4375 break;
4376
4377 case QUALIFIER_COLON: /* Character class expressions */
4378
4379 if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
4380 &format[index]))
4381 {
4382 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4383 if (isalnum(i))
4384 characterclass[i]++;
4385 index += sizeof(CLASS_ALNUM) - 1;
4386 }
4387 else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
4388 &format[index]))
4389 {
4390 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4391 if (isalpha(i))
4392 characterclass[i]++;
4393 index += sizeof(CLASS_ALPHA) - 1;
4394 }
4395 else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
4396 &format[index]))
4397 {
4398 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4399 if (iscntrl(i))
4400 characterclass[i]++;
4401 index += sizeof(CLASS_CNTRL) - 1;
4402 }
4403 else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
4404 &format[index]))
4405 {
4406 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4407 if (isdigit(i))
4408 characterclass[i]++;
4409 index += sizeof(CLASS_DIGIT) - 1;
4410 }
4411 else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
4412 &format[index]))
4413 {
4414 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4415 if (isgraph(i))
4416 characterclass[i]++;
4417 index += sizeof(CLASS_GRAPH) - 1;
4418 }
4419 else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
4420 &format[index]))
4421 {
4422 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4423 if (islower(i))
4424 characterclass[i]++;
4425 index += sizeof(CLASS_LOWER) - 1;
4426 }
4427 else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
4428 &format[index]))
4429 {
4430 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4431 if (isprint(i))
4432 characterclass[i]++;
4433 index += sizeof(CLASS_PRINT) - 1;
4434 }
4435 else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
4436 &format[index]))
4437 {
4438 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4439 if (ispunct(i))
4440 characterclass[i]++;
4441 index += sizeof(CLASS_PUNCT) - 1;
4442 }
4443 else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
4444 &format[index]))
4445 {
4446 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4447 if (isspace(i))
4448 characterclass[i]++;
4449 index += sizeof(CLASS_SPACE) - 1;
4450 }
4451 else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
4452 &format[index]))
4453 {
4454 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4455 if (isupper(i))
4456 characterclass[i]++;
4457 index += sizeof(CLASS_UPPER) - 1;
4458 }
4459 else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
4460 &format[index]))
4461 {
4462 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4463 if (isxdigit(i))
4464 characterclass[i]++;
4465 index += sizeof(CLASS_XDIGIT) - 1;
4466 }
4467 else
4468 {
4469 characterclass[(int)ch]++;
4470 }
4471 break;
4472
4473 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004474 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004475 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004476 }
4477 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004478
4479#endif /* TRIO_EXTENSION */
4480
Daniel Veillard92ad2102001-03-27 12:47:33 +00004481 default:
4482 characterclass[(int)ch]++;
4483 break;
4484 }
4485 }
4486 return 0;
4487}
4488
4489/*************************************************************************
4490 * TrioReadNumber [private]
4491 *
4492 * We implement our own number conversion in preference of strtol and
4493 * strtoul, because we must handle 'long long' and thousand separators.
4494 */
4495static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004496TrioReadNumber(trio_T *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004497 trio_uintmax_t *target,
4498 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004499 int width,
4500 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004501{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004502 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004503 int digit;
4504 int count;
4505 BOOLEAN_T isNegative = FALSE;
4506 int j;
4507
4508 assert(VALID(self));
4509 assert(VALID(self->InStream));
4510 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
4511
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004512 if (internalDigitsUnconverted)
4513 {
4514 /* Lazy evaluation of digits array */
4515 memset(internalDigitArray, -1, sizeof(internalDigitArray));
4516 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
4517 {
4518 internalDigitArray[(int)internalDigitsLower[j]] = j;
4519 internalDigitArray[(int)internalDigitsUpper[j]] = j;
4520 }
4521 internalDigitsUnconverted = FALSE;
4522 }
4523
Daniel Veillard92ad2102001-03-27 12:47:33 +00004524 TrioSkipWhitespaces(self);
4525
4526 if (!(flags & FLAGS_UNSIGNED))
4527 {
4528 /* Leading sign */
4529 if (self->current == '+')
4530 {
4531 self->InStream(self, NULL);
4532 }
4533 else if (self->current == '-')
4534 {
4535 self->InStream(self, NULL);
4536 isNegative = TRUE;
4537 }
4538 }
4539
4540 count = self->processed;
4541
4542 if (flags & FLAGS_ALTERNATIVE)
4543 {
4544 switch (base)
4545 {
4546 case NO_BASE:
4547 case BASE_OCTAL:
4548 case BASE_HEX:
4549 case BASE_BINARY:
4550 if (self->current == '0')
4551 {
4552 self->InStream(self, NULL);
4553 if (self->current)
4554 {
4555 if ((base == BASE_HEX) &&
4556 (toupper(self->current) == 'X'))
4557 {
4558 self->InStream(self, NULL);
4559 }
4560 else if ((base == BASE_BINARY) &&
4561 (toupper(self->current) == 'B'))
4562 {
4563 self->InStream(self, NULL);
4564 }
4565 }
4566 }
4567 else
4568 return FALSE;
4569 break;
4570 default:
4571 break;
4572 }
4573 }
4574
4575 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
4576 (! ((self->current == EOF) || isspace(self->current))))
4577 {
4578 if (isascii(self->current))
4579 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004580 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00004581 /* Abort if digit is not allowed in the specified base */
4582 if ((digit == -1) || (digit >= base))
4583 break;
4584 }
4585 else if (flags & FLAGS_QUOTE)
4586 {
4587 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004588 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004589 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004590 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004591 break;
4592
4593 self->InStream(self, NULL);
4594 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004595 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004596 break; /* Mismatch */
4597 else
4598 continue; /* Match */
4599 }
4600 else
4601 break;
4602
4603 number *= base;
4604 number += digit;
4605
4606 self->InStream(self, NULL);
4607 }
4608
4609 /* Was anything read at all? */
4610 if (self->processed == count)
4611 return FALSE;
4612
4613 if (target)
4614 *target = (isNegative) ? -number : number;
4615 return TRUE;
4616}
4617
4618/*************************************************************************
4619 * TrioReadChar [private]
4620 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004621static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004622TrioReadChar(trio_T *self,
4623 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004624 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004625 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004626{
4627 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004628 char ch;
4629 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004630
4631 assert(VALID(self));
4632 assert(VALID(self->InStream));
4633
4634 for (i = 0;
4635 (self->current != EOF) && (i < width);
4636 i++)
4637 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004638 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004639 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004640 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
4641 {
4642 switch (self->current)
4643 {
4644 case '\\': ch = '\\'; break;
4645 case 'a': ch = '\007'; break;
4646 case 'b': ch = '\b'; break;
4647 case 'f': ch = '\f'; break;
4648 case 'n': ch = '\n'; break;
4649 case 'r': ch = '\r'; break;
4650 case 't': ch = '\t'; break;
4651 case 'v': ch = '\v'; break;
4652 default:
4653 if (isdigit(self->current))
4654 {
4655 /* Read octal number */
4656 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
4657 return 0;
4658 ch = (char)number;
4659 }
4660 else if (toupper(self->current) == 'X')
4661 {
4662 /* Read hexadecimal number */
4663 self->InStream(self, NULL);
4664 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
4665 return 0;
4666 ch = (char)number;
4667 }
4668 else
4669 {
4670 ch = (char)self->current;
4671 }
4672 break;
4673 }
4674 }
4675
4676 if (target)
4677 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004678 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004679 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004680}
4681
4682/*************************************************************************
4683 * TrioReadString [private]
4684 */
4685static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004686TrioReadString(trio_T *self,
4687 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004688 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004689 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004690{
4691 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004692
4693 assert(VALID(self));
4694 assert(VALID(self->InStream));
4695
4696 TrioSkipWhitespaces(self);
4697
Bjorn Reese70a9da52001-04-21 16:57:29 +00004698 /*
4699 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004700 * or width is exceeded
4701 */
4702 for (i = 0;
4703 ((width == NO_WIDTH) || (i < width)) &&
4704 (! ((self->current == EOF) || isspace(self->current)));
4705 i++)
4706 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004707 if (TrioReadChar(self, &target[i], flags, 1) == 0)
4708 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004709 }
4710 if (target)
4711 target[i] = NIL;
4712 return TRUE;
4713}
4714
4715/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004716 * TrioReadWideChar [private]
4717 */
4718#if TRIO_WIDECHAR
4719static int
4720TrioReadWideChar(trio_T *self,
4721 wchar_t *target,
4722 unsigned long flags,
4723 int width)
4724{
4725 int i;
4726 int j;
4727 int size;
4728 int amount = 0;
4729 wchar_t wch;
4730 char buffer[MB_LEN_MAX + 1];
4731
4732 assert(VALID(self));
4733 assert(VALID(self->InStream));
4734
4735 for (i = 0;
4736 (self->current != EOF) && (i < width);
4737 i++)
4738 {
4739 if (isascii(self->current))
4740 {
4741 if (TrioReadChar(self, buffer, flags, 1) == 0)
4742 return 0;
4743 buffer[1] = NIL;
4744 }
4745 else
4746 {
4747 /*
4748 * Collect a multibyte character, by enlarging buffer until
4749 * it contains a fully legal multibyte character, or the
4750 * buffer is full.
4751 */
4752 j = 0;
4753 do
4754 {
4755 buffer[j++] = (char)self->current;
4756 buffer[j] = NIL;
4757 self->InStream(self, NULL);
4758 }
4759 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
4760 }
4761 if (target)
4762 {
4763 size = mbtowc(&wch, buffer, sizeof(buffer));
4764 if (size > 0)
4765 target[i] = wch;
4766 }
4767 amount += size;
4768 self->InStream(self, NULL);
4769 }
4770 return amount;
4771}
4772#endif /* TRIO_WIDECHAR */
4773
4774/*************************************************************************
4775 * TrioReadWideString [private]
4776 */
4777#if TRIO_WIDECHAR
4778static BOOLEAN_T
4779TrioReadWideString(trio_T *self,
4780 wchar_t *target,
4781 unsigned long flags,
4782 int width)
4783{
4784 int i;
4785 int size;
4786
4787 assert(VALID(self));
4788 assert(VALID(self->InStream));
4789
4790 TrioSkipWhitespaces(self);
4791
4792#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
4793 mblen(NULL, 0);
4794#endif
4795
4796 /*
4797 * Continue until end of string is reached, a whitespace is encountered,
4798 * or width is exceeded
4799 */
4800 for (i = 0;
4801 ((width == NO_WIDTH) || (i < width)) &&
4802 (! ((self->current == EOF) || isspace(self->current)));
4803 )
4804 {
4805 size = TrioReadWideChar(self, &target[i], flags, 1);
4806 if (size == 0)
4807 break; /* for */
4808
4809 i += size;
4810 }
4811 if (target)
4812 target[i] = L'\0';
4813 return TRUE;
4814}
4815#endif /* TRIO_WIDECHAR */
4816
4817/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004818 * TrioReadGroup [private]
4819 *
4820 * FIXME: characterclass does not work with multibyte characters
4821 */
4822static BOOLEAN_T
4823TrioReadGroup(trio_T *self,
4824 char *target,
4825 int *characterclass,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004826 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004827 int width)
4828{
Bjorn Reese70a9da52001-04-21 16:57:29 +00004829 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004830 int i;
4831
4832 assert(VALID(self));
4833 assert(VALID(self->InStream));
4834
4835 ch = self->current;
4836 for (i = 0;
4837 ((width == NO_WIDTH) || (i < width)) &&
4838 (! ((ch == EOF) ||
4839 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
4840 i++)
4841 {
4842 if (target)
4843 target[i] = (char)ch;
4844 self->InStream(self, &ch);
4845 }
4846
4847 if (target)
4848 target[i] = NIL;
4849 return TRUE;
4850}
4851
4852/*************************************************************************
4853 * TrioReadDouble [private]
4854 *
4855 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004856 * add long double
4857 */
4858static BOOLEAN_T
4859TrioReadDouble(trio_T *self,
4860 double *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004861 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004862 int width)
4863{
4864 int ch;
4865 char doubleString[512] = "";
4866 int index = 0;
4867 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004868 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004869 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004870
Bjorn Reese70a9da52001-04-21 16:57:29 +00004871 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004872 width = sizeof(doubleString) - 1;
4873
4874 TrioSkipWhitespaces(self);
4875
Bjorn Reese70a9da52001-04-21 16:57:29 +00004876 /*
4877 * Read entire double number from stream. StrToDouble requires a
Daniel Veillard92ad2102001-03-27 12:47:33 +00004878 * string as input, but InStream can be anything, so we have to
4879 * collect all characters.
4880 */
4881 ch = self->current;
4882 if ((ch == '+') || (ch == '-'))
4883 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004884 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004885 self->InStream(self, &ch);
4886 width--;
4887 }
4888
4889 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004890 switch (ch)
4891 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00004892 case 'n':
4893 case 'N':
4894 /* Not-a-number */
4895 if (index != 0)
4896 break;
4897 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004898 case 'i':
4899 case 'I':
4900 /* Infinity */
4901 while (isalpha(ch) && (index - start < width))
4902 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004903 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004904 self->InStream(self, &ch);
4905 }
4906 doubleString[index] = NIL;
4907
Daniel Veillard92ad2102001-03-27 12:47:33 +00004908 /* Case insensitive string comparison */
4909 if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
4910 StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
4911 {
4912 *target = ((start == 1 && doubleString[0] == '-'))
4913 ? -HUGE_VAL
4914 : HUGE_VAL;
4915 return TRUE;
4916 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004917 if (StrEqual(doubleString, NAN_LOWER))
4918 {
4919 /* NaN must not have a preceeding + nor - */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004920 *target = TrioGenerateNaN();
Daniel Veillard92ad2102001-03-27 12:47:33 +00004921 return TRUE;
4922 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004923 return FALSE;
4924
4925 default:
4926 break;
4927 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004928
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004929 if (ch == '0')
4930 {
4931 doubleString[index++] = (char)ch;
4932 self->InStream(self, &ch);
4933 if (toupper(ch) == 'X')
4934 {
4935 isHex = TRUE;
4936 doubleString[index++] = (char)ch;
4937 self->InStream(self, &ch);
4938 }
4939 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004940 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004941 {
4942 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004943 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00004944 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004945 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004946 self->InStream(self, &ch);
4947 }
4948 else if (flags & FLAGS_QUOTE)
4949 {
4950 /* Compare with thousands separator */
4951 for (j = 0; internalThousandSeparator[j] && self->current; j++)
4952 {
4953 if (internalThousandSeparator[j] != self->current)
4954 break;
4955
4956 self->InStream(self, &ch);
4957 }
4958 if (internalThousandSeparator[j])
4959 break; /* Mismatch */
4960 else
4961 continue; /* Match */
4962 }
4963 else
4964 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004965 }
4966 if (ch == '.')
4967 {
4968 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004969 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004970 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004971 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4972 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004973 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004974 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004975 self->InStream(self, &ch);
4976 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004977 if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004978 {
4979 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004980 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004981 self->InStream(self, &ch);
4982 if ((ch == '+') || (ch == '-'))
4983 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004984 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004985 self->InStream(self, &ch);
4986 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004987 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4988 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004989 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004990 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004991 self->InStream(self, &ch);
4992 }
4993 }
4994 }
4995
4996 if ((index == start) || (*doubleString == NIL))
4997 return FALSE;
4998
4999 if (flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005000/* *longdoublePointer = StrToLongDouble()*/
5001 return FALSE; /* FIXME: Remove when long double is implemented */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005002 else
5003 {
5004 *target = StrToDouble(doubleString, NULL);
5005 }
5006 return TRUE;
5007}
5008
5009/*************************************************************************
5010 * TrioReadPointer [private]
5011 */
5012static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00005013TrioReadPointer(trio_T *self,
5014 void **target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005015 unsigned long flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005016{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005017 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005018 char buffer[sizeof(null)];
5019
5020 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5021
5022 if (TrioReadNumber(self,
5023 &number,
5024 flags,
5025 POINTER_WIDTH,
5026 BASE_HEX))
5027 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005028 /*
5029 * The strange assignment of number is a workaround for a compiler
5030 * warning
5031 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005032 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005033 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005034 return TRUE;
5035 }
5036 else if (TrioReadString(self,
5037 (flags & FLAGS_IGNORE)
5038 ? NULL
5039 : buffer,
5040 0,
5041 sizeof(null) - 1))
5042 {
5043 if (StrEqualCase(buffer, null))
5044 {
5045 if (target)
5046 *target = NULL;
5047 return TRUE;
5048 }
5049 }
5050 return FALSE;
5051}
5052
5053/*************************************************************************
5054 * TrioScan [private]
5055 */
5056static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005057TrioScan(const void *source,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005058 size_t sourceSize,
5059 void (*InStream)(trio_T *, int *),
5060 const char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005061 va_list arglist,
5062 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005063{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005064#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005065 int charlen;
5066#endif
5067 int status;
5068 int assignment;
5069 parameter_T parameters[MAX_PARAMETERS];
5070 trio_T internalData;
5071 trio_T *data;
5072 int ch;
5073 int cnt;
5074 int index; /* Index of format string */
5075 int i; /* Index of current parameter */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005076 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005077 int width;
5078 int base;
5079 void *pointer;
5080
5081 assert(VALID(InStream));
5082 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00005083
5084 memset(&internalData, 0, sizeof(internalData));
5085 data = &internalData;
5086 data->InStream = InStream;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005087 data->location = (void *)source;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005088 data->max = sourceSize;
5089
5090#if defined(USE_LOCALE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005091 if (NULL == internalLocaleValues)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005092 {
5093 TrioSetLocale();
5094 }
5095#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00005096
Bjorn Reese70a9da52001-04-21 16:57:29 +00005097 status = TrioPreprocess(TYPE_SCAN, format, parameters, arglist, argarray);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005098 if (status < 0)
5099 return status;
5100
5101 assignment = 0;
5102 i = 0;
5103 index = 0;
5104 data->InStream(data, &ch);
5105
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005106#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005107 mblen(NULL, 0);
5108#endif
5109
5110 while (format[index])
5111 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005112#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005113 if (! isascii(format[index]))
5114 {
5115 charlen = mblen(&format[index], MB_LEN_MAX);
5116 /* Compare multibyte characters in format string */
5117 for (cnt = 0; cnt < charlen - 1; cnt++)
5118 {
5119 if (ch != format[index + cnt])
5120 {
5121 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5122 }
5123 data->InStream(data, &ch);
5124 }
5125 continue; /* while */
5126 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005127#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005128 if (EOF == ch)
5129 return EOF;
5130
5131 if (CHAR_IDENTIFIER == format[index])
5132 {
5133 if (CHAR_IDENTIFIER == format[index + 1])
5134 {
5135 /* Two % in format matches one % in input stream */
5136 if (CHAR_IDENTIFIER == ch)
5137 {
5138 data->InStream(data, &ch);
5139 index += 2;
5140 continue; /* while format chars left */
5141 }
5142 else
5143 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5144 }
5145
5146 /* Skip the parameter entries */
5147 while (parameters[i].type == FORMAT_PARAMETER)
5148 i++;
5149
5150 flags = parameters[i].flags;
5151 /* Find width */
5152 width = parameters[i].width;
5153 if (flags & FLAGS_WIDTH_PARAMETER)
5154 {
5155 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005156 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005157 }
5158 /* Find base */
5159 base = parameters[i].base;
5160 if (flags & FLAGS_BASE_PARAMETER)
5161 {
5162 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005163 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005164 }
5165
5166 switch (parameters[i].type)
5167 {
5168 case FORMAT_INT:
5169 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005170 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005171
5172 if (0 == base)
5173 base = BASE_DECIMAL;
5174
5175 if (!TrioReadNumber(data,
5176 &number,
5177 flags,
5178 width,
5179 base))
5180 return assignment;
5181 assignment++;
5182
5183 if (!(flags & FLAGS_IGNORE))
5184 {
5185 pointer = parameters[i].data.pointer;
5186#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5187 if (flags & FLAGS_SIZE_T)
5188 *(size_t *)pointer = (size_t)number;
5189 else
5190#endif
5191#if defined(QUALIFIER_PTRDIFF_T)
5192 if (flags & FLAGS_PTRDIFF_T)
5193 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
5194 else
5195#endif
5196#if defined(QUALIFIER_INTMAX_T)
5197 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005198 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005199 else
5200#endif
5201 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005202 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005203 else if (flags & FLAGS_LONG)
5204 *(long int *)pointer = (long int)number;
5205 else if (flags & FLAGS_SHORT)
5206 *(short int *)pointer = (short int)number;
5207 else
5208 *(int *)pointer = (int)number;
5209 }
5210 }
5211 break; /* FORMAT_INT */
5212
5213 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005214#if TRIO_WIDECHAR
5215 if (flags & FLAGS_WIDECHAR)
5216 {
5217 if (!TrioReadWideString(data,
5218 (flags & FLAGS_IGNORE)
5219 ? NULL
5220 : parameters[i].data.wstring,
5221 flags,
5222 width))
5223 return assignment;
5224 }
5225 else
5226#endif
5227 {
5228 if (!TrioReadString(data,
5229 (flags & FLAGS_IGNORE)
5230 ? NULL
5231 : parameters[i].data.string,
5232 flags,
5233 width))
5234 return assignment;
5235 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005236 assignment++;
5237 break; /* FORMAT_STRING */
5238
5239 case FORMAT_DOUBLE:
5240 if (!TrioReadDouble(data,
5241 (flags & FLAGS_IGNORE)
5242 ? NULL
5243 : parameters[i].data.doublePointer,
5244 flags,
5245 width))
5246 return assignment;
5247 assignment++;
5248 break; /* FORMAT_DOUBLE */
5249
5250 case FORMAT_GROUP:
5251 {
5252 int characterclass[MAX_CHARACTER_CLASS + 1];
5253 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005254
5255 /* Skip over modifiers */
5256 while (format[index] != SPECIFIER_GROUP)
5257 {
5258 index++;
5259 }
5260 /* Skip over group specifier */
5261 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005262
Daniel Veillard92ad2102001-03-27 12:47:33 +00005263 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005264 rc = TrioGetCharacterClass(format,
5265 &index,
5266 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005267 characterclass);
5268 if (rc < 0)
5269 return rc;
5270
5271 if (!TrioReadGroup(data,
5272 (flags & FLAGS_IGNORE)
5273 ? NULL
5274 : parameters[i].data.string,
5275 characterclass,
5276 flags,
5277 parameters[i].width))
5278 return assignment;
5279 assignment++;
5280 }
5281 break; /* FORMAT_GROUP */
5282
5283 case FORMAT_COUNT:
5284 pointer = parameters[i].data.pointer;
5285 if (NULL != pointer)
5286 {
5287#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5288 if (flags & FLAGS_SIZE_T)
5289 *(size_t *)pointer = (size_t)data->committed;
5290 else
5291#endif
5292#if defined(QUALIFIER_PTRDIFF_T)
5293 if (flags & FLAGS_PTRDIFF_T)
5294 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
5295 else
5296#endif
5297#if defined(QUALIFIER_INTMAX_T)
5298 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005299 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005300 else
5301#endif
5302 if (flags & FLAGS_QUAD)
5303 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005304 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005305 }
5306 else if (flags & FLAGS_LONG)
5307 {
5308 *(long int *)pointer = (long int)data->committed;
5309 }
5310 else if (flags & FLAGS_SHORT)
5311 {
5312 *(short int *)pointer = (short int)data->committed;
5313 }
5314 else
5315 {
5316 *(int *)pointer = (int)data->committed;
5317 }
5318 }
5319 break; /* FORMAT_COUNT */
5320
5321 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005322#if TRIO_WIDECHAR
5323 if (flags & FLAGS_WIDECHAR)
5324 {
5325 if (TrioReadWideChar(data,
5326 (flags & FLAGS_IGNORE)
5327 ? NULL
5328 : parameters[i].data.wstring,
5329 flags,
5330 (width == NO_WIDTH) ? 1 : width) > 0)
5331 return assignment;
5332 }
5333 else
5334#endif
5335 {
5336 if (TrioReadChar(data,
5337 (flags & FLAGS_IGNORE)
5338 ? NULL
5339 : parameters[i].data.string,
5340 flags,
5341 (width == NO_WIDTH) ? 1 : width) > 0)
5342 return assignment;
5343 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005344 assignment++;
5345 break; /* FORMAT_CHAR */
5346
5347 case FORMAT_POINTER:
5348 if (!TrioReadPointer(data,
5349 (flags & FLAGS_IGNORE)
5350 ? NULL
Bjorn Reese70a9da52001-04-21 16:57:29 +00005351 : (void **)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005352 flags))
5353 return assignment;
5354 assignment++;
5355 break; /* FORMAT_POINTER */
5356
5357 case FORMAT_PARAMETER:
5358 break; /* FORMAT_PARAMETER */
5359
5360 default:
5361 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5362 }
5363 ch = data->current;
5364 index = parameters[i].indexAfterSpecifier;
5365 i++;
5366 }
5367 else /* Not an % identifier */
5368 {
5369 if (isspace((int)format[index]))
5370 {
5371 /* Whitespaces may match any amount of whitespaces */
5372 ch = TrioSkipWhitespaces(data);
5373 }
5374 else if (ch == format[index])
5375 {
5376 data->InStream(data, &ch);
5377 }
5378 else
5379 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5380
5381 index++;
5382 }
5383 }
5384 return assignment;
5385}
5386
5387/*************************************************************************
5388 * TrioInStreamFile [private]
5389 */
5390static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005391TrioInStreamFile(trio_T *self,
5392 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005393{
5394 FILE *file = (FILE *)self->location;
5395
5396 assert(VALID(self));
5397 assert(VALID(file));
5398
5399 self->current = fgetc(file);
5400 self->processed++;
5401 self->committed++;
5402
5403 if (VALID(intPointer))
5404 {
5405 *intPointer = self->current;
5406 }
5407}
5408
5409/*************************************************************************
5410 * TrioInStreamFileDescriptor [private]
5411 */
5412static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005413TrioInStreamFileDescriptor(trio_T *self,
5414 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005415{
5416 int fd = *((int *)self->location);
5417 int size;
5418 unsigned char input;
5419
5420 assert(VALID(self));
5421
5422 size = read(fd, &input, sizeof(char));
5423 self->current = (size == 0) ? EOF : input;
5424 self->processed++;
5425 self->committed++;
5426
5427 if (VALID(intPointer))
5428 {
5429 *intPointer = self->current;
5430 }
5431}
5432
5433/*************************************************************************
5434 * TrioInStreamString [private]
5435 */
5436static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005437TrioInStreamString(trio_T *self,
5438 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005439{
5440 unsigned char **buffer;
5441
5442 assert(VALID(self));
5443 assert(VALID(self->InStream));
5444 assert(VALID(self->location));
5445
5446 buffer = (unsigned char **)self->location;
5447 self->current = (*buffer)[0];
5448 if (self->current == NIL)
5449 self->current = EOF;
5450 (*buffer)++;
5451 self->processed++;
5452 self->committed++;
5453
5454 if (VALID(intPointer))
5455 {
5456 *intPointer = self->current;
5457 }
5458}
5459
5460/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00005461 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00005462 */
5463int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005464trio_scanf(const char *format,
5465 ...)
5466{
5467 int status;
5468 va_list args;
5469
5470 assert(VALID(format));
5471
5472 va_start(args, format);
5473 status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5474 va_end(args);
5475 return status;
5476}
5477
5478int
5479trio_vscanf(const char *format,
5480 va_list args)
5481{
5482 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005483
5484 return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5485}
5486
5487int
5488trio_scanfv(const char *format,
5489 void **args)
5490{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005491 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005492
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005493 assert(VALID(format));
5494
5495 return TrioScan(stdin, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005496}
5497
5498/*************************************************************************
5499 * fscanf
5500 */
5501int
5502trio_fscanf(FILE *file,
5503 const char *format,
5504 ...)
5505{
5506 int status;
5507 va_list args;
5508
5509 assert(VALID(file));
5510 assert(VALID(format));
5511
5512 va_start(args, format);
5513 status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5514 va_end(args);
5515 return status;
5516}
5517
5518int
5519trio_vfscanf(FILE *file,
5520 const char *format,
5521 va_list args)
5522{
5523 assert(VALID(file));
5524 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005525
5526 return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5527}
5528
5529int
5530trio_fscanfv(FILE *file,
5531 const char *format,
5532 void **args)
5533{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005534 va_list dummy;
5535
Bjorn Reese70a9da52001-04-21 16:57:29 +00005536 assert(VALID(file));
5537 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005538
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005539 return TrioScan(file, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005540}
5541
5542/*************************************************************************
5543 * dscanf
5544 */
5545int
5546trio_dscanf(int fd,
5547 const char *format,
5548 ...)
5549{
5550 int status;
5551 va_list args;
5552
5553 assert(VALID(format));
5554
5555 va_start(args, format);
5556 status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5557 va_end(args);
5558 return status;
5559}
5560
5561int
5562trio_vdscanf(int fd,
5563 const char *format,
5564 va_list args)
5565{
5566 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005567
5568 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5569}
5570
5571int
5572trio_dscanfv(int fd,
5573 const char *format,
5574 void **args)
5575{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005576 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005577
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005578 assert(VALID(format));
5579
5580 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005581}
5582
5583/*************************************************************************
5584 * sscanf
5585 */
5586int
5587trio_sscanf(const char *buffer,
5588 const char *format,
5589 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005590{
5591 int status;
5592 va_list args;
5593
5594 assert(VALID(buffer));
5595 assert(VALID(format));
5596
5597 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005598 status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005599 va_end(args);
5600 return status;
5601}
5602
Bjorn Reese70a9da52001-04-21 16:57:29 +00005603int
5604trio_vsscanf(const char *buffer,
5605 const char *format,
5606 va_list args)
5607{
5608 assert(VALID(buffer));
5609 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005610
5611 return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
5612}
5613
5614int
5615trio_sscanfv(const char *buffer,
5616 const char *format,
5617 void **args)
5618{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005619 va_list dummy;
5620
Bjorn Reese70a9da52001-04-21 16:57:29 +00005621 assert(VALID(buffer));
5622 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005623
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005624 return TrioScan(&buffer, 0, TrioInStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005625}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005626