blob: 380f54c5562f45620fca680ed8d4e02af31a143a [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
Bjorn Reese3157b342001-06-22 14:41:45 +0000792TrioDivide(double dividend, double divisor)
793{
794 return dividend / divisor;
795}
796
797static double
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000798TrioGenerateNaN(void)
799{
800#if defined(TRIO_COMPILER_SUPPORTS_C99)
801 return nan(NULL);
802#elif defined(DBL_QNAN)
803 return DBL_QNAN;
804#elif defined(PLATFORM_UNIX)
805 double value;
806 void (*signal_handler)(int);
807
808 signal_handler = signal(SIGFPE, SIG_IGN);
Bjorn Reese3157b342001-06-22 14:41:45 +0000809 value = TrioDivide(0.0, 0.0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000810 signal(SIGFPE, signal_handler);
811 return value;
812#else
Bjorn Reese3157b342001-06-22 14:41:45 +0000813 return TrioDivide(0.0, 0.0);
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000814#endif
815}
816
817/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000818 * TrioIsNan [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +0000819 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000820static int
821TrioIsNan(double number)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000822{
Bjorn Reese70a9da52001-04-21 16:57:29 +0000823#ifdef isnan
824 /* C99 defines isnan() as a macro */
825 return isnan(number);
826#else
827 double integral, fraction;
828
829 return (/* NaN is the only number which does not compare to itself */
830 (number != number) ||
831 /* Fallback solution if NaN compares to NaN */
832 ((number != 0.0) &&
833 (fraction = modf(number, &integral),
834 integral == fraction)));
Daniel Veillard92ad2102001-03-27 12:47:33 +0000835#endif
836}
837
838/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000839 * TrioIsInfinite [private]
840 */
841static int
842TrioIsInfinite(double number)
843{
844#ifdef isinf
845 /* C99 defines isinf() as a macro */
846 return isinf(number);
847#else
848 return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));
849#endif
850}
851
852/*************************************************************************
853 * TrioSetLocale [private]
854 */
855#if defined(USE_LOCALE)
856static void
857TrioSetLocale(void)
858{
859 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000860 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000861 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000862 if ((internalLocaleValues->decimal_point) &&
863 (internalLocaleValues->decimal_point[0] != NIL))
864 {
865 StrCopyMax(internalDecimalPoint,
866 sizeof(internalDecimalPoint),
867 internalLocaleValues->decimal_point);
868 }
869 if ((internalLocaleValues->thousands_sep) &&
870 (internalLocaleValues->thousands_sep[0] != NIL))
871 {
872 StrCopyMax(internalThousandSeparator,
873 sizeof(internalThousandSeparator),
874 internalLocaleValues->thousands_sep);
875 }
876 if ((internalLocaleValues->grouping) &&
877 (internalLocaleValues->grouping[0] != NIL))
878 {
879 StrCopyMax(internalGrouping,
880 sizeof(internalGrouping),
881 internalLocaleValues->grouping);
882 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000883 }
884}
885#endif /* defined(USE_LOCALE) */
886
887/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000888 * TrioGetPosition [private]
889 *
890 * Get the %n$ position.
891 */
892static int
Bjorn Reese70a9da52001-04-21 16:57:29 +0000893TrioGetPosition(const char *format,
894 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000895{
896 char *tmpformat;
897 int number = 0;
898 int index = *indexPointer;
899
900 number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
901 index = (int)(tmpformat - format);
902 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
903 {
904 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000905 /*
906 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000907 * the array it is indexing starts from 0.
908 */
909 return number - 1;
910 }
911 return NO_POSITION;
912}
913
914/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000915 * TrioFindNamespace [private]
916 *
917 * Find registered user-defined specifier.
918 * The prev argument is used for optimisation only.
919 */
920static userdef_T *
921TrioFindNamespace(const char *name, userdef_T **prev)
922{
923 userdef_T *def;
924
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000925 if (internalEnterCriticalRegion)
926 (void)internalEnterCriticalRegion(NULL);
927
Bjorn Reese70a9da52001-04-21 16:57:29 +0000928 for (def = internalUserDef; def; def = def->next)
929 {
930 /* Case-sensitive string comparison */
931 if (StrEqualCase(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000932 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000933
934 if (prev)
935 *prev = def;
936 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000937
938 if (internalLeaveCriticalRegion)
939 (void)internalLeaveCriticalRegion(NULL);
940
Bjorn Reese70a9da52001-04-21 16:57:29 +0000941 return def;
942}
943
944/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000945 * TrioPreprocess [private]
946 *
947 * Description:
948 * Parse the format string
949 */
950static int
951TrioPreprocess(int type,
952 const char *format,
953 parameter_T *parameters,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000954 va_list arglist,
955 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000956{
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000957#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +0000958 /* Count the number of times a parameter is referenced */
959 unsigned short usedEntries[MAX_PARAMETERS];
960#endif
961 /* Parameter counters */
962 int parameterPosition;
963 int currentParam;
964 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000965 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000966 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000967 int width;
968 int precision;
969 int varsize;
970 int base;
971 int index; /* Index into formatting string */
972 int dots; /* Count number of dots in modifier part */
973 BOOLEAN_T positional; /* Does the specifier have a positional? */
974 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000975 /*
976 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +0000977 * read from the va_args (this is necessary to handle positionals)
978 */
979 int indices[MAX_PARAMETERS];
980 int pos = 0;
981 /* Various variables */
982 char ch;
983 int charlen;
984 int i = -1;
985 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000986 char *tmpformat;
987
988
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000989#if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +0000990 /*
991 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +0000992 * know which entries we have used.
993 */
994 memset(usedEntries, 0, sizeof(usedEntries));
995#endif
996
997 index = 0;
998 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000999#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001000 mblen(NULL, 0);
1001#endif
1002
1003 while (format[index])
1004 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001005#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001006 if (! isascii(format[index]))
1007 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001008 /*
1009 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001010 * modifiers, so we skip over them.
1011 */
1012 charlen = mblen(&format[index], MB_LEN_MAX);
1013 index += (charlen > 0) ? charlen : 1;
1014 continue; /* while */
1015 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001016#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001017 if (CHAR_IDENTIFIER == format[index++])
1018 {
1019 if (CHAR_IDENTIFIER == format[index])
1020 {
1021 index++;
1022 continue; /* while */
1023 }
1024
1025 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001026 dots = 0;
1027 currentParam = TrioGetPosition(format, &index);
1028 positional = (NO_POSITION != currentParam);
1029 if (!positional)
1030 {
1031 /* We have no positional, get the next counter */
1032 currentParam = parameterPosition;
1033 }
1034 if(currentParam >= MAX_PARAMETERS)
1035 {
1036 /* Bail out completely to make the error more obvious */
1037 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1038 }
1039
1040 if (currentParam > maxParam)
1041 maxParam = currentParam;
1042
1043 /* Default values */
1044 width = NO_WIDTH;
1045 precision = NO_PRECISION;
1046 base = NO_BASE;
1047 varsize = NO_SIZE;
1048
Bjorn Reese70a9da52001-04-21 16:57:29 +00001049 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001050 {
1051 ch = format[index++];
1052
Daniel Veillard92ad2102001-03-27 12:47:33 +00001053 switch (ch)
1054 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00001055 case QUALIFIER_SPACE:
1056 flags |= FLAGS_SPACE;
1057 break;
1058
1059 case QUALIFIER_PLUS:
1060 flags |= FLAGS_SHOWSIGN;
1061 break;
1062
1063 case QUALIFIER_MINUS:
1064 flags |= FLAGS_LEFTADJUST;
1065 flags &= ~FLAGS_NILPADDING;
1066 break;
1067
1068 case QUALIFIER_ALTERNATIVE:
1069 flags |= FLAGS_ALTERNATIVE;
1070 break;
1071
1072 case QUALIFIER_DOT:
1073 if (dots == 0) /* Precision */
1074 {
1075 dots++;
1076
1077 /* Skip if no precision */
1078 if (QUALIFIER_DOT == format[index])
1079 break;
1080
1081 /* After the first dot we have the precision */
1082 flags |= FLAGS_PRECISION;
1083 if ((QUALIFIER_STAR == format[index]) ||
1084 (QUALIFIER_PARAM == format[index]))
1085 {
1086 index++;
1087 flags |= FLAGS_PRECISION_PARAMETER;
1088
1089 precision = TrioGetPosition(format, &index);
1090 if (precision == NO_POSITION)
1091 {
1092 parameterPosition++;
1093 if (positional)
1094 precision = parameterPosition;
1095 else
1096 {
1097 precision = currentParam;
1098 currentParam = precision + 1;
1099 }
1100 }
1101 else
1102 {
1103 if (! positional)
1104 currentParam = precision + 1;
1105 if (width > maxParam)
1106 maxParam = precision;
1107 }
1108 if (currentParam > maxParam)
1109 maxParam = currentParam;
1110 }
1111 else
1112 {
1113 precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1114 index = (int)(tmpformat - format);
1115 }
1116 }
1117 else if (dots == 1) /* Base */
1118 {
1119 dots++;
1120
1121 /* After the second dot we have the base */
1122 flags |= FLAGS_BASE;
1123 if ((QUALIFIER_STAR == format[index]) ||
1124 (QUALIFIER_PARAM == format[index]))
1125 {
1126 index++;
1127 flags |= FLAGS_BASE_PARAMETER;
1128 base = TrioGetPosition(format, &index);
1129 if (base == NO_POSITION)
1130 {
1131 parameterPosition++;
1132 if (positional)
1133 base = parameterPosition;
1134 else
1135 {
1136 base = currentParam;
1137 currentParam = base + 1;
1138 }
1139 }
1140 else
1141 {
1142 if (! positional)
1143 currentParam = base + 1;
1144 if (base > maxParam)
1145 maxParam = base;
1146 }
1147 if (currentParam > maxParam)
1148 maxParam = currentParam;
1149 }
1150 else
1151 {
1152 base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1153 if (base > MAX_BASE)
1154 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1155 index = (int)(tmpformat - format);
1156 }
1157 }
1158 else
1159 {
1160 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1161 }
1162 break; /* QUALIFIER_DOT */
1163
1164 case QUALIFIER_PARAM:
1165 type = TYPE_PRINT;
1166 /* FALLTHROUGH */
1167 case QUALIFIER_STAR:
1168 /* This has different meanings for print and scan */
1169 if (TYPE_PRINT == type)
1170 {
1171 /* Read with from parameter */
1172 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1173 width = TrioGetPosition(format, &index);
1174 if (width == NO_POSITION)
1175 {
1176 parameterPosition++;
1177 if (positional)
1178 width = parameterPosition;
1179 else
1180 {
1181 width = currentParam;
1182 currentParam = width + 1;
1183 }
1184 }
1185 else
1186 {
1187 if (! positional)
1188 currentParam = width + 1;
1189 if (width > maxParam)
1190 maxParam = width;
1191 }
1192 if (currentParam > maxParam)
1193 maxParam = currentParam;
1194 }
1195 else
1196 {
1197 /* Scan, but do not store result */
1198 flags |= FLAGS_IGNORE;
1199 }
1200
1201 break; /* QUALIFIER_STAR */
1202
1203 case '0':
1204 if (! (flags & FLAGS_LEFTADJUST))
1205 flags |= FLAGS_NILPADDING;
1206 /* FALLTHROUGH */
1207 case '1': case '2': case '3': case '4':
1208 case '5': case '6': case '7': case '8': case '9':
1209 flags |= FLAGS_WIDTH;
1210 /* &format[index - 1] is used to "rewind" the read
1211 * character from format
1212 */
1213 width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
1214 index = (int)(tmpformat - format);
1215 break;
1216
1217 case QUALIFIER_SHORT:
1218 if (flags & FLAGS_SHORTSHORT)
1219 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1220 else if (flags & FLAGS_SHORT)
1221 flags |= FLAGS_SHORTSHORT;
1222 else
1223 flags |= FLAGS_SHORT;
1224 break;
1225
1226 case QUALIFIER_LONG:
1227 if (flags & FLAGS_QUAD)
1228 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1229 else if (flags & FLAGS_LONG)
1230 flags |= FLAGS_QUAD;
1231 else
1232 flags |= FLAGS_LONG;
1233 break;
1234
1235 case QUALIFIER_LONG_UPPER:
1236 flags |= FLAGS_LONGDOUBLE;
1237 break;
1238
1239#if defined(QUALIFIER_SIZE_T)
1240 case QUALIFIER_SIZE_T:
1241 flags |= FLAGS_SIZE_T;
1242 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001243 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001244 flags |= FLAGS_QUAD;
1245 else if (sizeof(size_t) == sizeof(long))
1246 flags |= FLAGS_LONG;
1247 break;
1248#endif
1249
1250#if defined(QUALIFIER_PTRDIFF_T)
1251 case QUALIFIER_PTRDIFF_T:
1252 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001253 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001254 flags |= FLAGS_QUAD;
1255 else if (sizeof(ptrdiff_t) == sizeof(long))
1256 flags |= FLAGS_LONG;
1257 break;
1258#endif
1259
1260#if defined(QUALIFIER_INTMAX_T)
1261 case QUALIFIER_INTMAX_T:
1262 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001263 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001264 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001265 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001266 flags |= FLAGS_LONG;
1267 break;
1268#endif
1269
1270#if defined(QUALIFIER_QUAD)
1271 case QUALIFIER_QUAD:
1272 flags |= FLAGS_QUAD;
1273 break;
1274#endif
1275
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001276#if defined(QUALIFIER_FIXED_SIZE)
1277 case QUALIFIER_FIXED_SIZE:
1278 if (flags & FLAGS_FIXED_SIZE)
1279 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1280
1281 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1282 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1283 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1284
1285 if ((format[index] == '6') &&
1286 (format[index + 1] == '4'))
1287 {
1288 varsize = sizeof(trio_int64_t);
1289 index += 2;
1290 }
1291 else if ((format[index] == '3') &&
1292 (format[index + 1] == '2'))
1293 {
1294 varsize = sizeof(trio_int32_t);
1295 index += 2;
1296 }
1297 else if ((format[index] == '1') &&
1298 (format[index + 1] == '6'))
1299 {
1300 varsize = sizeof(trio_int16_t);
1301 index += 2;
1302 }
1303 else if (format[index] == '8')
1304 {
1305 varsize = sizeof(trio_int8_t);
1306 index++;
1307 }
1308 else
1309 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1310
1311 flags |= FLAGS_FIXED_SIZE;
1312 break;
1313#endif
1314
Daniel Veillard92ad2102001-03-27 12:47:33 +00001315#if defined(QUALIFIER_WIDECHAR)
1316 case QUALIFIER_WIDECHAR:
1317 flags |= FLAGS_WIDECHAR;
1318 break;
1319#endif
1320
1321#if defined(QUALIFIER_SIZE_T_UPPER)
1322 case QUALIFIER_SIZE_T_UPPER:
1323 break;
1324#endif
1325
1326#if defined(QUALIFIER_QUOTE)
1327 case QUALIFIER_QUOTE:
1328 flags |= FLAGS_QUOTE;
1329 break;
1330#endif
1331
1332#if defined(QUALIFIER_STICKY)
1333 case QUALIFIER_STICKY:
1334 flags |= FLAGS_STICKY;
1335 got_sticky = TRUE;
1336 break;
1337#endif
1338
1339#if defined(QUALIFIER_VARSIZE)
1340 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001341 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001342 parameterPosition++;
1343 if (positional)
1344 varsize = parameterPosition;
1345 else
1346 {
1347 varsize = currentParam;
1348 currentParam = varsize + 1;
1349 }
1350 if (currentParam > maxParam)
1351 maxParam = currentParam;
1352 break;
1353#endif
1354
1355 default:
1356 /* Bail out completely to make the error more obvious */
1357 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1358 }
1359 } /* while qualifier */
1360
Bjorn Reese70a9da52001-04-21 16:57:29 +00001361 /*
1362 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001363 * read later.
1364 */
1365 if (flags & FLAGS_WIDTH_PARAMETER)
1366 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001367#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001368 usedEntries[width] += 1;
1369#endif
1370 parameters[pos].type = FORMAT_PARAMETER;
1371 indices[width] = pos;
1372 width = pos++;
1373 }
1374 if (flags & FLAGS_PRECISION_PARAMETER)
1375 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001376#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001377 usedEntries[precision] += 1;
1378#endif
1379 parameters[pos].type = FORMAT_PARAMETER;
1380 indices[precision] = pos;
1381 precision = pos++;
1382 }
1383 if (flags & FLAGS_BASE_PARAMETER)
1384 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001385#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001386 usedEntries[base] += 1;
1387#endif
1388 parameters[pos].type = FORMAT_PARAMETER;
1389 indices[base] = pos;
1390 base = pos++;
1391 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001392 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001393 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001394#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001395 usedEntries[varsize] += 1;
1396#endif
1397 parameters[pos].type = FORMAT_PARAMETER;
1398 indices[varsize] = pos;
1399 varsize = pos++;
1400 }
1401
1402 indices[currentParam] = pos;
1403
1404 switch (format[index++])
1405 {
1406#if defined(SPECIFIER_CHAR_UPPER)
1407 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001408 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001409 /* FALLTHROUGH */
1410#endif
1411 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001412 if (flags & FLAGS_LONG)
1413 flags |= FLAGS_WIDECHAR;
1414 else if (flags & FLAGS_SHORT)
1415 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001416 parameters[pos].type = FORMAT_CHAR;
1417 break;
1418
1419#if defined(SPECIFIER_STRING_UPPER)
1420 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001421 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001422 /* FALLTHROUGH */
1423#endif
1424 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001425 if (flags & FLAGS_LONG)
1426 flags |= FLAGS_WIDECHAR;
1427 else if (flags & FLAGS_SHORT)
1428 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001429 parameters[pos].type = FORMAT_STRING;
1430 break;
1431
1432 case SPECIFIER_GROUP:
1433 if (TYPE_SCAN == type)
1434 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001435 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001436 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001437 if (format[index] == QUALIFIER_CIRCUMFLEX)
1438 index++;
1439 if (format[index] == SPECIFIER_UNGROUP)
1440 index++;
1441 if (format[index] == QUALIFIER_MINUS)
1442 index++;
1443 /* Skip nested brackets */
1444 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001445 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001446 if (format[index] == SPECIFIER_GROUP)
1447 {
1448 depth++;
1449 }
1450 else if (format[index] == SPECIFIER_UNGROUP)
1451 {
1452 if (--depth <= 0)
1453 {
1454 index++;
1455 break;
1456 }
1457 }
1458 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001459 }
1460 }
1461 break;
1462
1463 case SPECIFIER_INTEGER:
1464 parameters[pos].type = FORMAT_INT;
1465 break;
1466
1467 case SPECIFIER_UNSIGNED:
1468 flags |= FLAGS_UNSIGNED;
1469 parameters[pos].type = FORMAT_INT;
1470 break;
1471
1472 case SPECIFIER_DECIMAL:
1473 /* Disable base modifier */
1474 flags &= ~FLAGS_BASE_PARAMETER;
1475 base = BASE_DECIMAL;
1476 parameters[pos].type = FORMAT_INT;
1477 break;
1478
1479 case SPECIFIER_OCTAL:
1480 flags &= ~FLAGS_BASE_PARAMETER;
1481 base = BASE_OCTAL;
1482 parameters[pos].type = FORMAT_INT;
1483 break;
1484
1485#if defined(SPECIFIER_BINARY)
1486 case SPECIFIER_BINARY_UPPER:
1487 flags |= FLAGS_UPPER;
1488 /* FALLTHROUGH */
1489 case SPECIFIER_BINARY:
1490 flags |= FLAGS_NILPADDING;
1491 flags &= ~FLAGS_BASE_PARAMETER;
1492 base = BASE_BINARY;
1493 parameters[pos].type = FORMAT_INT;
1494 break;
1495#endif
1496
1497 case SPECIFIER_HEX_UPPER:
1498 flags |= FLAGS_UPPER;
1499 /* FALLTHROUGH */
1500 case SPECIFIER_HEX:
1501 flags |= FLAGS_UNSIGNED;
1502 flags &= ~FLAGS_BASE_PARAMETER;
1503 base = BASE_HEX;
1504 parameters[pos].type = FORMAT_INT;
1505 break;
1506
1507 case SPECIFIER_FLOAT_E_UPPER:
1508 flags |= FLAGS_UPPER;
1509 /* FALLTHROUGH */
1510 case SPECIFIER_FLOAT_E:
1511 flags |= FLAGS_FLOAT_E;
1512 parameters[pos].type = FORMAT_DOUBLE;
1513 break;
1514
1515 case SPECIFIER_FLOAT_G_UPPER:
1516 flags |= FLAGS_UPPER;
1517 /* FALLTHROUGH */
1518 case SPECIFIER_FLOAT_G:
1519 flags |= FLAGS_FLOAT_G;
1520 parameters[pos].type = FORMAT_DOUBLE;
1521 break;
1522
1523 case SPECIFIER_FLOAT_F_UPPER:
1524 flags |= FLAGS_UPPER;
1525 /* FALLTHROUGH */
1526 case SPECIFIER_FLOAT_F:
1527 parameters[pos].type = FORMAT_DOUBLE;
1528 break;
1529
1530 case SPECIFIER_POINTER:
1531 parameters[pos].type = FORMAT_POINTER;
1532 break;
1533
1534 case SPECIFIER_COUNT:
1535 parameters[pos].type = FORMAT_COUNT;
1536 break;
1537
1538#if defined(SPECIFIER_HEXFLOAT)
1539# if defined(SPECIFIER_HEXFLOAT_UPPER)
1540 case SPECIFIER_HEXFLOAT_UPPER:
1541 flags |= FLAGS_UPPER;
1542 /* FALLTHROUGH */
1543# endif
1544 case SPECIFIER_HEXFLOAT:
1545 base = BASE_HEX;
1546 parameters[pos].type = FORMAT_DOUBLE;
1547 break;
1548#endif
1549
1550#if defined(FORMAT_ERRNO)
1551 case SPECIFIER_ERRNO:
1552 parameters[pos].type = FORMAT_ERRNO;
1553 break;
1554#endif
1555
Bjorn Reese70a9da52001-04-21 16:57:29 +00001556#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1557 case SPECIFIER_USER_DEFINED_BEGIN:
1558 {
1559 unsigned int max;
1560 int without_namespace = TRUE;
1561
1562 parameters[pos].type = FORMAT_USER_DEFINED;
1563 parameters[pos].user_name[0] = NIL;
1564 tmpformat = (char *)&format[index];
1565
1566 while ((ch = format[index]))
1567 {
1568 index++;
1569 if (ch == SPECIFIER_USER_DEFINED_END)
1570 {
1571 if (without_namespace)
1572 {
1573 /* We must get the handle first */
1574 parameters[pos].type = FORMAT_PARAMETER;
1575 parameters[pos].indexAfterSpecifier = index;
1576 parameters[pos].flags = FLAGS_USER_DEFINED;
1577 /* Adjust parameters for insertion of new one */
1578 pos++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001579# if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +00001580 usedEntries[currentParam] += 1;
1581# endif
1582 parameters[pos].type = FORMAT_USER_DEFINED;
1583 currentParam++;
1584 indices[currentParam] = pos;
1585 if (currentParam > maxParam)
1586 maxParam = currentParam;
1587 }
1588 /* Copy the user data */
1589 max = (unsigned int)(&format[index] - tmpformat);
1590 if (max > MAX_USER_DATA)
1591 max = MAX_USER_DATA;
1592 StrCopyMax(parameters[pos].user_data,
1593 max,
1594 tmpformat);
1595 break; /* while */
1596 }
1597 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1598 {
1599 without_namespace = FALSE;
1600 /* Copy the namespace for later looking-up */
1601 max = (int)(&format[index] - tmpformat);
1602 if (max > MAX_USER_NAME)
1603 max = MAX_USER_NAME;
1604 StrCopyMax(parameters[pos].user_name,
1605 max,
1606 tmpformat);
1607 tmpformat = (char *)&format[index];
1608 }
1609 }
1610 if (ch != SPECIFIER_USER_DEFINED_END)
1611 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1612 }
1613 break;
1614#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1615
Daniel Veillard92ad2102001-03-27 12:47:33 +00001616 default:
1617 /* Bail out completely to make the error more obvious */
1618 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1619 }
1620
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001621#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001622 /* Count the number of times this entry has been used */
1623 usedEntries[currentParam] += 1;
1624#endif
1625
1626 /* Find last sticky parameters */
1627 if (got_sticky && !(flags & FLAGS_STICKY))
1628 {
1629 for (i = pos - 1; i >= 0; i--)
1630 {
1631 if (parameters[i].type == FORMAT_PARAMETER)
1632 continue;
1633 if ((parameters[i].flags & FLAGS_STICKY) &&
1634 (parameters[i].type == parameters[pos].type))
1635 {
1636 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001637 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001638 if (width == NO_WIDTH)
1639 width = parameters[i].width;
1640 if (precision == NO_PRECISION)
1641 precision = parameters[i].precision;
1642 if (base == NO_BASE)
1643 base = parameters[i].base;
1644 break;
1645 }
1646 }
1647 }
1648
1649 parameters[pos].indexAfterSpecifier = index;
1650 parameters[pos].flags = flags;
1651 parameters[pos].width = width;
1652 parameters[pos].precision = precision;
1653 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1654 parameters[pos].varsize = varsize;
1655 pos++;
1656
Bjorn Reese70a9da52001-04-21 16:57:29 +00001657 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001658 parameterPosition++;
1659
1660 } /* if identifier */
1661
1662 } /* while format characters left */
1663
1664 for (num = 0; num <= maxParam; num++)
1665 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001666#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001667 if (usedEntries[num] != 1)
1668 {
1669 if (usedEntries[num] == 0) /* gap detected */
1670 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1671 else /* double references detected */
1672 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1673 }
1674#endif
1675
1676 i = indices[num];
1677
Bjorn Reese70a9da52001-04-21 16:57:29 +00001678 /*
1679 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001680 * so it makes no sense to check the ignore flag (besides,
1681 * the flags variable is not set for that particular type)
1682 */
1683 if ((parameters[i].type != FORMAT_PARAMETER) &&
1684 (parameters[i].flags & FLAGS_IGNORE))
1685 continue; /* for all arguments */
1686
Bjorn Reese70a9da52001-04-21 16:57:29 +00001687 /*
1688 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001689 * default argument promotions:
1690 *
1691 * char = int
1692 * short = int
1693 * unsigned char = unsigned int
1694 * unsigned short = unsigned int
1695 * float = double
1696 *
1697 * In addition to the ANSI C89 these types are read (the
1698 * default argument promotions of C99 has not been
1699 * considered yet)
1700 *
1701 * long long
1702 * long double
1703 * size_t
1704 * ptrdiff_t
1705 * intmax_t
1706 */
1707 switch (parameters[i].type)
1708 {
1709 case FORMAT_GROUP:
1710 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001711#if TRIO_WIDECHAR
1712 if (flags & FLAGS_WIDECHAR)
1713 {
1714 parameters[i].data.wstring = (argarray == NULL)
1715 ? va_arg(arglist, wchar_t *)
1716 : (wchar_t *)(argarray[num]);
1717 }
1718 else
1719#endif
1720 {
1721 parameters[i].data.string = (argarray == NULL)
1722 ? va_arg(arglist, char *)
1723 : (char *)(argarray[num]);
1724 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001725 break;
1726
1727 case FORMAT_POINTER:
1728 case FORMAT_COUNT:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001729 case FORMAT_USER_DEFINED:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001730 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001731 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001732 ? va_arg(arglist, void *)
1733 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001734 break;
1735
1736 case FORMAT_CHAR:
1737 case FORMAT_INT:
1738 if (TYPE_SCAN == type)
1739 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001740 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001741 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001742 (trio_uintmax_t *)va_arg(arglist, void *);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001743 else
1744 {
1745 if (parameters[i].type == FORMAT_CHAR)
1746 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001747 (trio_uintmax_t *)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001748 else if (parameters[i].flags & FLAGS_SHORT)
1749 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001750 (trio_uintmax_t *)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001751 else
1752 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001753 (trio_uintmax_t *)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001754 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001755 }
1756 else
1757 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001758#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
1759 if ((parameters[i].flags & FLAGS_VARSIZE_PARAMETER) ||
1760 (parameters[i].flags & FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001761 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001762 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1763 {
1764 /*
1765 * Variable sizes are mapped onto the fixed sizes, in
1766 * accordance with integer promotion.
1767 *
1768 * Please note that this may not be portable, as we
1769 * only guess the size, not the layout of the numbers.
1770 * For example, if int is little-endian, and long is
1771 * big-endian, then this will fail.
1772 */
1773 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1774 }
1775 else
1776 {
1777 /* Used for the I<bits> modifiers */
1778 varsize = parameters[i].varsize;
1779 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001780 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001781
Daniel Veillard92ad2102001-03-27 12:47:33 +00001782 if (varsize <= (int)sizeof(int))
1783 ;
1784 else if (varsize <= (int)sizeof(long))
1785 parameters[i].flags |= FLAGS_LONG;
1786#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001787 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001788 parameters[i].flags |= FLAGS_QUAD;
1789 else
1790 parameters[i].flags |= FLAGS_INTMAX_T;
1791#else
1792 else
1793 parameters[i].flags |= FLAGS_QUAD;
1794#endif
1795 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001796#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001797#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1798 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001799 parameters[i].data.number.as_unsigned = (argarray == NULL)
1800 ? (trio_uintmax_t)va_arg(arglist, size_t)
1801 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001802 else
1803#endif
1804#if defined(QUALIFIER_PTRDIFF_T)
1805 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001806 parameters[i].data.number.as_unsigned = (argarray == NULL)
1807 ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
1808 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001809 else
1810#endif
1811#if defined(QUALIFIER_INTMAX_T)
1812 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001813 parameters[i].data.number.as_unsigned = (argarray == NULL)
1814 ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
1815 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001816 else
1817#endif
1818 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001819 parameters[i].data.number.as_unsigned = (argarray == NULL)
1820 ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
1821 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001822 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001823 parameters[i].data.number.as_unsigned = (argarray == NULL)
1824 ? (trio_uintmax_t)va_arg(arglist, long)
1825 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001826 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001827 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001828 if (argarray == NULL)
1829 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001830 else
1831 {
1832 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001833 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001834 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001835 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001836 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001837 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001838 }
1839 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001840 }
1841 break;
1842
1843 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001844 /*
1845 * The parameter for the user-defined specifier is a pointer,
1846 * whereas the rest (width, precision, base) uses an integer.
1847 */
1848 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001849 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001850 ? va_arg(arglist, void *)
1851 : argarray[num];
1852 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001853 parameters[i].data.number.as_unsigned = (argarray == NULL)
1854 ? (trio_uintmax_t)va_arg(arglist, int)
1855 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001856 break;
1857
1858 case FORMAT_DOUBLE:
1859 if (TYPE_SCAN == type)
1860 {
1861 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001862 parameters[i].data.longdoublePointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001863 ? va_arg(arglist, long double *)
1864 : (long double *)((long double *)argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001865 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001866 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001867 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001868 parameters[i].data.doublePointer =
1869 va_arg(arglist, double *);
1870 else
1871 {
1872 if (parameters[i].flags & FLAGS_SHORT)
1873 parameters[i].data.doublePointer =
1874 (double *)((float *)argarray[num]);
1875 else
1876 parameters[i].data.doublePointer =
1877 (double *)((double *)argarray[num]);
1878 }
1879 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001880 }
1881 else
1882 {
1883 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001884 parameters[i].data.longdoubleNumber = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001885 ? va_arg(arglist, long double)
1886 : (long double)(*((long double *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001887 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001888 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001889 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001890 parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
1891 else
1892 {
1893 if (parameters[i].flags & FLAGS_SHORT)
1894 parameters[i].data.longdoubleNumber = (long double)(*((float *)argarray[num]));
1895 else
1896 parameters[i].data.longdoubleNumber = (long double)(long double)(*((double *)argarray[num]));
1897 }
1898 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001899 }
1900 break;
1901
1902#if defined(FORMAT_ERRNO)
1903 case FORMAT_ERRNO:
1904 parameters[i].data.errorNumber = errno;
1905 break;
1906#endif
1907
1908 default:
1909 break;
1910 }
1911 } /* for all specifiers */
1912 return num;
1913}
1914
1915
1916/*************************************************************************
1917 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00001918 * @FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00001919 *
1920 ************************************************************************/
1921
1922
1923/*************************************************************************
1924 * TrioWriteNumber [private]
1925 *
1926 * Description:
1927 * Output a number.
1928 * The complexity of this function is a result of the complexity
1929 * of the dependencies of the flags.
1930 */
1931static void
1932TrioWriteNumber(trio_T *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001933 trio_uintmax_t number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001934 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001935 int width,
1936 int precision,
1937 int base)
1938{
1939 BOOLEAN_T isNegative;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001940 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001941 char *bufferend;
1942 char *pointer;
1943 const char *digits;
1944 int i;
1945 int length;
1946 char *p;
1947 int charsPerThousand;
1948 int groupingIndex;
1949 int count;
1950
1951 assert(VALID(self));
1952 assert(VALID(self->OutStream));
1953 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
1954
Bjorn Reese70a9da52001-04-21 16:57:29 +00001955 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001956
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001957 isNegative = (flags & FLAGS_UNSIGNED)
1958 ? FALSE
1959 : ((trio_intmax_t)number < 0);
1960 if (isNegative)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001961 number = -number;
1962
1963 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001964 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001965 else if (flags & FLAGS_LONG)
1966 number &= (unsigned long)-1;
1967 else
1968 number &= (unsigned int)-1;
1969
1970 /* Build number */
1971 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1972 *pointer-- = NIL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001973 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001974 groupingIndex = 1;
1975 for (i = 1; i < (int)sizeof(buffer); i++)
1976 {
1977 *pointer-- = digits[number % base];
1978 number /= base;
1979 if (number == 0)
1980 break;
1981
1982 if ((flags & FLAGS_QUOTE)
1983 && (charsPerThousand != NO_GROUPING)
1984 && (i % charsPerThousand == 0))
1985 {
1986 /*
1987 * We are building the number from the least significant
1988 * to the most significant digit, so we have to copy the
1989 * thousand separator backwards
1990 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001991 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001992 if (((int)(pointer - buffer) - length) > 0)
1993 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001994 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001995 while (length-- > 0)
1996 *pointer-- = *p--;
1997 }
1998
1999 /* Advance to next grouping number */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002000 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002001 {
2002 case CHAR_MAX: /* Disable grouping */
2003 charsPerThousand = NO_GROUPING;
2004 break;
2005 case 0: /* Repeat last group */
2006 break;
2007 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002008 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002009 break;
2010 }
2011 }
2012 }
2013
2014 /* Adjust width */
2015 width -= (bufferend - pointer) - 1;
2016
2017 /* Adjust precision */
2018 if (NO_PRECISION != precision)
2019 {
2020 precision -= (bufferend - pointer) - 1;
2021 if (precision < 0)
2022 precision = 0;
2023 flags |= FLAGS_NILPADDING;
2024 }
2025
2026 /* Adjust width further */
2027 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2028 width--;
2029 if (flags & FLAGS_ALTERNATIVE)
2030 {
2031 switch (base)
2032 {
2033 case BASE_BINARY:
2034 case BASE_HEX:
2035 width -= 2;
2036 break;
2037 case BASE_OCTAL:
2038 width--;
2039 break;
2040 default:
2041 break;
2042 }
2043 }
2044
2045 /* Output prefixes spaces if needed */
2046 if (! ((flags & FLAGS_LEFTADJUST) ||
2047 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2048 {
2049 count = (precision == NO_PRECISION) ? 0 : precision;
2050 while (width-- > count)
2051 self->OutStream(self, CHAR_ADJUST);
2052 }
2053
2054 /* width has been adjusted for signs and alternatives */
2055 if (isNegative)
2056 self->OutStream(self, '-');
2057 else if (flags & FLAGS_SHOWSIGN)
2058 self->OutStream(self, '+');
2059 else if (flags & FLAGS_SPACE)
2060 self->OutStream(self, ' ');
2061
2062 if (flags & FLAGS_ALTERNATIVE)
2063 {
2064 switch (base)
2065 {
2066 case BASE_BINARY:
2067 self->OutStream(self, '0');
2068 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2069 break;
2070
2071 case BASE_OCTAL:
2072 self->OutStream(self, '0');
2073 break;
2074
2075 case BASE_HEX:
2076 self->OutStream(self, '0');
2077 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2078 break;
2079
2080 default:
2081 break;
2082 } /* switch base */
2083 }
2084
2085 /* Output prefixed zero padding if needed */
2086 if (flags & FLAGS_NILPADDING)
2087 {
2088 if (precision == NO_PRECISION)
2089 precision = width;
2090 while (precision-- > 0)
2091 {
2092 self->OutStream(self, '0');
2093 width--;
2094 }
2095 }
2096
2097 /* Output the number itself */
2098 while (*(++pointer))
2099 {
2100 self->OutStream(self, *pointer);
2101 }
2102
2103 /* Output trailing spaces if needed */
2104 if (flags & FLAGS_LEFTADJUST)
2105 {
2106 while (width-- > 0)
2107 self->OutStream(self, CHAR_ADJUST);
2108 }
2109}
2110
2111/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002112 * TrioWriteStringCharacter [private]
2113 *
2114 * Description:
2115 * Output a single character of a string
2116 */
2117static void
2118TrioWriteStringCharacter(trio_T *self,
2119 int ch,
2120 unsigned long flags)
2121{
2122 if (flags & FLAGS_ALTERNATIVE)
2123 {
2124 if (! (isprint(ch) || isspace(ch)))
2125 {
2126 /*
2127 * Non-printable characters are converted to C escapes or
2128 * \number, if no C escape exists.
2129 */
2130 self->OutStream(self, CHAR_BACKSLASH);
2131 switch (ch)
2132 {
2133 case '\007': self->OutStream(self, 'a'); break;
2134 case '\b': self->OutStream(self, 'b'); break;
2135 case '\f': self->OutStream(self, 'f'); break;
2136 case '\n': self->OutStream(self, 'n'); break;
2137 case '\r': self->OutStream(self, 'r'); break;
2138 case '\t': self->OutStream(self, 't'); break;
2139 case '\v': self->OutStream(self, 'v'); break;
2140 case '\\': self->OutStream(self, '\\'); break;
2141 default:
2142 self->OutStream(self, 'x');
2143 TrioWriteNumber(self, (trio_intmax_t)ch,
2144 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2145 2, 2, BASE_HEX);
2146 break;
2147 }
2148 }
2149 else if (ch == CHAR_BACKSLASH)
2150 {
2151 self->OutStream(self, CHAR_BACKSLASH);
2152 self->OutStream(self, CHAR_BACKSLASH);
2153 }
2154 else
2155 {
2156 self->OutStream(self, ch);
2157 }
2158 }
2159 else
2160 {
2161 self->OutStream(self, ch);
2162 }
2163}
2164
2165/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002166 * TrioWriteString [private]
2167 *
2168 * Description:
2169 * Output a string
2170 */
2171static void
2172TrioWriteString(trio_T *self,
2173 const char *string,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002174 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002175 int width,
2176 int precision)
2177{
2178 int length;
2179 int ch;
2180
2181 assert(VALID(self));
2182 assert(VALID(self->OutStream));
2183
2184 if (string == NULL)
2185 {
2186 string = null;
2187 length = sizeof(null) - 1;
2188 /* Disable quoting for the null pointer */
2189 flags &= (~FLAGS_QUOTE);
2190 width = 0;
2191 }
2192 else
2193 {
2194 length = StrLength(string);
2195 }
2196 if ((NO_PRECISION != precision) &&
2197 (precision < length))
2198 {
2199 length = precision;
2200 }
2201 width -= length;
2202
2203 if (flags & FLAGS_QUOTE)
2204 self->OutStream(self, CHAR_QUOTE);
2205
2206 if (! (flags & FLAGS_LEFTADJUST))
2207 {
2208 while (width-- > 0)
2209 self->OutStream(self, CHAR_ADJUST);
2210 }
2211
2212 while (length-- > 0)
2213 {
2214 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002215 ch = (int)((unsigned char)(*string++));
2216 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002217 }
2218
2219 if (flags & FLAGS_LEFTADJUST)
2220 {
2221 while (width-- > 0)
2222 self->OutStream(self, CHAR_ADJUST);
2223 }
2224 if (flags & FLAGS_QUOTE)
2225 self->OutStream(self, CHAR_QUOTE);
2226}
2227
2228/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002229 * TrioWriteWideStringCharacter [private]
2230 *
2231 * Description:
2232 * Output a wide string as a multi-byte sequence
2233 */
2234#if TRIO_WIDECHAR
2235static int
2236TrioWriteWideStringCharacter(trio_T *self,
2237 wchar_t wch,
2238 unsigned long flags,
2239 int width)
2240{
2241 int size;
2242 int i;
2243 int ch;
2244 char *string;
2245 char buffer[MB_LEN_MAX + 1];
2246
2247 if (width == NO_WIDTH)
2248 width = sizeof(buffer);
2249
2250 size = wctomb(buffer, wch);
2251 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2252 return 0;
2253
2254 string = buffer;
2255 i = size;
2256 while ((width >= i) && (width-- > 0) && (i-- > 0))
2257 {
2258 /* The ctype parameters must be an unsigned char (or EOF) */
2259 ch = (int)((unsigned char)(*string++));
2260 TrioWriteStringCharacter(self, ch, flags);
2261 }
2262 return size;
2263}
2264#endif /* TRIO_WIDECHAR */
2265
2266/*************************************************************************
2267 * TrioWriteString [private]
2268 *
2269 * Description:
2270 * Output a wide character string as a multi-byte string
2271 */
2272#if TRIO_WIDECHAR
2273static void
2274TrioWriteWideString(trio_T *self,
2275 const wchar_t *wstring,
2276 unsigned long flags,
2277 int width,
2278 int precision)
2279{
2280 int length;
2281 int size;
2282
2283 assert(VALID(self));
2284 assert(VALID(self->OutStream));
2285
2286#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2287 mblen(NULL, 0);
2288#endif
2289
2290 if (wstring == NULL)
2291 {
2292 TrioWriteString(self, NULL, flags, width, precision);
2293 return;
2294 }
2295
2296 if (NO_PRECISION == precision)
2297 {
2298 length = INT_MAX;
2299 }
2300 else
2301 {
2302 length = precision;
2303 width -= length;
2304 }
2305
2306 if (flags & FLAGS_QUOTE)
2307 self->OutStream(self, CHAR_QUOTE);
2308
2309 if (! (flags & FLAGS_LEFTADJUST))
2310 {
2311 while (width-- > 0)
2312 self->OutStream(self, CHAR_ADJUST);
2313 }
2314
2315 while (length > 0)
2316 {
2317 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2318 if (size == 0)
2319 break; /* while */
2320 length -= size;
2321 }
2322
2323 if (flags & FLAGS_LEFTADJUST)
2324 {
2325 while (width-- > 0)
2326 self->OutStream(self, CHAR_ADJUST);
2327 }
2328 if (flags & FLAGS_QUOTE)
2329 self->OutStream(self, CHAR_QUOTE);
2330}
2331#endif /* TRIO_WIDECHAR */
2332
2333/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002334 * TrioWriteDouble [private]
2335 */
2336static void
2337TrioWriteDouble(trio_T *self,
2338 long double longdoubleNumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002339 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002340 int width,
2341 int precision,
2342 int base)
2343{
2344 int charsPerThousand;
2345 int length;
2346 double number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002347 double workNumber;
2348 int integerDigits;
2349 int fractionDigits;
2350 int exponentDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002351 int expectedWidth;
2352 int exponent;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002353 unsigned int uExponent = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002354 double dblBase;
2355 BOOLEAN_T isNegative;
2356 BOOLEAN_T isExponentNegative = FALSE;
2357 BOOLEAN_T isHex;
2358 const char *digits;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002359 char numberBuffer[MAX_MANTISSA_DIGITS
2360 * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002361 char *numberPointer;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002362 char exponentBuffer[MAX_EXPONENT_DIGITS + 1];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002363 char *exponentPointer = NULL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002364 int groupingIndex;
2365 char *work;
2366 int i;
2367 BOOLEAN_T onlyzero;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002368 int zeroes = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002369
2370 assert(VALID(self));
2371 assert(VALID(self->OutStream));
2372 assert(base == BASE_DECIMAL || base == BASE_HEX);
2373
2374 number = (double)longdoubleNumber;
2375
Bjorn Reese70a9da52001-04-21 16:57:29 +00002376 /* Look for infinite numbers and non-a-number first */
2377 switch (TrioIsInfinite(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002378 {
2379 case 1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002380 /* Positive infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002381 TrioWriteString(self,
2382 (flags & FLAGS_UPPER)
2383 ? INFINITE_UPPER
2384 : INFINITE_LOWER,
2385 flags, width, precision);
2386 return;
2387
2388 case -1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002389 /* Negative infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002390 TrioWriteString(self,
2391 (flags & FLAGS_UPPER)
2392 ? "-" INFINITE_UPPER
2393 : "-" INFINITE_LOWER,
2394 flags, width, precision);
2395 return;
2396
2397 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002398 /* Finitude */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002399 break;
2400 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002401 if (TrioIsNan(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002402 {
2403 TrioWriteString(self,
2404 (flags & FLAGS_UPPER)
2405 ? NAN_UPPER
2406 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002407 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002408 return;
2409 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002410
2411 /* Normal numbers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002412 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002413 isHex = (base == BASE_HEX);
2414 dblBase = (double)base;
2415
2416 if (precision == NO_PRECISION)
2417 precision = FLT_DIG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002418
2419 isNegative = (number < 0.0);
2420 if (isNegative)
2421 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002422
Daniel Veillard92ad2102001-03-27 12:47:33 +00002423 if ((flags & FLAGS_FLOAT_G) || isHex)
2424 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002425 if (precision == 0)
2426 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002427
2428 if ((number < 1.0e-4) || (number > pow(10.0, (double)precision)))
2429 {
2430 /* Use scientific notation */
2431 flags |= FLAGS_FLOAT_E;
2432 }
2433 else if (number < 1.0)
2434 {
2435 /*
2436 * Use normal notation. If the integer part of the number is
2437 * zero, then adjust the precision to include leading fractional
2438 * zeros.
2439 */
2440 workNumber = fabs(guarded_log10(number));
2441 if (workNumber - floor(workNumber) < 0.001)
2442 workNumber--;
2443 zeroes = (int)floor(workNumber);
2444 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002445 }
2446
2447 if (flags & FLAGS_FLOAT_E)
2448 {
2449 /* Scale the number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002450 workNumber = guarded_log10(number);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002451 if (workNumber == -HUGE_VAL)
2452 {
2453 exponent = 0;
2454 /* Undo setting */
2455 if (flags & FLAGS_FLOAT_G)
2456 flags &= ~FLAGS_FLOAT_E;
2457 }
2458 else
2459 {
2460 exponent = (int)floor(workNumber);
2461 number /= pow(10.0, (double)exponent);
2462 isExponentNegative = (exponent < 0);
2463 uExponent = (isExponentNegative) ? -exponent : exponent;
2464 /* No thousand separators */
2465 flags &= ~FLAGS_QUOTE;
2466 }
2467 }
2468
2469 /*
2470 * Truncated number.
2471 *
2472 * precision is number of significant digits for FLOAT_G
2473 * and number of fractional digits for others
2474 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002475 integerDigits = (floor(number) > DBL_EPSILON)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002476 ? 1 + (int)guarded_log10(floor(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002477 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002478 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002479 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002480 : zeroes + precision;
2481
2482 number = floor(0.5 + number * pow(dblBase, (double)fractionDigits));
2483 workNumber = (isHex
2484 ? guarded_log16(0.5 + number)
2485 : guarded_log10(0.5 + number));
2486 if ((int)workNumber + 1 > integerDigits + fractionDigits)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002487 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002488 if (flags & FLAGS_FLOAT_E)
2489 {
2490 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2491 exponent--;
2492 uExponent -= (isExponentNegative) ? 1 : -1;
2493 number /= dblBase;
2494 }
2495 else
2496 {
2497 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2498 integerDigits++;
2499 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002500 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002501
2502 /* Build the fraction part */
2503 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
2504 *numberPointer = NIL;
2505 onlyzero = TRUE;
2506 for (i = 0; i < fractionDigits; i++)
2507 {
2508 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2509 number = floor(number / dblBase);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002510
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002511 if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE))
2512 {
2513 /* Prune trailing zeroes */
2514 if (numberPointer[0] != digits[0])
2515 onlyzero = FALSE;
2516 else if (onlyzero && (numberPointer[0] == digits[0]))
2517 numberPointer++;
2518 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002519 else
2520 onlyzero = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002521 }
2522
2523 /* Insert decimal point */
2524 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
2525 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002526 i = StrLength(internalDecimalPoint);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002527 while (i> 0)
2528 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002529 *(--numberPointer) = internalDecimalPoint[--i];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002530 }
2531 }
2532 /* Insert the integer part and thousand separators */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002533 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002534 groupingIndex = 1;
2535 for (i = 1; i < integerDigits + 1; i++)
2536 {
2537 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2538 number = floor(number / dblBase);
2539 if (number < DBL_EPSILON)
2540 break;
2541
2542 if ((i > 0)
2543 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2544 && (charsPerThousand != NO_GROUPING)
2545 && (i % charsPerThousand == 0))
2546 {
2547 /*
2548 * We are building the number from the least significant
2549 * to the most significant digit, so we have to copy the
2550 * thousand separator backwards
2551 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002552 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002553 integerDigits += length;
2554 if (((int)(numberPointer - numberBuffer) - length) > 0)
2555 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002556 work = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002557 while (length-- > 0)
2558 *(--numberPointer) = *work--;
2559 }
2560
2561 /* Advance to next grouping number */
2562 if (charsPerThousand != NO_GROUPING)
2563 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002564 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002565 {
2566 case CHAR_MAX: /* Disable grouping */
2567 charsPerThousand = NO_GROUPING;
2568 break;
2569 case 0: /* Repeat last group */
2570 break;
2571 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002572 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002573 break;
2574 }
2575 }
2576 }
2577 }
2578
2579 /* Build the exponent */
2580 exponentDigits = 0;
2581 if (flags & FLAGS_FLOAT_E)
2582 {
2583 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2584 *exponentPointer-- = NIL;
2585 do {
2586 *exponentPointer-- = digits[uExponent % base];
2587 uExponent /= base;
2588 exponentDigits++;
2589 } while (uExponent);
2590 }
2591
Bjorn Reese70a9da52001-04-21 16:57:29 +00002592 /*
2593 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002594 * sign + integer part + thousands separators + decimal point
2595 * + fraction + exponent
2596 */
2597 expectedWidth = StrLength(numberPointer);
2598 if (isNegative || (flags & FLAGS_SHOWSIGN))
2599 expectedWidth += sizeof("-") - 1;
2600 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002601 expectedWidth += exponentDigits +
2602 ((exponentDigits > 1) ? sizeof("E+") : sizeof("E+0")) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002603 if (isHex)
2604 expectedWidth += sizeof("0X") - 1;
2605
2606 /* Output prefixing */
2607 if (flags & FLAGS_NILPADDING)
2608 {
2609 /* Leading zeros must be after sign */
2610 if (isNegative)
2611 self->OutStream(self, '-');
2612 else if (flags & FLAGS_SHOWSIGN)
2613 self->OutStream(self, '+');
2614 if (isHex)
2615 {
2616 self->OutStream(self, '0');
2617 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2618 }
2619 if (!(flags & FLAGS_LEFTADJUST))
2620 {
2621 for (i = expectedWidth; i < width; i++)
2622 {
2623 self->OutStream(self, '0');
2624 }
2625 }
2626 }
2627 else
2628 {
2629 /* Leading spaces must be before sign */
2630 if (!(flags & FLAGS_LEFTADJUST))
2631 {
2632 for (i = expectedWidth; i < width; i++)
2633 {
2634 self->OutStream(self, CHAR_ADJUST);
2635 }
2636 }
2637 if (isNegative)
2638 self->OutStream(self, '-');
2639 else if (flags & FLAGS_SHOWSIGN)
2640 self->OutStream(self, '+');
2641 if (isHex)
2642 {
2643 self->OutStream(self, '0');
2644 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2645 }
2646 }
2647 /* Output number */
2648 for (i = 0; numberPointer[i]; i++)
2649 {
2650 self->OutStream(self, numberPointer[i]);
2651 }
2652 /* Output exponent */
2653 if (exponentDigits > 0)
2654 {
2655 self->OutStream(self,
2656 isHex
2657 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2658 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2659 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002660
2661 /* The exponent must contain at least two digits */
2662 if (exponentDigits == 1)
2663 self->OutStream(self, '0');
2664
Daniel Veillard92ad2102001-03-27 12:47:33 +00002665 for (i = 0; i < exponentDigits; i++)
2666 {
2667 self->OutStream(self, exponentPointer[i + 1]);
2668 }
2669 }
2670 /* Output trailing spaces */
2671 if (flags & FLAGS_LEFTADJUST)
2672 {
2673 for (i = expectedWidth; i < width; i++)
2674 {
2675 self->OutStream(self, CHAR_ADJUST);
2676 }
2677 }
2678}
2679
2680/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002681 * TrioFormatProcess [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +00002682 */
2683static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002684TrioFormatProcess(trio_T *data,
2685 const char *format,
2686 parameter_T *parameters)
2687
Daniel Veillard92ad2102001-03-27 12:47:33 +00002688{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002689#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002690 int charlen;
2691#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00002692 int i;
2693 const char *string;
2694 void *pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002695 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002696 int width;
2697 int precision;
2698 int base;
2699 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002700
Daniel Veillard92ad2102001-03-27 12:47:33 +00002701 index = 0;
2702 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002703#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002704 mblen(NULL, 0);
2705#endif
2706
2707 while (format[index])
2708 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002709#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002710 if (! isascii(format[index]))
2711 {
2712 charlen = mblen(&format[index], MB_LEN_MAX);
2713 while (charlen-- > 0)
2714 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002716 }
2717 continue; /* while */
2718 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002719#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002720 if (CHAR_IDENTIFIER == format[index])
2721 {
2722 if (CHAR_IDENTIFIER == format[index + 1])
2723 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002724 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002725 index += 2;
2726 }
2727 else
2728 {
2729 /* Skip the parameter entries */
2730 while (parameters[i].type == FORMAT_PARAMETER)
2731 i++;
2732
2733 flags = parameters[i].flags;
2734
2735 /* Find width */
2736 width = parameters[i].width;
2737 if (flags & FLAGS_WIDTH_PARAMETER)
2738 {
2739 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002740 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002741 }
2742
2743 /* Find precision */
2744 if (flags & FLAGS_PRECISION)
2745 {
2746 precision = parameters[i].precision;
2747 if (flags & FLAGS_PRECISION_PARAMETER)
2748 {
2749 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002751 }
2752 }
2753 else
2754 {
2755 precision = NO_PRECISION;
2756 }
2757
2758 /* Find base */
2759 base = parameters[i].base;
2760 if (flags & FLAGS_BASE_PARAMETER)
2761 {
2762 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002763 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002764 }
2765
2766 switch (parameters[i].type)
2767 {
2768 case FORMAT_CHAR:
2769 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002770 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002771 if (! (flags & FLAGS_LEFTADJUST))
2772 {
2773 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002774 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002775 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002776#if TRIO_WIDECHAR
2777 if (flags & FLAGS_WIDECHAR)
2778 {
2779 TrioWriteWideStringCharacter(data,
2780 (wchar_t)parameters[i].data.number.as_signed,
2781 flags,
2782 NO_WIDTH);
2783 }
2784 else
2785#endif
2786 TrioWriteStringCharacter(data,
2787 (int)parameters[i].data.number.as_signed,
2788 flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002789
2790 if (flags & FLAGS_LEFTADJUST)
2791 {
2792 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002793 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002794 }
2795 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002796 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002797
2798 break; /* FORMAT_CHAR */
2799
2800 case FORMAT_INT:
2801 if (base == NO_BASE)
2802 base = BASE_DECIMAL;
2803
2804 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002805 parameters[i].data.number.as_signed,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002806 flags,
2807 width,
2808 precision,
2809 base);
2810
2811 break; /* FORMAT_INT */
2812
2813 case FORMAT_DOUBLE:
2814 TrioWriteDouble(data,
2815 parameters[i].data.longdoubleNumber,
2816 flags,
2817 width,
2818 precision,
2819 base);
2820 break; /* FORMAT_DOUBLE */
2821
2822 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002823#if TRIO_WIDECHAR
2824 if (flags & FLAGS_WIDECHAR)
2825 {
2826 TrioWriteWideString(data,
2827 parameters[i].data.wstring,
2828 flags,
2829 width,
2830 precision);
2831 }
2832 else
2833#endif
2834 {
2835 TrioWriteString(data,
2836 parameters[i].data.string,
2837 flags,
2838 width,
2839 precision);
2840 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002841 break; /* FORMAT_STRING */
2842
2843 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002844 {
2845 reference_T reference;
2846
2847 reference.data = data;
2848 reference.parameter = &parameters[i];
2849 trio_print_pointer(&reference, parameters[i].data.pointer);
2850 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002851 break; /* FORMAT_POINTER */
2852
2853 case FORMAT_COUNT:
2854 pointer = parameters[i].data.pointer;
2855 if (NULL != pointer)
2856 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002857 /*
2858 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00002859 * characters written to the output stream so far by
2860 * this call", which is data->committed
2861 */
2862#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2863 if (flags & FLAGS_SIZE_T)
2864 *(size_t *)pointer = (size_t)data->committed;
2865 else
2866#endif
2867#if defined(QUALIFIER_PTRDIFF_T)
2868 if (flags & FLAGS_PTRDIFF_T)
2869 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2870 else
2871#endif
2872#if defined(QUALIFIER_INTMAX_T)
2873 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002874 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002875 else
2876#endif
2877 if (flags & FLAGS_QUAD)
2878 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002879 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002880 }
2881 else if (flags & FLAGS_LONG)
2882 {
2883 *(long int *)pointer = (long int)data->committed;
2884 }
2885 else if (flags & FLAGS_SHORT)
2886 {
2887 *(short int *)pointer = (short int)data->committed;
2888 }
2889 else
2890 {
2891 *(int *)pointer = (int)data->committed;
2892 }
2893 }
2894 break; /* FORMAT_COUNT */
2895
2896 case FORMAT_PARAMETER:
2897 break; /* FORMAT_PARAMETER */
2898
2899#if defined(FORMAT_ERRNO)
2900 case FORMAT_ERRNO:
2901 string = StrError(parameters[i].data.errorNumber);
2902 if (string)
2903 {
2904 TrioWriteString(data,
2905 string,
2906 flags,
2907 width,
2908 precision);
2909 }
2910 else
2911 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002912 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002913 TrioWriteNumber(data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002914 (trio_intmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002915 flags,
2916 width,
2917 precision,
2918 BASE_DECIMAL);
2919 }
2920 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002921#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002922
Bjorn Reese70a9da52001-04-21 16:57:29 +00002923#if defined(FORMAT_USER_DEFINED)
2924 case FORMAT_USER_DEFINED:
2925 {
2926 reference_T reference;
2927 userdef_T *def = NULL;
2928
2929 if (parameters[i].user_name[0] == NIL)
2930 {
2931 /* Use handle */
2932 if ((i > 0) ||
2933 (parameters[i - 1].type == FORMAT_PARAMETER))
2934 def = (userdef_T *)parameters[i - 1].data.pointer;
2935 }
2936 else
2937 {
2938 /* Look up namespace */
2939 def = TrioFindNamespace(parameters[i].user_name, NULL);
2940 }
2941 if (def) {
2942 reference.data = data;
2943 reference.parameter = &parameters[i];
2944 def->callback(&reference);
2945 }
2946 }
2947 break;
2948#endif /* defined(FORMAT_USER_DEFINED) */
2949
Daniel Veillard92ad2102001-03-27 12:47:33 +00002950 default:
2951 break;
2952 } /* switch parameter type */
2953
2954 /* Prepare for next */
2955 index = parameters[i].indexAfterSpecifier;
2956 i++;
2957 }
2958 }
2959 else /* not identifier */
2960 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002961 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002962 }
2963 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002964 return data->processed;
2965}
2966
2967/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002968 * TrioFormatRef [private]
2969 */
2970static int
2971TrioFormatRef(reference_T *reference,
2972 const char *format,
2973 va_list arglist,
2974 void **argarray)
2975{
2976 int status;
2977 parameter_T parameters[MAX_PARAMETERS];
2978
2979 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2980 if (status < 0)
2981 return status;
2982
2983 return TrioFormatProcess(reference->data, format, parameters);
2984}
2985
2986/*************************************************************************
2987 * TrioFormat [private]
2988 *
2989 * Description:
2990 * This is the main engine for formatting output
2991 */
2992static int
2993TrioFormat(void *destination,
2994 size_t destinationSize,
2995 void (*OutStream)(trio_T *, int),
2996 const char *format,
2997 va_list arglist,
2998 void **argarray)
2999{
3000 int status;
3001 trio_T data;
3002 parameter_T parameters[MAX_PARAMETERS];
3003
3004 assert(VALID(OutStream));
3005 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003006
3007 memset(&data, 0, sizeof(data));
3008 data.OutStream = OutStream;
3009 data.location = destination;
3010 data.max = destinationSize;
3011
3012#if defined(USE_LOCALE)
3013 if (NULL == internalLocaleValues)
3014 {
3015 TrioSetLocale();
3016 }
3017#endif
3018
3019 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
3020 if (status < 0)
3021 return status;
3022
3023 return TrioFormatProcess(&data, format, parameters);
3024}
3025
3026/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00003027 * TrioOutStreamFile [private]
3028 */
3029static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003030TrioOutStreamFile(trio_T *self,
3031 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003032{
3033 FILE *file = (FILE *)self->location;
3034
3035 assert(VALID(self));
3036 assert(VALID(file));
3037
3038 self->processed++;
3039 self->committed++;
3040 (void)fputc(output, file);
3041}
3042
3043/*************************************************************************
3044 * TrioOutStreamFileDescriptor [private]
3045 */
3046static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003047TrioOutStreamFileDescriptor(trio_T *self,
3048 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003049{
3050 int fd = *((int *)self->location);
3051 char ch;
3052
3053 assert(VALID(self));
3054
3055 ch = (char)output;
3056 (void)write(fd, &ch, sizeof(char));
3057 self->processed++;
3058 self->committed++;
3059}
3060
3061/*************************************************************************
3062 * TrioOutStreamString [private]
3063 */
3064static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003065TrioOutStreamString(trio_T *self,
3066 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003067{
3068 char **buffer = (char **)self->location;
3069
3070 assert(VALID(self));
3071 assert(VALID(buffer));
3072
3073 **buffer = (char)output;
3074 (*buffer)++;
3075 self->processed++;
3076 self->committed++;
3077}
3078
3079/*************************************************************************
3080 * TrioOutStreamStringMax [private]
3081 */
3082static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003083TrioOutStreamStringMax(trio_T *self,
3084 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003085{
3086 char **buffer;
3087
3088 assert(VALID(self));
3089 buffer = (char **)self->location;
3090 assert(VALID(buffer));
3091
3092 if (self->processed < self->max)
3093 {
3094 **buffer = (char)output;
3095 (*buffer)++;
3096 self->committed++;
3097 }
3098 self->processed++;
3099}
3100
3101/*************************************************************************
3102 * TrioOutStreamStringDynamic [private]
3103 */
3104#define DYNAMIC_START_SIZE 32
3105struct dynamicBuffer {
3106 char *buffer;
3107 size_t length;
3108 size_t allocated;
3109};
3110
3111static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003112TrioOutStreamStringDynamic(trio_T *self,
3113 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003114{
3115 struct dynamicBuffer *infop;
3116
3117 assert(VALID(self));
3118 assert(VALID(self->location));
3119
3120 infop = (struct dynamicBuffer *)self->location;
3121
3122 if (infop->buffer == NULL)
3123 {
3124 /* Start with a reasonable size */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003125 infop->buffer = (char *)TRIO_MALLOC(DYNAMIC_START_SIZE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003126 if (infop->buffer == NULL)
3127 return; /* fail */
3128
3129 infop->allocated = DYNAMIC_START_SIZE;
3130 self->processed = 0;
3131 self->committed = 0;
3132 }
3133 else if (self->committed + sizeof(NIL) >= infop->allocated)
3134 {
3135 char *newptr;
3136
3137 /* Allocate increasing chunks */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003138 newptr = (char *)TRIO_REALLOC(infop->buffer, infop->allocated * 2);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003139
3140 if (newptr == NULL)
3141 return;
3142
3143 infop->buffer = newptr;
3144 infop->allocated *= 2;
3145 }
3146
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003147 infop->buffer[self->committed] = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003148 self->committed++;
3149 self->processed++;
3150
3151 infop->length = self->committed;
3152}
3153
Daniel Veillard92ad2102001-03-27 12:47:33 +00003154/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003155 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003156 */
3157int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003158trio_printf(const char *format,
3159 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003160{
3161 int status;
3162 va_list args;
3163
3164 assert(VALID(format));
3165
3166 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003167 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003168 va_end(args);
3169 return status;
3170}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003171
Bjorn Reese70a9da52001-04-21 16:57:29 +00003172int
3173trio_vprintf(const char *format,
3174 va_list args)
3175{
3176 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003177
3178 return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
3179}
3180
3181int
3182trio_printfv(const char *format,
3183 void ** args)
3184{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003185 va_list dummy;
3186
Bjorn Reese70a9da52001-04-21 16:57:29 +00003187 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003188
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003189 return TrioFormat(stdout, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003190}
3191
Daniel Veillard92ad2102001-03-27 12:47:33 +00003192/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003193 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003194 */
3195int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003196trio_fprintf(FILE *file,
3197 const char *format,
3198 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003199{
3200 int status;
3201 va_list args;
3202
3203 assert(VALID(file));
3204 assert(VALID(format));
3205
3206 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003207 status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003208 va_end(args);
3209 return status;
3210}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003211
Daniel Veillard92ad2102001-03-27 12:47:33 +00003212int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003213trio_vfprintf(FILE *file,
3214 const char *format,
3215 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003216{
3217 assert(VALID(file));
3218 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003219
Bjorn Reese70a9da52001-04-21 16:57:29 +00003220 return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003221}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003222
Bjorn Reese70a9da52001-04-21 16:57:29 +00003223int
3224trio_fprintfv(FILE *file,
3225 const char *format,
3226 void ** args)
3227{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003228 va_list dummy;
3229
Bjorn Reese70a9da52001-04-21 16:57:29 +00003230 assert(VALID(file));
3231 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003232
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003233 return TrioFormat(file, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003234}
3235
Daniel Veillard92ad2102001-03-27 12:47:33 +00003236/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003237 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003238 */
3239int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003240trio_dprintf(int fd,
3241 const char *format,
3242 ...)
3243{
3244 int status;
3245 va_list args;
3246
3247 assert(VALID(format));
3248
3249 va_start(args, format);
3250 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3251 va_end(args);
3252 return status;
3253}
3254
3255int
3256trio_vdprintf(int fd,
3257 const char *format,
3258 va_list args)
3259{
3260 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003261
3262 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3263}
3264
3265int
3266trio_dprintfv(int fd,
3267 const char *format,
3268 void **args)
3269{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003270 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003271
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003272 assert(VALID(format));
3273
3274 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003275}
3276
3277/*************************************************************************
3278 * sprintf
3279 */
3280int
3281trio_sprintf(char *buffer,
3282 const char *format,
3283 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003284{
3285 int status;
3286 va_list args;
3287
3288 assert(VALID(buffer));
3289 assert(VALID(format));
3290
3291 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003292 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003293 *buffer = NIL; /* Terminate with NIL character */
3294 va_end(args);
3295 return status;
3296}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003297
Daniel Veillard92ad2102001-03-27 12:47:33 +00003298int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003299trio_vsprintf(char *buffer,
3300 const char *format,
3301 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003302{
3303 int status;
3304
3305 assert(VALID(buffer));
3306 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003307
Bjorn Reese70a9da52001-04-21 16:57:29 +00003308 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003309 *buffer = NIL;
3310 return status;
3311}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003312
Bjorn Reese70a9da52001-04-21 16:57:29 +00003313int
3314trio_sprintfv(char *buffer,
3315 const char *format,
3316 void **args)
3317{
3318 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003319 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003320
3321 assert(VALID(buffer));
3322 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003323
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003324 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003325 *buffer = NIL;
3326 return status;
3327}
3328
Daniel Veillard92ad2102001-03-27 12:47:33 +00003329/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003330 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003331 */
3332int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003333trio_snprintf(char *buffer,
3334 size_t bufferSize,
3335 const char *format,
3336 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003337{
3338 int status;
3339 va_list args;
3340
3341 assert(VALID(buffer));
3342 assert(VALID(format));
3343
3344 va_start(args, format);
3345 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003346 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003347 if (bufferSize > 0)
3348 *buffer = NIL;
3349 va_end(args);
3350 return status;
3351}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003352
Daniel Veillard92ad2102001-03-27 12:47:33 +00003353int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003354trio_vsnprintf(char *buffer,
3355 size_t bufferSize,
3356 const char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003357 va_list args)
3358{
3359 int status;
3360
3361 assert(VALID(buffer));
3362 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003363
3364 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003365 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003366 if (bufferSize > 0)
3367 *buffer = NIL;
3368 return status;
3369}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003370
3371int
3372trio_snprintfv(char *buffer,
3373 size_t bufferSize,
3374 const char *format,
3375 void **args)
3376{
3377 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003378 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003379
3380 assert(VALID(buffer));
3381 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003382
3383 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003384 TrioOutStreamStringMax, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003385 if (bufferSize > 0)
3386 *buffer = NIL;
3387 return status;
3388}
3389
3390/*************************************************************************
3391 * snprintfcat
3392 * Appends the new string to the buffer string overwriting the '\0'
3393 * character at the end of buffer.
3394 */
3395int
3396trio_snprintfcat(char *buffer,
3397 size_t bufferSize,
3398 const char *format,
3399 ...)
3400{
3401 int status;
3402 va_list args;
3403 size_t buf_len;
3404
3405 va_start(args, format);
3406
3407 assert(VALID(buffer));
3408 assert(VALID(format));
3409
3410 buf_len = strlen(buffer);
3411 buffer = &buffer[buf_len];
3412
3413 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3414 TrioOutStreamStringMax, format, args, NULL);
3415 va_end(args);
3416 *buffer = NIL;
3417 return status;
3418}
3419
3420int
3421trio_vsnprintfcat(char *buffer,
3422 size_t bufferSize,
3423 const char *format,
3424 va_list args)
3425{
3426 int status;
3427 size_t buf_len;
3428 assert(VALID(buffer));
3429 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003430
3431 buf_len = strlen(buffer);
3432 buffer = &buffer[buf_len];
3433 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3434 TrioOutStreamStringMax, format, args, NULL);
3435 *buffer = NIL;
3436 return status;
3437}
3438
3439/*************************************************************************
3440 * trio_aprintf
3441 */
3442
3443/* Deprecated */
3444char *
3445trio_aprintf(const char *format,
3446 ...)
3447{
3448 va_list args;
3449 struct dynamicBuffer info;
3450
3451 assert(VALID(format));
3452
3453 info.buffer = NULL;
3454 info.length = 0;
3455 info.allocated = 0;
3456
3457 va_start(args, format);
3458 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3459 va_end(args);
3460 if (info.length) {
3461 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3462 return info.buffer;
3463 }
3464 else
3465 return NULL;
3466}
3467
3468/* Deprecated */
3469char *
3470trio_vaprintf(const char *format,
3471 va_list args)
3472{
3473 struct dynamicBuffer info;
3474
3475 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003476
3477 info.buffer = NULL;
3478 info.length = 0;
3479 info.allocated = 0;
3480
3481 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3482 if (info.length) {
3483 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3484 return info.buffer;
3485 }
3486 else
3487 return NULL;
3488}
3489
3490int
3491trio_asprintf(char **result,
3492 const char *format,
3493 ...)
3494{
3495 va_list args;
3496 int status;
3497 struct dynamicBuffer info;
3498
3499 assert(VALID(format));
3500
3501 info.buffer = NULL;
3502 info.length = 0;
3503 info.allocated = 0;
3504
3505 va_start(args, format);
3506 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3507 va_end(args);
3508 if (status < 0) {
3509 *result = NULL;
3510 return status;
3511 }
3512 if (info.length == 0) {
3513 /*
3514 * If the length is zero, no characters have been written and therefore
3515 * no memory has been allocated, but we must to allocate and return an
3516 * empty string.
3517 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003518 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003519 if (info.buffer == NULL) {
3520 *result = NULL;
3521 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3522 }
3523 }
3524 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3525 *result = info.buffer;
3526
3527 return status;
3528}
3529
3530int
3531trio_vasprintf(char **result,
3532 const char *format,
3533 va_list args)
3534{
3535 int status;
3536 struct dynamicBuffer info;
3537
3538 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003539
3540 info.buffer = NULL;
3541 info.length = 0;
3542 info.allocated = 0;
3543
3544 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3545 if (status < 0) {
3546 *result = NULL;
3547 return status;
3548 }
3549 if (info.length == 0) {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003550 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003551 if (info.buffer == NULL) {
3552 *result = NULL;
3553 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3554 }
3555 }
3556 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3557 *result = info.buffer;
3558
3559 return status;
3560}
3561
Daniel Veillard92ad2102001-03-27 12:47:33 +00003562
3563/*************************************************************************
3564 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003565 * @CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00003566 *
3567 ************************************************************************/
3568
Bjorn Reese70a9da52001-04-21 16:57:29 +00003569
3570/*************************************************************************
3571 * trio_register [public]
3572 */
3573void *
3574trio_register(trio_callback_t callback,
3575 const char *name)
3576{
3577 userdef_T *def;
3578 userdef_T *prev = NULL;
3579
3580 if (callback == NULL)
3581 return NULL;
3582
3583 if (name)
3584 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003585 /* Handle built-in namespaces */
3586 if (name[0] == ':')
3587 {
3588 if (StrEqual(name, ":enter"))
3589 {
3590 internalEnterCriticalRegion = callback;
3591 }
3592 else if (StrEqual(name, ":leave"))
3593 {
3594 internalLeaveCriticalRegion = callback;
3595 }
3596 return NULL;
3597 }
3598
Bjorn Reese70a9da52001-04-21 16:57:29 +00003599 /* Bail out if namespace is too long */
3600 if (StrLength(name) >= MAX_USER_NAME)
3601 return NULL;
3602
3603 /* Bail out if namespace already is registered */
3604 def = TrioFindNamespace(name, &prev);
3605 if (def)
3606 return NULL;
3607 }
3608
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003609 def = (userdef_T *)TRIO_MALLOC(sizeof(userdef_T));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003610 if (def)
3611 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003612 if (internalEnterCriticalRegion)
3613 (void)internalEnterCriticalRegion(NULL);
3614
Bjorn Reese70a9da52001-04-21 16:57:29 +00003615 if (name)
3616 {
3617 /* Link into internal list */
3618 if (prev == NULL)
3619 internalUserDef = def;
3620 else
3621 prev->next = def;
3622 }
3623 /* Initialize */
3624 def->callback = callback;
3625 def->name = (name == NULL)
3626 ? NULL
3627 : StrDuplicate(name);
3628 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003629
3630 if (internalLeaveCriticalRegion)
3631 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003632 }
3633 return def;
3634}
3635
3636/*************************************************************************
3637 * trio_unregister [public]
3638 */
3639void
3640trio_unregister(void *handle)
3641{
3642 userdef_T *self = (userdef_T *)handle;
3643 userdef_T *def;
3644 userdef_T *prev = NULL;
3645
3646 assert(VALID(self));
3647
3648 if (self->name)
3649 {
3650 def = TrioFindNamespace(self->name, &prev);
3651 if (def)
3652 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003653 if (internalEnterCriticalRegion)
3654 (void)internalEnterCriticalRegion(NULL);
3655
Bjorn Reese70a9da52001-04-21 16:57:29 +00003656 if (prev == NULL)
3657 internalUserDef = NULL;
3658 else
3659 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003660
3661 if (internalLeaveCriticalRegion)
3662 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003663 }
3664 StrFree(self->name);
3665 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003666 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003667}
3668
3669/*************************************************************************
3670 * trio_get_format [public]
3671 */
3672const char *
3673trio_get_format(void *ref)
3674{
3675 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3676
3677 return (((reference_T *)ref)->parameter->user_data);
3678}
3679
3680/*************************************************************************
3681 * trio_get_argument [public]
3682 */
3683void *
3684trio_get_argument(void *ref)
3685{
3686 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3687
3688 return ((reference_T *)ref)->parameter->data.pointer;
3689}
3690
3691/*************************************************************************
3692 * trio_get_width / trio_set_width [public]
3693 */
3694int
3695trio_get_width(void *ref)
3696{
3697 return ((reference_T *)ref)->parameter->width;
3698}
3699
3700void
3701trio_set_width(void *ref,
3702 int width)
3703{
3704 ((reference_T *)ref)->parameter->width = width;
3705}
3706
3707/*************************************************************************
3708 * trio_get_precision / trio_set_precision [public]
3709 */
3710int
3711trio_get_precision(void *ref)
3712{
3713 return (((reference_T *)ref)->parameter->precision);
3714}
3715
3716void
3717trio_set_precision(void *ref,
3718 int precision)
3719{
3720 ((reference_T *)ref)->parameter->precision = precision;
3721}
3722
3723/*************************************************************************
3724 * trio_get_base / trio_set_base [public]
3725 */
3726int
3727trio_get_base(void *ref)
3728{
3729 return (((reference_T *)ref)->parameter->base);
3730}
3731
3732void
3733trio_set_base(void *ref,
3734 int base)
3735{
3736 ((reference_T *)ref)->parameter->base = base;
3737}
3738
3739/*************************************************************************
3740 * trio_get_long / trio_set_long [public]
3741 */
3742int
3743trio_get_long(void *ref)
3744{
3745 return (((reference_T *)ref)->parameter->flags & FLAGS_LONG);
3746}
3747
3748void
3749trio_set_long(void *ref,
3750 int is_long)
3751{
3752 if (is_long)
3753 ((reference_T *)ref)->parameter->flags |= FLAGS_LONG;
3754 else
3755 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONG;
3756}
3757
3758/*************************************************************************
3759 * trio_get_longlong / trio_set_longlong [public]
3760 */
3761int
3762trio_get_longlong(void *ref)
3763{
3764 return (((reference_T *)ref)->parameter->flags & FLAGS_QUAD);
3765}
3766
3767void
3768trio_set_longlong(void *ref,
3769 int is_longlong)
3770{
3771 if (is_longlong)
3772 ((reference_T *)ref)->parameter->flags |= FLAGS_QUAD;
3773 else
3774 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUAD;
3775}
3776
3777/*************************************************************************
3778 * trio_get_longdouble / trio_set_longdouble [public]
3779 */
3780int
3781trio_get_longdouble(void *ref)
3782{
3783 return (((reference_T *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
3784}
3785
3786void
3787trio_set_longdouble(void *ref,
3788 int is_longdouble)
3789{
3790 if (is_longdouble)
3791 ((reference_T *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
3792 else
3793 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
3794}
3795
3796/*************************************************************************
3797 * trio_get_short / trio_set_short [public]
3798 */
3799int
3800trio_get_short(void *ref)
3801{
3802 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORT);
3803}
3804
3805void
3806trio_set_short(void *ref,
3807 int is_short)
3808{
3809 if (is_short)
3810 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORT;
3811 else
3812 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORT;
3813}
3814
3815/*************************************************************************
3816 * trio_get_shortshort / trio_set_shortshort [public]
3817 */
3818int
3819trio_get_shortshort(void *ref)
3820{
3821 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORTSHORT);
3822}
3823
3824void
3825trio_set_shortshort(void *ref,
3826 int is_shortshort)
3827{
3828 if (is_shortshort)
3829 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
3830 else
3831 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
3832}
3833
3834/*************************************************************************
3835 * trio_get_alternative / trio_set_alternative [public]
3836 */
3837int
3838trio_get_alternative(void *ref)
3839{
3840 return (((reference_T *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
3841}
3842
3843void
3844trio_set_alternative(void *ref,
3845 int is_alternative)
3846{
3847 if (is_alternative)
3848 ((reference_T *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
3849 else
3850 ((reference_T *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
3851}
3852
3853/*************************************************************************
3854 * trio_get_alignment / trio_set_alignment [public]
3855 */
3856int
3857trio_get_alignment(void *ref)
3858{
3859 return (((reference_T *)ref)->parameter->flags & FLAGS_LEFTADJUST);
3860}
3861
3862void
3863trio_set_alignment(void *ref,
3864 int is_leftaligned)
3865{
3866 if (is_leftaligned)
3867 ((reference_T *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
3868 else
3869 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
3870}
3871
3872/*************************************************************************
3873 * trio_get_spacing /trio_set_spacing [public]
3874 */
3875int
3876trio_get_spacing(void *ref)
3877{
3878 return (((reference_T *)ref)->parameter->flags & FLAGS_SPACE);
3879}
3880
3881void
3882trio_set_spacing(void *ref,
3883 int is_space)
3884{
3885 if (is_space)
3886 ((reference_T *)ref)->parameter->flags |= FLAGS_SPACE;
3887 else
3888 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SPACE;
3889}
3890
3891/*************************************************************************
3892 * trio_get_sign / trio_set_sign [public]
3893 */
3894int
3895trio_get_sign(void *ref)
3896{
3897 return (((reference_T *)ref)->parameter->flags & FLAGS_SHOWSIGN);
3898}
3899
3900void
3901trio_set_sign(void *ref,
3902 int is_sign)
3903{
3904 if (is_sign)
3905 ((reference_T *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
3906 else
3907 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
3908}
3909
3910/*************************************************************************
3911 * trio_get_padding / trio_set_padding [public]
3912 */
3913int
3914trio_get_padding(void *ref)
3915{
3916 return (((reference_T *)ref)->parameter->flags & FLAGS_NILPADDING);
3917}
3918
3919void
3920trio_set_padding(void *ref,
3921 int is_padding)
3922{
3923 if (is_padding)
3924 ((reference_T *)ref)->parameter->flags |= FLAGS_NILPADDING;
3925 else
3926 ((reference_T *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
3927}
3928
3929/*************************************************************************
3930 * trio_get_quote / trio_set_quote [public]
3931 */
3932int
3933trio_get_quote(void *ref)
3934{
3935 return (((reference_T *)ref)->parameter->flags & FLAGS_QUOTE);
3936}
3937
3938void
3939trio_set_quote(void *ref,
3940 int is_quote)
3941{
3942 if (is_quote)
3943 ((reference_T *)ref)->parameter->flags |= FLAGS_QUOTE;
3944 else
3945 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUOTE;
3946}
3947
3948/*************************************************************************
3949 * trio_get_upper / trio_set_upper [public]
3950 */
3951int
3952trio_get_upper(void *ref)
3953{
3954 return (((reference_T *)ref)->parameter->flags & FLAGS_UPPER);
3955}
3956
3957void
3958trio_set_upper(void *ref,
3959 int is_upper)
3960{
3961 if (is_upper)
3962 ((reference_T *)ref)->parameter->flags |= FLAGS_UPPER;
3963 else
3964 ((reference_T *)ref)->parameter->flags &= ~FLAGS_UPPER;
3965}
3966
3967/*************************************************************************
3968 * trio_get_largest / trio_set_largest [public]
3969 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003970#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00003971int
3972trio_get_largest(void *ref)
3973{
3974 return (((reference_T *)ref)->parameter->flags & FLAGS_INTMAX_T);
3975}
3976
3977void
3978trio_set_largest(void *ref,
3979 int is_largest)
3980{
3981 if (is_largest)
3982 ((reference_T *)ref)->parameter->flags |= FLAGS_INTMAX_T;
3983 else
3984 ((reference_T *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
3985}
3986#endif
3987
3988/*************************************************************************
3989 * trio_get_ptrdiff / trio_set_ptrdiff [public]
3990 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003991int
3992trio_get_ptrdiff(void *ref)
3993{
3994 return (((reference_T *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
3995}
3996
3997void
3998trio_set_ptrdiff(void *ref,
3999 int is_ptrdiff)
4000{
4001 if (is_ptrdiff)
4002 ((reference_T *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
4003 else
4004 ((reference_T *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
4005}
Bjorn Reese70a9da52001-04-21 16:57:29 +00004006
4007/*************************************************************************
4008 * trio_get_size / trio_set_size [public]
4009 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004010#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00004011int
4012trio_get_size(void *ref)
4013{
4014 return (((reference_T *)ref)->parameter->flags & FLAGS_SIZE_T);
4015}
4016
4017void
4018trio_set_size(void *ref,
4019 int is_size)
4020{
4021 if (is_size)
4022 ((reference_T *)ref)->parameter->flags |= FLAGS_SIZE_T;
4023 else
4024 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4025}
4026#endif
4027
4028/*************************************************************************
4029 * trio_print_int [public]
4030 */
4031void
4032trio_print_int(void *ref,
4033 int number)
4034{
4035 reference_T *self = (reference_T *)ref;
4036
4037 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004038 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004039 self->parameter->flags,
4040 self->parameter->width,
4041 self->parameter->precision,
4042 self->parameter->base);
4043}
4044
4045/*************************************************************************
4046 * trio_print_uint [public]
4047 */
4048void
4049trio_print_uint(void *ref,
4050 unsigned int number)
4051{
4052 reference_T *self = (reference_T *)ref;
4053
4054 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004055 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004056 self->parameter->flags | FLAGS_UNSIGNED,
4057 self->parameter->width,
4058 self->parameter->precision,
4059 self->parameter->base);
4060}
4061
4062/*************************************************************************
4063 * trio_print_double [public]
4064 */
4065void
4066trio_print_double(void *ref,
4067 double number)
4068{
4069 reference_T *self = (reference_T *)ref;
4070
4071 TrioWriteDouble(self->data,
4072 number,
4073 self->parameter->flags,
4074 self->parameter->width,
4075 self->parameter->precision,
4076 self->parameter->base);
4077}
4078
4079/*************************************************************************
4080 * trio_print_string [public]
4081 */
4082void
4083trio_print_string(void *ref,
4084 char *string)
4085{
4086 reference_T *self = (reference_T *)ref;
4087
4088 TrioWriteString(self->data,
4089 string,
4090 self->parameter->flags,
4091 self->parameter->width,
4092 self->parameter->precision);
4093}
4094
4095/*************************************************************************
4096 * trio_print_pointer [public]
4097 */
4098void
4099trio_print_pointer(void *ref,
4100 void *pointer)
4101{
4102 reference_T *self = (reference_T *)ref;
4103 unsigned long flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004104 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004105
4106 if (NULL == pointer)
4107 {
4108 const char *string = null;
4109 while (*string)
4110 self->data->OutStream(self->data, *string++);
4111 }
4112 else
4113 {
4114 /*
4115 * The subtraction of the null pointer is a workaround
4116 * to avoid a compiler warning. The performance overhead
4117 * is negligible (and likely to be removed by an
4118 * optimising compiler). The (char *) casting is done
4119 * to please ANSI C++.
4120 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004121 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004122 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004123 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004124 flags = self->parameter->flags;
4125 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4126 FLAGS_NILPADDING);
4127 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004128 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004129 flags,
4130 POINTER_WIDTH,
4131 NO_PRECISION,
4132 BASE_HEX);
4133 }
4134}
4135
4136/*************************************************************************
4137 * trio_print_ref [public]
4138 */
4139int
4140trio_print_ref(void *ref,
4141 const char *format,
4142 ...)
4143{
4144 int status;
4145 va_list arglist;
4146
4147 assert(VALID(format));
4148
4149 va_start(arglist, format);
4150 status = TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4151 va_end(arglist);
4152 return status;
4153}
4154
4155/*************************************************************************
4156 * trio_vprint_ref [public]
4157 */
4158int
4159trio_vprint_ref(void *ref,
4160 const char *format,
4161 va_list arglist)
4162{
4163 assert(VALID(format));
4164
4165 return TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4166}
4167
4168/*************************************************************************
4169 * trio_printv_ref [public]
4170 */
4171int
4172trio_printv_ref(void *ref,
4173 const char *format,
4174 void **argarray)
4175{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004176 va_list dummy;
4177
Bjorn Reese70a9da52001-04-21 16:57:29 +00004178 assert(VALID(format));
4179
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004180 return TrioFormatRef((reference_T *)ref, format, dummy, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004181}
4182
4183
4184/*************************************************************************
4185 *
4186 * @SCANNING
4187 *
4188 ************************************************************************/
4189
Daniel Veillard92ad2102001-03-27 12:47:33 +00004190
4191/*************************************************************************
4192 * TrioSkipWhitespaces [private]
4193 */
4194static int
4195TrioSkipWhitespaces(trio_T *self)
4196{
4197 int ch;
4198
4199 ch = self->current;
4200 while (isspace(ch))
4201 {
4202 self->InStream(self, &ch);
4203 }
4204 return ch;
4205}
4206
4207/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004208 * TrioGetCollation [private]
4209 */
4210#if TRIO_EXTENSION
4211static void
4212TrioGetCollation()
4213{
4214 int i;
4215 int j;
4216 int k;
4217 char first[2];
4218 char second[2];
4219
4220 /* This is computational expensive */
4221 first[1] = NIL;
4222 second[1] = NIL;
4223 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4224 {
4225 k = 0;
4226 first[0] = (char)i;
4227 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
4228 {
4229 second[0] = (char)j;
4230 if (StrEqualLocale(first, second))
4231 internalCollationArray[i][k++] = (char)j;
4232 }
4233 internalCollationArray[i][k] = NIL;
4234 }
4235}
4236#endif
4237
4238/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004239 * TrioGetCharacterClass [private]
4240 *
4241 * FIXME:
4242 * multibyte
4243 */
4244static int
4245TrioGetCharacterClass(const char *format,
4246 int *indexPointer,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004247 unsigned long *flagsPointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004248 int *characterclass)
4249{
4250 int index = *indexPointer;
4251 int i;
4252 char ch;
4253 char range_begin;
4254 char range_end;
4255
4256 *flagsPointer &= ~FLAGS_EXCLUDE;
4257
4258 if (format[index] == QUALIFIER_CIRCUMFLEX)
4259 {
4260 *flagsPointer |= FLAGS_EXCLUDE;
4261 index++;
4262 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004263 /*
4264 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004265 * it will be part of the class, and a second ungroup character
4266 * must follow to end the group.
4267 */
4268 if (format[index] == SPECIFIER_UNGROUP)
4269 {
4270 characterclass[(int)SPECIFIER_UNGROUP]++;
4271 index++;
4272 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004273 /*
4274 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004275 * it must be at the beginning of the list
4276 */
4277 if (format[index] == QUALIFIER_MINUS)
4278 {
4279 characterclass[(int)QUALIFIER_MINUS]++;
4280 index++;
4281 }
4282 /* Collect characters */
4283 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004284 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004285 ch = format[++index])
4286 {
4287 switch (ch)
4288 {
4289 case QUALIFIER_MINUS: /* Scanlist ranges */
4290
Bjorn Reese70a9da52001-04-21 16:57:29 +00004291 /*
4292 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00004293 * defined.
4294 *
4295 * We support the following behaviour (although this may
4296 * change as we become wiser)
4297 * - only increasing ranges, ie. [a-b] but not [b-a]
4298 * - transitive ranges, ie. [a-b-c] == [a-c]
4299 * - trailing minus, ie. [a-] is interpreted as an 'a'
4300 * and a '-'
4301 * - duplicates (although we can easily convert these
4302 * into errors)
4303 */
4304 range_begin = format[index - 1];
4305 range_end = format[++index];
4306 if (range_end == SPECIFIER_UNGROUP)
4307 {
4308 /* Trailing minus is included */
4309 characterclass[(int)ch]++;
4310 ch = range_end;
4311 break; /* for */
4312 }
4313 if (range_end == NIL)
4314 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4315 if (range_begin > range_end)
4316 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
4317
4318 for (i = (int)range_begin; i <= (int)range_end; i++)
4319 characterclass[i]++;
4320
4321 ch = range_end;
4322 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004323
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004324#if TRIO_EXTENSION
4325
4326 case SPECIFIER_GROUP:
4327
4328 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004329 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004330 case QUALIFIER_DOT: /* Collating symbol */
4331 /*
4332 * FIXME: This will be easier to implement when multibyte
4333 * characters have been implemented. Until now, we ignore
4334 * this feature.
4335 */
4336 for (i = index + 2; ; i++)
4337 {
4338 if (format[i] == NIL)
4339 /* Error in syntax */
4340 return -1;
4341 else if (format[i] == QUALIFIER_DOT)
4342 break; /* for */
4343 }
4344 if (format[++i] != SPECIFIER_UNGROUP)
4345 return -1;
4346
4347 index = i;
4348 break;
4349
4350 case QUALIFIER_EQUAL: /* Equivalence class expressions */
4351 {
4352 unsigned int j;
4353 unsigned int k;
4354
4355 if (internalCollationUnconverted)
4356 {
4357 /* Lazy evalutation of collation array */
4358 TrioGetCollation();
4359 internalCollationUnconverted = FALSE;
4360 }
4361 for (i = index + 2; ; i++)
4362 {
4363 if (format[i] == NIL)
4364 /* Error in syntax */
4365 return -1;
4366 else if (format[i] == QUALIFIER_EQUAL)
4367 break; /* for */
4368 else
4369 {
4370 /* Mark any equivalent character */
4371 k = (unsigned int)format[i];
4372 for (j = 0; internalCollationArray[k][j] != NIL; j++)
4373 characterclass[(int)internalCollationArray[k][j]]++;
4374 }
4375 }
4376 if (format[++i] != SPECIFIER_UNGROUP)
4377 return -1;
4378
4379 index = i;
4380 }
4381 break;
4382
4383 case QUALIFIER_COLON: /* Character class expressions */
4384
4385 if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
4386 &format[index]))
4387 {
4388 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4389 if (isalnum(i))
4390 characterclass[i]++;
4391 index += sizeof(CLASS_ALNUM) - 1;
4392 }
4393 else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
4394 &format[index]))
4395 {
4396 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4397 if (isalpha(i))
4398 characterclass[i]++;
4399 index += sizeof(CLASS_ALPHA) - 1;
4400 }
4401 else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
4402 &format[index]))
4403 {
4404 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4405 if (iscntrl(i))
4406 characterclass[i]++;
4407 index += sizeof(CLASS_CNTRL) - 1;
4408 }
4409 else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
4410 &format[index]))
4411 {
4412 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4413 if (isdigit(i))
4414 characterclass[i]++;
4415 index += sizeof(CLASS_DIGIT) - 1;
4416 }
4417 else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
4418 &format[index]))
4419 {
4420 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4421 if (isgraph(i))
4422 characterclass[i]++;
4423 index += sizeof(CLASS_GRAPH) - 1;
4424 }
4425 else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
4426 &format[index]))
4427 {
4428 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4429 if (islower(i))
4430 characterclass[i]++;
4431 index += sizeof(CLASS_LOWER) - 1;
4432 }
4433 else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
4434 &format[index]))
4435 {
4436 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4437 if (isprint(i))
4438 characterclass[i]++;
4439 index += sizeof(CLASS_PRINT) - 1;
4440 }
4441 else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
4442 &format[index]))
4443 {
4444 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4445 if (ispunct(i))
4446 characterclass[i]++;
4447 index += sizeof(CLASS_PUNCT) - 1;
4448 }
4449 else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
4450 &format[index]))
4451 {
4452 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4453 if (isspace(i))
4454 characterclass[i]++;
4455 index += sizeof(CLASS_SPACE) - 1;
4456 }
4457 else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
4458 &format[index]))
4459 {
4460 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4461 if (isupper(i))
4462 characterclass[i]++;
4463 index += sizeof(CLASS_UPPER) - 1;
4464 }
4465 else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
4466 &format[index]))
4467 {
4468 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4469 if (isxdigit(i))
4470 characterclass[i]++;
4471 index += sizeof(CLASS_XDIGIT) - 1;
4472 }
4473 else
4474 {
4475 characterclass[(int)ch]++;
4476 }
4477 break;
4478
4479 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004480 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004481 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004482 }
4483 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004484
4485#endif /* TRIO_EXTENSION */
4486
Daniel Veillard92ad2102001-03-27 12:47:33 +00004487 default:
4488 characterclass[(int)ch]++;
4489 break;
4490 }
4491 }
4492 return 0;
4493}
4494
4495/*************************************************************************
4496 * TrioReadNumber [private]
4497 *
4498 * We implement our own number conversion in preference of strtol and
4499 * strtoul, because we must handle 'long long' and thousand separators.
4500 */
4501static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004502TrioReadNumber(trio_T *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004503 trio_uintmax_t *target,
4504 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004505 int width,
4506 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004507{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004508 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004509 int digit;
4510 int count;
4511 BOOLEAN_T isNegative = FALSE;
4512 int j;
4513
4514 assert(VALID(self));
4515 assert(VALID(self->InStream));
4516 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
4517
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004518 if (internalDigitsUnconverted)
4519 {
4520 /* Lazy evaluation of digits array */
4521 memset(internalDigitArray, -1, sizeof(internalDigitArray));
4522 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
4523 {
4524 internalDigitArray[(int)internalDigitsLower[j]] = j;
4525 internalDigitArray[(int)internalDigitsUpper[j]] = j;
4526 }
4527 internalDigitsUnconverted = FALSE;
4528 }
4529
Daniel Veillard92ad2102001-03-27 12:47:33 +00004530 TrioSkipWhitespaces(self);
4531
4532 if (!(flags & FLAGS_UNSIGNED))
4533 {
4534 /* Leading sign */
4535 if (self->current == '+')
4536 {
4537 self->InStream(self, NULL);
4538 }
4539 else if (self->current == '-')
4540 {
4541 self->InStream(self, NULL);
4542 isNegative = TRUE;
4543 }
4544 }
4545
4546 count = self->processed;
4547
4548 if (flags & FLAGS_ALTERNATIVE)
4549 {
4550 switch (base)
4551 {
4552 case NO_BASE:
4553 case BASE_OCTAL:
4554 case BASE_HEX:
4555 case BASE_BINARY:
4556 if (self->current == '0')
4557 {
4558 self->InStream(self, NULL);
4559 if (self->current)
4560 {
4561 if ((base == BASE_HEX) &&
4562 (toupper(self->current) == 'X'))
4563 {
4564 self->InStream(self, NULL);
4565 }
4566 else if ((base == BASE_BINARY) &&
4567 (toupper(self->current) == 'B'))
4568 {
4569 self->InStream(self, NULL);
4570 }
4571 }
4572 }
4573 else
4574 return FALSE;
4575 break;
4576 default:
4577 break;
4578 }
4579 }
4580
4581 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
4582 (! ((self->current == EOF) || isspace(self->current))))
4583 {
4584 if (isascii(self->current))
4585 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004586 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00004587 /* Abort if digit is not allowed in the specified base */
4588 if ((digit == -1) || (digit >= base))
4589 break;
4590 }
4591 else if (flags & FLAGS_QUOTE)
4592 {
4593 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004594 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004595 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004596 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004597 break;
4598
4599 self->InStream(self, NULL);
4600 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004601 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004602 break; /* Mismatch */
4603 else
4604 continue; /* Match */
4605 }
4606 else
4607 break;
4608
4609 number *= base;
4610 number += digit;
4611
4612 self->InStream(self, NULL);
4613 }
4614
4615 /* Was anything read at all? */
4616 if (self->processed == count)
4617 return FALSE;
4618
4619 if (target)
4620 *target = (isNegative) ? -number : number;
4621 return TRUE;
4622}
4623
4624/*************************************************************************
4625 * TrioReadChar [private]
4626 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004627static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004628TrioReadChar(trio_T *self,
4629 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004630 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004631 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004632{
4633 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004634 char ch;
4635 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004636
4637 assert(VALID(self));
4638 assert(VALID(self->InStream));
4639
4640 for (i = 0;
4641 (self->current != EOF) && (i < width);
4642 i++)
4643 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004644 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004645 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004646 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
4647 {
4648 switch (self->current)
4649 {
4650 case '\\': ch = '\\'; break;
4651 case 'a': ch = '\007'; break;
4652 case 'b': ch = '\b'; break;
4653 case 'f': ch = '\f'; break;
4654 case 'n': ch = '\n'; break;
4655 case 'r': ch = '\r'; break;
4656 case 't': ch = '\t'; break;
4657 case 'v': ch = '\v'; break;
4658 default:
4659 if (isdigit(self->current))
4660 {
4661 /* Read octal number */
4662 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
4663 return 0;
4664 ch = (char)number;
4665 }
4666 else if (toupper(self->current) == 'X')
4667 {
4668 /* Read hexadecimal number */
4669 self->InStream(self, NULL);
4670 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
4671 return 0;
4672 ch = (char)number;
4673 }
4674 else
4675 {
4676 ch = (char)self->current;
4677 }
4678 break;
4679 }
4680 }
4681
4682 if (target)
4683 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004684 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004685 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004686}
4687
4688/*************************************************************************
4689 * TrioReadString [private]
4690 */
4691static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004692TrioReadString(trio_T *self,
4693 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004694 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004695 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004696{
4697 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004698
4699 assert(VALID(self));
4700 assert(VALID(self->InStream));
4701
4702 TrioSkipWhitespaces(self);
4703
Bjorn Reese70a9da52001-04-21 16:57:29 +00004704 /*
4705 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004706 * or width is exceeded
4707 */
4708 for (i = 0;
4709 ((width == NO_WIDTH) || (i < width)) &&
4710 (! ((self->current == EOF) || isspace(self->current)));
4711 i++)
4712 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004713 if (TrioReadChar(self, &target[i], flags, 1) == 0)
4714 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004715 }
4716 if (target)
4717 target[i] = NIL;
4718 return TRUE;
4719}
4720
4721/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004722 * TrioReadWideChar [private]
4723 */
4724#if TRIO_WIDECHAR
4725static int
4726TrioReadWideChar(trio_T *self,
4727 wchar_t *target,
4728 unsigned long flags,
4729 int width)
4730{
4731 int i;
4732 int j;
4733 int size;
4734 int amount = 0;
4735 wchar_t wch;
4736 char buffer[MB_LEN_MAX + 1];
4737
4738 assert(VALID(self));
4739 assert(VALID(self->InStream));
4740
4741 for (i = 0;
4742 (self->current != EOF) && (i < width);
4743 i++)
4744 {
4745 if (isascii(self->current))
4746 {
4747 if (TrioReadChar(self, buffer, flags, 1) == 0)
4748 return 0;
4749 buffer[1] = NIL;
4750 }
4751 else
4752 {
4753 /*
4754 * Collect a multibyte character, by enlarging buffer until
4755 * it contains a fully legal multibyte character, or the
4756 * buffer is full.
4757 */
4758 j = 0;
4759 do
4760 {
4761 buffer[j++] = (char)self->current;
4762 buffer[j] = NIL;
4763 self->InStream(self, NULL);
4764 }
4765 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
4766 }
4767 if (target)
4768 {
4769 size = mbtowc(&wch, buffer, sizeof(buffer));
4770 if (size > 0)
4771 target[i] = wch;
4772 }
4773 amount += size;
4774 self->InStream(self, NULL);
4775 }
4776 return amount;
4777}
4778#endif /* TRIO_WIDECHAR */
4779
4780/*************************************************************************
4781 * TrioReadWideString [private]
4782 */
4783#if TRIO_WIDECHAR
4784static BOOLEAN_T
4785TrioReadWideString(trio_T *self,
4786 wchar_t *target,
4787 unsigned long flags,
4788 int width)
4789{
4790 int i;
4791 int size;
4792
4793 assert(VALID(self));
4794 assert(VALID(self->InStream));
4795
4796 TrioSkipWhitespaces(self);
4797
4798#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
4799 mblen(NULL, 0);
4800#endif
4801
4802 /*
4803 * Continue until end of string is reached, a whitespace is encountered,
4804 * or width is exceeded
4805 */
4806 for (i = 0;
4807 ((width == NO_WIDTH) || (i < width)) &&
4808 (! ((self->current == EOF) || isspace(self->current)));
4809 )
4810 {
4811 size = TrioReadWideChar(self, &target[i], flags, 1);
4812 if (size == 0)
4813 break; /* for */
4814
4815 i += size;
4816 }
4817 if (target)
4818 target[i] = L'\0';
4819 return TRUE;
4820}
4821#endif /* TRIO_WIDECHAR */
4822
4823/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004824 * TrioReadGroup [private]
4825 *
4826 * FIXME: characterclass does not work with multibyte characters
4827 */
4828static BOOLEAN_T
4829TrioReadGroup(trio_T *self,
4830 char *target,
4831 int *characterclass,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004832 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004833 int width)
4834{
Bjorn Reese70a9da52001-04-21 16:57:29 +00004835 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004836 int i;
4837
4838 assert(VALID(self));
4839 assert(VALID(self->InStream));
4840
4841 ch = self->current;
4842 for (i = 0;
4843 ((width == NO_WIDTH) || (i < width)) &&
4844 (! ((ch == EOF) ||
4845 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
4846 i++)
4847 {
4848 if (target)
4849 target[i] = (char)ch;
4850 self->InStream(self, &ch);
4851 }
4852
4853 if (target)
4854 target[i] = NIL;
4855 return TRUE;
4856}
4857
4858/*************************************************************************
4859 * TrioReadDouble [private]
4860 *
4861 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004862 * add long double
4863 */
4864static BOOLEAN_T
4865TrioReadDouble(trio_T *self,
4866 double *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004867 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004868 int width)
4869{
4870 int ch;
4871 char doubleString[512] = "";
4872 int index = 0;
4873 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004874 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004875 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004876
Bjorn Reese70a9da52001-04-21 16:57:29 +00004877 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004878 width = sizeof(doubleString) - 1;
4879
4880 TrioSkipWhitespaces(self);
4881
Bjorn Reese70a9da52001-04-21 16:57:29 +00004882 /*
4883 * Read entire double number from stream. StrToDouble requires a
Daniel Veillard92ad2102001-03-27 12:47:33 +00004884 * string as input, but InStream can be anything, so we have to
4885 * collect all characters.
4886 */
4887 ch = self->current;
4888 if ((ch == '+') || (ch == '-'))
4889 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004890 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004891 self->InStream(self, &ch);
4892 width--;
4893 }
4894
4895 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004896 switch (ch)
4897 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00004898 case 'n':
4899 case 'N':
4900 /* Not-a-number */
4901 if (index != 0)
4902 break;
4903 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004904 case 'i':
4905 case 'I':
4906 /* Infinity */
4907 while (isalpha(ch) && (index - start < width))
4908 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004909 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004910 self->InStream(self, &ch);
4911 }
4912 doubleString[index] = NIL;
4913
Daniel Veillard92ad2102001-03-27 12:47:33 +00004914 /* Case insensitive string comparison */
4915 if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
4916 StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
4917 {
4918 *target = ((start == 1 && doubleString[0] == '-'))
4919 ? -HUGE_VAL
4920 : HUGE_VAL;
4921 return TRUE;
4922 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004923 if (StrEqual(doubleString, NAN_LOWER))
4924 {
4925 /* NaN must not have a preceeding + nor - */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004926 *target = TrioGenerateNaN();
Daniel Veillard92ad2102001-03-27 12:47:33 +00004927 return TRUE;
4928 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004929 return FALSE;
4930
4931 default:
4932 break;
4933 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004934
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004935 if (ch == '0')
4936 {
4937 doubleString[index++] = (char)ch;
4938 self->InStream(self, &ch);
4939 if (toupper(ch) == 'X')
4940 {
4941 isHex = TRUE;
4942 doubleString[index++] = (char)ch;
4943 self->InStream(self, &ch);
4944 }
4945 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004946 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004947 {
4948 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004949 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00004950 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004951 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004952 self->InStream(self, &ch);
4953 }
4954 else if (flags & FLAGS_QUOTE)
4955 {
4956 /* Compare with thousands separator */
4957 for (j = 0; internalThousandSeparator[j] && self->current; j++)
4958 {
4959 if (internalThousandSeparator[j] != self->current)
4960 break;
4961
4962 self->InStream(self, &ch);
4963 }
4964 if (internalThousandSeparator[j])
4965 break; /* Mismatch */
4966 else
4967 continue; /* Match */
4968 }
4969 else
4970 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004971 }
4972 if (ch == '.')
4973 {
4974 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004975 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004976 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004977 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4978 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004979 {
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 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004983 if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004984 {
4985 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004986 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004987 self->InStream(self, &ch);
4988 if ((ch == '+') || (ch == '-'))
4989 {
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 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004993 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4994 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004995 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004996 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004997 self->InStream(self, &ch);
4998 }
4999 }
5000 }
5001
5002 if ((index == start) || (*doubleString == NIL))
5003 return FALSE;
5004
5005 if (flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005006/* *longdoublePointer = StrToLongDouble()*/
5007 return FALSE; /* FIXME: Remove when long double is implemented */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005008 else
5009 {
5010 *target = StrToDouble(doubleString, NULL);
5011 }
5012 return TRUE;
5013}
5014
5015/*************************************************************************
5016 * TrioReadPointer [private]
5017 */
5018static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00005019TrioReadPointer(trio_T *self,
5020 void **target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005021 unsigned long flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005022{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005023 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005024 char buffer[sizeof(null)];
5025
5026 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5027
5028 if (TrioReadNumber(self,
5029 &number,
5030 flags,
5031 POINTER_WIDTH,
5032 BASE_HEX))
5033 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00005034 /*
5035 * The strange assignment of number is a workaround for a compiler
5036 * warning
5037 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005038 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005039 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005040 return TRUE;
5041 }
5042 else if (TrioReadString(self,
5043 (flags & FLAGS_IGNORE)
5044 ? NULL
5045 : buffer,
5046 0,
5047 sizeof(null) - 1))
5048 {
5049 if (StrEqualCase(buffer, null))
5050 {
5051 if (target)
5052 *target = NULL;
5053 return TRUE;
5054 }
5055 }
5056 return FALSE;
5057}
5058
5059/*************************************************************************
5060 * TrioScan [private]
5061 */
5062static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005063TrioScan(const void *source,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005064 size_t sourceSize,
5065 void (*InStream)(trio_T *, int *),
5066 const char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00005067 va_list arglist,
5068 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005069{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005070#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005071 int charlen;
5072#endif
5073 int status;
5074 int assignment;
5075 parameter_T parameters[MAX_PARAMETERS];
5076 trio_T internalData;
5077 trio_T *data;
5078 int ch;
5079 int cnt;
5080 int index; /* Index of format string */
5081 int i; /* Index of current parameter */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005082 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005083 int width;
5084 int base;
5085 void *pointer;
5086
5087 assert(VALID(InStream));
5088 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00005089
5090 memset(&internalData, 0, sizeof(internalData));
5091 data = &internalData;
5092 data->InStream = InStream;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005093 data->location = (void *)source;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005094 data->max = sourceSize;
5095
5096#if defined(USE_LOCALE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005097 if (NULL == internalLocaleValues)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005098 {
5099 TrioSetLocale();
5100 }
5101#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00005102
Bjorn Reese70a9da52001-04-21 16:57:29 +00005103 status = TrioPreprocess(TYPE_SCAN, format, parameters, arglist, argarray);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005104 if (status < 0)
5105 return status;
5106
5107 assignment = 0;
5108 i = 0;
5109 index = 0;
5110 data->InStream(data, &ch);
5111
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005112#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005113 mblen(NULL, 0);
5114#endif
5115
5116 while (format[index])
5117 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005118#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005119 if (! isascii(format[index]))
5120 {
5121 charlen = mblen(&format[index], MB_LEN_MAX);
5122 /* Compare multibyte characters in format string */
5123 for (cnt = 0; cnt < charlen - 1; cnt++)
5124 {
5125 if (ch != format[index + cnt])
5126 {
5127 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5128 }
5129 data->InStream(data, &ch);
5130 }
5131 continue; /* while */
5132 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005133#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005134 if (EOF == ch)
5135 return EOF;
5136
5137 if (CHAR_IDENTIFIER == format[index])
5138 {
5139 if (CHAR_IDENTIFIER == format[index + 1])
5140 {
5141 /* Two % in format matches one % in input stream */
5142 if (CHAR_IDENTIFIER == ch)
5143 {
5144 data->InStream(data, &ch);
5145 index += 2;
5146 continue; /* while format chars left */
5147 }
5148 else
5149 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5150 }
5151
5152 /* Skip the parameter entries */
5153 while (parameters[i].type == FORMAT_PARAMETER)
5154 i++;
5155
5156 flags = parameters[i].flags;
5157 /* Find width */
5158 width = parameters[i].width;
5159 if (flags & FLAGS_WIDTH_PARAMETER)
5160 {
5161 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005162 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005163 }
5164 /* Find base */
5165 base = parameters[i].base;
5166 if (flags & FLAGS_BASE_PARAMETER)
5167 {
5168 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005169 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005170 }
5171
5172 switch (parameters[i].type)
5173 {
5174 case FORMAT_INT:
5175 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005176 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005177
5178 if (0 == base)
5179 base = BASE_DECIMAL;
5180
5181 if (!TrioReadNumber(data,
5182 &number,
5183 flags,
5184 width,
5185 base))
5186 return assignment;
5187 assignment++;
5188
5189 if (!(flags & FLAGS_IGNORE))
5190 {
5191 pointer = parameters[i].data.pointer;
5192#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5193 if (flags & FLAGS_SIZE_T)
5194 *(size_t *)pointer = (size_t)number;
5195 else
5196#endif
5197#if defined(QUALIFIER_PTRDIFF_T)
5198 if (flags & FLAGS_PTRDIFF_T)
5199 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
5200 else
5201#endif
5202#if defined(QUALIFIER_INTMAX_T)
5203 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005204 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005205 else
5206#endif
5207 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005208 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005209 else if (flags & FLAGS_LONG)
5210 *(long int *)pointer = (long int)number;
5211 else if (flags & FLAGS_SHORT)
5212 *(short int *)pointer = (short int)number;
5213 else
5214 *(int *)pointer = (int)number;
5215 }
5216 }
5217 break; /* FORMAT_INT */
5218
5219 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005220#if TRIO_WIDECHAR
5221 if (flags & FLAGS_WIDECHAR)
5222 {
5223 if (!TrioReadWideString(data,
5224 (flags & FLAGS_IGNORE)
5225 ? NULL
5226 : parameters[i].data.wstring,
5227 flags,
5228 width))
5229 return assignment;
5230 }
5231 else
5232#endif
5233 {
5234 if (!TrioReadString(data,
5235 (flags & FLAGS_IGNORE)
5236 ? NULL
5237 : parameters[i].data.string,
5238 flags,
5239 width))
5240 return assignment;
5241 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005242 assignment++;
5243 break; /* FORMAT_STRING */
5244
5245 case FORMAT_DOUBLE:
5246 if (!TrioReadDouble(data,
5247 (flags & FLAGS_IGNORE)
5248 ? NULL
5249 : parameters[i].data.doublePointer,
5250 flags,
5251 width))
5252 return assignment;
5253 assignment++;
5254 break; /* FORMAT_DOUBLE */
5255
5256 case FORMAT_GROUP:
5257 {
5258 int characterclass[MAX_CHARACTER_CLASS + 1];
5259 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005260
5261 /* Skip over modifiers */
5262 while (format[index] != SPECIFIER_GROUP)
5263 {
5264 index++;
5265 }
5266 /* Skip over group specifier */
5267 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005268
Daniel Veillard92ad2102001-03-27 12:47:33 +00005269 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005270 rc = TrioGetCharacterClass(format,
5271 &index,
5272 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005273 characterclass);
5274 if (rc < 0)
5275 return rc;
5276
5277 if (!TrioReadGroup(data,
5278 (flags & FLAGS_IGNORE)
5279 ? NULL
5280 : parameters[i].data.string,
5281 characterclass,
5282 flags,
5283 parameters[i].width))
5284 return assignment;
5285 assignment++;
5286 }
5287 break; /* FORMAT_GROUP */
5288
5289 case FORMAT_COUNT:
5290 pointer = parameters[i].data.pointer;
5291 if (NULL != pointer)
5292 {
5293#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5294 if (flags & FLAGS_SIZE_T)
5295 *(size_t *)pointer = (size_t)data->committed;
5296 else
5297#endif
5298#if defined(QUALIFIER_PTRDIFF_T)
5299 if (flags & FLAGS_PTRDIFF_T)
5300 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
5301 else
5302#endif
5303#if defined(QUALIFIER_INTMAX_T)
5304 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005305 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005306 else
5307#endif
5308 if (flags & FLAGS_QUAD)
5309 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005310 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005311 }
5312 else if (flags & FLAGS_LONG)
5313 {
5314 *(long int *)pointer = (long int)data->committed;
5315 }
5316 else if (flags & FLAGS_SHORT)
5317 {
5318 *(short int *)pointer = (short int)data->committed;
5319 }
5320 else
5321 {
5322 *(int *)pointer = (int)data->committed;
5323 }
5324 }
5325 break; /* FORMAT_COUNT */
5326
5327 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005328#if TRIO_WIDECHAR
5329 if (flags & FLAGS_WIDECHAR)
5330 {
5331 if (TrioReadWideChar(data,
5332 (flags & FLAGS_IGNORE)
5333 ? NULL
5334 : parameters[i].data.wstring,
5335 flags,
5336 (width == NO_WIDTH) ? 1 : width) > 0)
5337 return assignment;
5338 }
5339 else
5340#endif
5341 {
5342 if (TrioReadChar(data,
5343 (flags & FLAGS_IGNORE)
5344 ? NULL
5345 : parameters[i].data.string,
5346 flags,
5347 (width == NO_WIDTH) ? 1 : width) > 0)
5348 return assignment;
5349 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005350 assignment++;
5351 break; /* FORMAT_CHAR */
5352
5353 case FORMAT_POINTER:
5354 if (!TrioReadPointer(data,
5355 (flags & FLAGS_IGNORE)
5356 ? NULL
Bjorn Reese70a9da52001-04-21 16:57:29 +00005357 : (void **)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005358 flags))
5359 return assignment;
5360 assignment++;
5361 break; /* FORMAT_POINTER */
5362
5363 case FORMAT_PARAMETER:
5364 break; /* FORMAT_PARAMETER */
5365
5366 default:
5367 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5368 }
5369 ch = data->current;
5370 index = parameters[i].indexAfterSpecifier;
5371 i++;
5372 }
5373 else /* Not an % identifier */
5374 {
5375 if (isspace((int)format[index]))
5376 {
5377 /* Whitespaces may match any amount of whitespaces */
5378 ch = TrioSkipWhitespaces(data);
5379 }
5380 else if (ch == format[index])
5381 {
5382 data->InStream(data, &ch);
5383 }
5384 else
5385 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5386
5387 index++;
5388 }
5389 }
5390 return assignment;
5391}
5392
5393/*************************************************************************
5394 * TrioInStreamFile [private]
5395 */
5396static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005397TrioInStreamFile(trio_T *self,
5398 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005399{
5400 FILE *file = (FILE *)self->location;
5401
5402 assert(VALID(self));
5403 assert(VALID(file));
5404
5405 self->current = fgetc(file);
5406 self->processed++;
5407 self->committed++;
5408
5409 if (VALID(intPointer))
5410 {
5411 *intPointer = self->current;
5412 }
5413}
5414
5415/*************************************************************************
5416 * TrioInStreamFileDescriptor [private]
5417 */
5418static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005419TrioInStreamFileDescriptor(trio_T *self,
5420 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005421{
5422 int fd = *((int *)self->location);
5423 int size;
5424 unsigned char input;
5425
5426 assert(VALID(self));
5427
5428 size = read(fd, &input, sizeof(char));
5429 self->current = (size == 0) ? EOF : input;
5430 self->processed++;
5431 self->committed++;
5432
5433 if (VALID(intPointer))
5434 {
5435 *intPointer = self->current;
5436 }
5437}
5438
5439/*************************************************************************
5440 * TrioInStreamString [private]
5441 */
5442static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005443TrioInStreamString(trio_T *self,
5444 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005445{
5446 unsigned char **buffer;
5447
5448 assert(VALID(self));
5449 assert(VALID(self->InStream));
5450 assert(VALID(self->location));
5451
5452 buffer = (unsigned char **)self->location;
5453 self->current = (*buffer)[0];
5454 if (self->current == NIL)
5455 self->current = EOF;
5456 (*buffer)++;
5457 self->processed++;
5458 self->committed++;
5459
5460 if (VALID(intPointer))
5461 {
5462 *intPointer = self->current;
5463 }
5464}
5465
5466/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00005467 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00005468 */
5469int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005470trio_scanf(const char *format,
5471 ...)
5472{
5473 int status;
5474 va_list args;
5475
5476 assert(VALID(format));
5477
5478 va_start(args, format);
5479 status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5480 va_end(args);
5481 return status;
5482}
5483
5484int
5485trio_vscanf(const char *format,
5486 va_list args)
5487{
5488 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005489
5490 return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5491}
5492
5493int
5494trio_scanfv(const char *format,
5495 void **args)
5496{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005497 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005498
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005499 assert(VALID(format));
5500
5501 return TrioScan(stdin, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005502}
5503
5504/*************************************************************************
5505 * fscanf
5506 */
5507int
5508trio_fscanf(FILE *file,
5509 const char *format,
5510 ...)
5511{
5512 int status;
5513 va_list args;
5514
5515 assert(VALID(file));
5516 assert(VALID(format));
5517
5518 va_start(args, format);
5519 status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5520 va_end(args);
5521 return status;
5522}
5523
5524int
5525trio_vfscanf(FILE *file,
5526 const char *format,
5527 va_list args)
5528{
5529 assert(VALID(file));
5530 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005531
5532 return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5533}
5534
5535int
5536trio_fscanfv(FILE *file,
5537 const char *format,
5538 void **args)
5539{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005540 va_list dummy;
5541
Bjorn Reese70a9da52001-04-21 16:57:29 +00005542 assert(VALID(file));
5543 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005544
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005545 return TrioScan(file, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005546}
5547
5548/*************************************************************************
5549 * dscanf
5550 */
5551int
5552trio_dscanf(int fd,
5553 const char *format,
5554 ...)
5555{
5556 int status;
5557 va_list args;
5558
5559 assert(VALID(format));
5560
5561 va_start(args, format);
5562 status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5563 va_end(args);
5564 return status;
5565}
5566
5567int
5568trio_vdscanf(int fd,
5569 const char *format,
5570 va_list args)
5571{
5572 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005573
5574 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5575}
5576
5577int
5578trio_dscanfv(int fd,
5579 const char *format,
5580 void **args)
5581{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005582 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005583
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005584 assert(VALID(format));
5585
5586 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005587}
5588
5589/*************************************************************************
5590 * sscanf
5591 */
5592int
5593trio_sscanf(const char *buffer,
5594 const char *format,
5595 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005596{
5597 int status;
5598 va_list args;
5599
5600 assert(VALID(buffer));
5601 assert(VALID(format));
5602
5603 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005604 status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005605 va_end(args);
5606 return status;
5607}
5608
Bjorn Reese70a9da52001-04-21 16:57:29 +00005609int
5610trio_vsscanf(const char *buffer,
5611 const char *format,
5612 va_list args)
5613{
5614 assert(VALID(buffer));
5615 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005616
5617 return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
5618}
5619
5620int
5621trio_sscanfv(const char *buffer,
5622 const char *format,
5623 void **args)
5624{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005625 va_list dummy;
5626
Bjorn Reese70a9da52001-04-21 16:57:29 +00005627 assert(VALID(buffer));
5628 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005629
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005630 return TrioScan(&buffer, 0, TrioInStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005631}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005632