blob: 1d6ea6a4778540cc2d163a6005bbc9068d34f858 [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 */
Bjorn Reese45029602001-08-21 09:23:53 +000049#include "triodef.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000050#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000051#include "triop.h"
Bjorn Reese45029602001-08-21 09:23:53 +000052#include "trionan.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000053#include "strio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000054
Bjorn Reese70a9da52001-04-21 16:57:29 +000055/*
56 * Encode the error code and the position. This is decoded
Daniel Veillard92ad2102001-03-27 12:47:33 +000057 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
58 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +000059#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +000060# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
61#else
62# define TRIO_ERROR_RETURN(x,y) (-1)
63#endif
64
Bjorn Reese906ec8a2001-06-05 12:46:33 +000065#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
66# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
67# if !defined(MB_LEN_MAX)
68# define MB_LEN_MAX 6
69# endif
70#endif
71
72
73/*************************************************************************
74 * Generic definitions
75 */
76
77#if !(defined(DEBUG) || defined(NDEBUG))
78# define NDEBUG
79#endif
80#include <assert.h>
81#include <ctype.h>
82#if !defined(TRIO_COMPILER_SUPPORTS_C99)
83# define isblank(x) (((x)==32) || ((x)==9))
84#endif
85#include <math.h>
86#include <limits.h>
87#include <float.h>
88#include <stdarg.h>
89#include <stddef.h>
90#include <errno.h>
91
92#ifndef NULL
93# define NULL 0
94#endif
95#define NIL ((char)0)
96#ifndef FALSE
97# define FALSE (1 == 0)
98# define TRUE (! FALSE)
99#endif
100#define BOOLEAN_T int
101
102/* mincore() can be used for debugging purposes */
103#define VALID(x) (NULL != (x))
104
105/* xlC crashes on log10(0) */
Bjorn Reese45029602001-08-21 09:23:53 +0000106#define guarded_log10(x) (((x) == 0.0) ? trio_ninf() : log10(x))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000107#define guarded_log16(x) (guarded_log10(x) / log10(16.0))
108
109
110/*************************************************************************
111 * Platform specific definitions
112 */
113#if defined(PLATFORM_UNIX)
114# include <unistd.h>
115# include <signal.h>
116# include <locale.h>
117# define USE_LOCALE
118#endif /* PLATFORM_UNIX */
119#if defined(PLATFORM_WIN32)
120# include <io.h>
121# define read _read
122# define write _write
123#endif /* PLATFORM_WIN32 */
124
Bjorn Reese45029602001-08-21 09:23:53 +0000125#define TRIO_MSVC_VERSION_5 1100
126
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000127#if TRIO_WIDECHAR
128# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
129# include <wchar.h>
130# include <wctype.h>
131# else
132typedef char wchar_t;
133typedef int wint_t;
134# define WEOF EOF
135# define iswalnum(x) isalnum(x)
136# define iswalpha(x) isalpha(x)
137# define iswblank(x) isblank(x)
138# define iswcntrl(x) iscntrl(x)
139# define iswdigit(x) isdigit(x)
140# define iswgraph(x) isgraph(x)
141# define iswlower(x) islower(x)
142# define iswprint(x) isprint(x)
143# define iswpunct(x) ispunct(x)
144# define iswspace(x) isspace(x)
145# define iswupper(x) isupper(x)
146# define iswxdigit(x) isxdigit(x)
147# endif
148#endif
149
150
151/*************************************************************************
152 * Compiler dependent definitions
153 */
154
155/* Support for long long */
156#ifndef __cplusplus
157# if !defined(USE_LONGLONG)
158# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
159# define USE_LONGLONG
160# elif defined(__SUNPRO_C)
161# define USE_LONGLONG
162# elif defined(_LONG_LONG) || defined(_LONGLONG)
163# define USE_LONGLONG
164# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000165# endif
166#endif
167
168/* The extra long numbers */
169#if defined(USE_LONGLONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000170typedef signed long long int trio_longlong_t;
171typedef unsigned long long int trio_ulonglong_t;
172#elif defined(_MSC_VER)
Bjorn Reese45029602001-08-21 09:23:53 +0000173# if (_MSC_VER >= TRIO_MSVC_VERSION_5)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000174typedef signed __int64 trio_longlong_t;
175typedef unsigned __int64 trio_ulonglong_t;
176# else
177typedef signed long int trio_longlong_t;
178typedef unsigned long int trio_ulonglong_t;
179# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000180#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000181typedef signed long int trio_longlong_t;
182typedef unsigned long int trio_ulonglong_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000183#endif
184
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000185/* Maximal and fixed integer types */
186#if defined(TRIO_COMPILER_SUPPORTS_C99)
187# include <stdint.h>
188typedef intmax_t trio_intmax_t;
189typedef uintmax_t trio_uintmax_t;
190typedef int8_t trio_int8_t;
191typedef int16_t trio_int16_t;
192typedef int32_t trio_int32_t;
193typedef int64_t trio_int64_t;
194#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
195# include <inttypes.h>
196typedef intmax_t trio_intmax_t;
197typedef uintmax_t trio_uintmax_t;
198typedef int8_t trio_int8_t;
199typedef int16_t trio_int16_t;
200typedef int32_t trio_int32_t;
201typedef int64_t trio_int64_t;
202#elif defined(_MSC_VER) && (_MSC_VER >= TRIO_MSVC_5)
203typedef trio_longlong_t trio_intmax_t;
204typedef trio_ulonglong_t trio_uintmax_t;
205typedef __int8 trio_int8_t;
206typedef __int16 trio_int16_t;
207typedef __int32 trio_int32_t;
208typedef __int64 trio_int64_t;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000209#else
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000210typedef trio_longlong_t trio_intmax_t;
211typedef trio_ulonglong_t trio_uintmax_t;
212# if defined(TRIO_INT8_T)
213typedef TRIO_INT8_T trio_int8_t;
214# else
215typedef signed char trio_int8_t;
216# endif
217# if defined(TRIO_INT16_T)
218typedef TRIO_INT16_T trio_int16_t;
219# else
220typedef signed short trio_int16_t;
221# endif
222# if defined(TRIO_INT32_T)
223typedef TRIO_INT32_T trio_int32_t;
224# else
225typedef signed int trio_int32_t;
226# endif
227# if defined(TRIO_INT64_T)
228typedef TRIO_INT64_T trio_int64_t;
229# else
230typedef trio_longlong_t trio_int64_t;
231# endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000232#endif
233
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000234
235/*************************************************************************
236 * Internal definitions
237 */
238
239/* Long double sizes */
240#ifdef LDBL_DIG
241# define MAX_MANTISSA_DIGITS LDBL_DIG
242# define MAX_EXPONENT_DIGITS 4
243#else
244# define MAX_MANTISSA_DIGITS DBL_DIG
245# define MAX_EXPONENT_DIGITS 3
246#endif
247
248/* The maximal number of digits is for base 2 */
249#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000250/* The width of a pointer. The number of bits in a hex digit is 4 */
251#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
252
253/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000254#define INFINITE_LOWER "inf"
255#define INFINITE_UPPER "INF"
256#define LONG_INFINITE_LOWER "infinite"
257#define LONG_INFINITE_UPPER "INFINITE"
258#define NAN_LOWER "nan"
259#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000260
261/* Various constants */
262enum {
263 TYPE_PRINT = 1,
264 TYPE_SCAN = 2,
265
266 /* Flags. Use maximum 32 */
267 FLAGS_NEW = 0,
268 FLAGS_STICKY = 1,
269 FLAGS_SPACE = 2 * FLAGS_STICKY,
270 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
271 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
272 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
273 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
274 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
275 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
276 FLAGS_QUAD = 2 * FLAGS_LONG,
277 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
278 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
279 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
280 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
281 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
282 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
283 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
284 FLAGS_WIDTH = 2 * FLAGS_UPPER,
285 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
286 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
287 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
288 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
289 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
290 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
291 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
292 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
293 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
294 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
295 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
296 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000297 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
298 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000299 /* Reused flags */
300 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000301 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000302 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000303 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000304 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000305
306 NO_POSITION = -1,
307 NO_WIDTH = 0,
308 NO_PRECISION = -1,
309 NO_SIZE = -1,
310
311 NO_BASE = -1,
312 MIN_BASE = 2,
313 MAX_BASE = 36,
314 BASE_BINARY = 2,
315 BASE_OCTAL = 8,
316 BASE_DECIMAL = 10,
317 BASE_HEX = 16,
318
319 /* Maximal number of allowed parameters */
320 MAX_PARAMETERS = 64,
321 /* Maximal number of characters in class */
322 MAX_CHARACTER_CLASS = UCHAR_MAX,
323
Bjorn Reese70a9da52001-04-21 16:57:29 +0000324 /* Maximal string lengths for user-defined specifiers */
325 MAX_USER_NAME = 64,
326 MAX_USER_DATA = 256,
327
Daniel Veillard92ad2102001-03-27 12:47:33 +0000328 /* Maximal length of locale separator strings */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000329 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000330 /* Maximal number of integers in grouping */
Daniel Veillard5792e162001-04-30 17:44:45 +0000331 MAX_LOCALE_GROUPS = 64
Daniel Veillard92ad2102001-03-27 12:47:33 +0000332};
333
334#define NO_GROUPING ((int)CHAR_MAX)
335
336/* Fundamental formatting parameter types */
337#define FORMAT_UNKNOWN 0
338#define FORMAT_INT 1
339#define FORMAT_DOUBLE 2
340#define FORMAT_CHAR 3
341#define FORMAT_STRING 4
342#define FORMAT_POINTER 5
343#define FORMAT_COUNT 6
344#define FORMAT_PARAMETER 7
345#define FORMAT_GROUP 8
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000346#if TRIO_GNU
Bjorn Reese70a9da52001-04-21 16:57:29 +0000347# define FORMAT_ERRNO 9
348#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000349#if TRIO_EXTENSION
Bjorn Reese70a9da52001-04-21 16:57:29 +0000350# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000351#endif
352
353/* Character constants */
354#define CHAR_IDENTIFIER '%'
355#define CHAR_BACKSLASH '\\'
356#define CHAR_QUOTE '\"'
357#define CHAR_ADJUST ' '
358
359/* Character class expressions */
360#define CLASS_ALNUM ":alnum:"
361#define CLASS_ALPHA ":alpha:"
362#define CLASS_CNTRL ":cntrl:"
363#define CLASS_DIGIT ":digit:"
364#define CLASS_GRAPH ":graph:"
365#define CLASS_LOWER ":lower:"
366#define CLASS_PRINT ":print:"
367#define CLASS_PUNCT ":punct:"
368#define CLASS_SPACE ":space:"
369#define CLASS_UPPER ":upper:"
370#define CLASS_XDIGIT ":xdigit:"
371
372/*
373 * SPECIFIERS:
374 *
375 *
376 * a Hex-float
377 * A Hex-float
378 * c Character
379 * C Widechar character (wint_t)
380 * d Decimal
381 * e Float
382 * E Float
383 * F Float
384 * F Float
385 * g Float
386 * G Float
387 * i Integer
388 * m Error message
389 * n Count
390 * o Octal
391 * p Pointer
392 * s String
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000393 * S Widechar string (wchar_t *)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000394 * u Unsigned
395 * x Hex
396 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000397 * [] Group
398 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000399 *
400 * Reserved:
401 *
402 * D Binary Coded Decimal %D(length,precision) (OS/390)
403 */
404#define SPECIFIER_CHAR 'c'
405#define SPECIFIER_STRING 's'
406#define SPECIFIER_DECIMAL 'd'
407#define SPECIFIER_INTEGER 'i'
408#define SPECIFIER_UNSIGNED 'u'
409#define SPECIFIER_OCTAL 'o'
410#define SPECIFIER_HEX 'x'
411#define SPECIFIER_HEX_UPPER 'X'
412#define SPECIFIER_FLOAT_E 'e'
413#define SPECIFIER_FLOAT_E_UPPER 'E'
414#define SPECIFIER_FLOAT_F 'f'
415#define SPECIFIER_FLOAT_F_UPPER 'F'
416#define SPECIFIER_FLOAT_G 'g'
417#define SPECIFIER_FLOAT_G_UPPER 'G'
418#define SPECIFIER_POINTER 'p'
419#define SPECIFIER_GROUP '['
420#define SPECIFIER_UNGROUP ']'
421#define SPECIFIER_COUNT 'n'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000422#if TRIO_UNIX98
Daniel Veillard92ad2102001-03-27 12:47:33 +0000423# define SPECIFIER_CHAR_UPPER 'C'
424# define SPECIFIER_STRING_UPPER 'S'
425#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000426#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000427# define SPECIFIER_HEXFLOAT 'a'
428# define SPECIFIER_HEXFLOAT_UPPER 'A'
429#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000430#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000431# define SPECIFIER_ERRNO 'm'
432#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000433#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000434# define SPECIFIER_BINARY 'b'
435# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000436# define SPECIFIER_USER_DEFINED_BEGIN '<'
437# define SPECIFIER_USER_DEFINED_END '>'
438# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000439#endif
440
441/*
442 * QUALIFIERS:
443 *
444 *
445 * Numbers = d,i,o,u,x,X
446 * Float = a,A,e,E,f,F,g,G
447 * String = s
448 * Char = c
449 *
450 *
451 * 9$ Position
452 * Use the 9th parameter. 9 can be any number between 1 and
453 * the maximal argument
454 *
455 * 9 Width
456 * Set width to 9. 9 can be any number, but must not be postfixed
457 * by '$'
458 *
459 * h Short
460 * Numbers:
461 * (unsigned) short int
462 *
463 * hh Short short
464 * Numbers:
465 * (unsigned) char
466 *
467 * l Long
468 * Numbers:
469 * (unsigned) long int
470 * String:
471 * as the S specifier
472 * Char:
473 * as the C specifier
474 *
475 * ll Long Long
476 * Numbers:
477 * (unsigned) long long int
478 *
479 * L Long Double
480 * Float
481 * long double
482 *
483 * # Alternative
484 * Float:
485 * Decimal-point is always present
486 * String:
487 * non-printable characters are handled as \number
488 *
489 * Spacing
490 *
491 * + Sign
492 *
493 * - Alignment
494 *
495 * . Precision
496 *
497 * * Parameter
498 * print: use parameter
499 * scan: no parameter (ignore)
500 *
501 * q Quad
502 *
503 * Z size_t
504 *
505 * w Widechar
506 *
507 * ' Thousands/quote
508 * Numbers:
509 * Integer part grouped in thousands
510 * Binary numbers:
511 * Number grouped in nibbles (4 bits)
512 * String:
513 * Quoted string
514 *
515 * j intmax_t
516 * t prtdiff_t
517 * z size_t
518 *
519 * ! Sticky
520 * @ Parameter (for both print and scan)
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000521 *
522 * I n-bit Integer
523 * Numbers:
524 * The following options exists
525 * I8 = 8-bit integer
526 * I16 = 16-bit integer
527 * I32 = 32-bit integer
528 * I64 = 64-bit integer
Daniel Veillard92ad2102001-03-27 12:47:33 +0000529 */
530#define QUALIFIER_POSITION '$'
531#define QUALIFIER_SHORT 'h'
532#define QUALIFIER_LONG 'l'
533#define QUALIFIER_LONG_UPPER 'L'
534#define QUALIFIER_ALTERNATIVE '#'
535#define QUALIFIER_SPACE ' '
536#define QUALIFIER_PLUS '+'
537#define QUALIFIER_MINUS '-'
538#define QUALIFIER_DOT '.'
539#define QUALIFIER_STAR '*'
540#define QUALIFIER_CIRCUMFLEX '^'
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000541#if TRIO_C99
Daniel Veillard92ad2102001-03-27 12:47:33 +0000542# define QUALIFIER_SIZE_T 'z'
543# define QUALIFIER_PTRDIFF_T 't'
544# define QUALIFIER_INTMAX_T 'j'
545#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000546#if TRIO_BSD || TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000547# define QUALIFIER_QUAD 'q'
548#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000549#if TRIO_GNU
Daniel Veillard92ad2102001-03-27 12:47:33 +0000550# define QUALIFIER_SIZE_T_UPPER 'Z'
551#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000552#if TRIO_MISC
Daniel Veillard92ad2102001-03-27 12:47:33 +0000553# define QUALIFIER_WIDECHAR 'w'
554#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000555#if TRIO_MICROSOFT
556# define QUALIFIER_FIXED_SIZE 'I'
557#endif
558#if TRIO_EXTENSION
Daniel Veillard92ad2102001-03-27 12:47:33 +0000559# define QUALIFIER_QUOTE '\''
560# define QUALIFIER_STICKY '!'
561# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
562# define QUALIFIER_PARAM '@' /* Experimental */
563# define QUALIFIER_COLON ':' /* For scanlists */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000564# define QUALIFIER_EQUAL '=' /* For scanlists */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000565#endif
566
Bjorn Reese70a9da52001-04-21 16:57:29 +0000567
568/*************************************************************************
569 * Internal structures
570 */
571
572/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000573typedef struct {
574 int type;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000575 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000576 int width;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000577 int precision;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000578 int base;
579 int varsize;
580 int indexAfterSpecifier;
581 union {
582 char *string;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000583#if TRIO_WIDECHAR
584 wchar_t *wstring;
585#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000586 void *pointer;
587 union {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000588 trio_uintmax_t as_signed;
589 trio_intmax_t as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000590 } number;
591 double doubleNumber;
592 double *doublePointer;
593 long double longdoubleNumber;
594 long double *longdoublePointer;
595 int errorNumber;
596 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000597 /* For the user-defined specifier */
598 char user_name[MAX_USER_NAME];
599 char user_data[MAX_USER_DATA];
Daniel Veillard92ad2102001-03-27 12:47:33 +0000600} parameter_T;
601
Bjorn Reese70a9da52001-04-21 16:57:29 +0000602/* General trio "class" */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000603typedef struct _trio_T {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000604 void *location;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000605 void (*OutStream)(struct _trio_T *, int);
606 void (*InStream)(struct _trio_T *, int *);
Bjorn Reese70a9da52001-04-21 16:57:29 +0000607 /*
608 * The number of characters that would have been written/read if
Daniel Veillard92ad2102001-03-27 12:47:33 +0000609 * there had been sufficient space.
610 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000611 int processed;
612 /*
613 * The number of characters that are actually written/read.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000614 * Processed and committed with only differ for the *nprintf
615 * and *nscanf functions.
616 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000617 int committed;
618 int max;
619 int current;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000620} trio_T;
621
Bjorn Reese70a9da52001-04-21 16:57:29 +0000622/* References (for user-defined callbacks) */
623typedef struct _reference_T {
624 trio_T *data;
625 parameter_T *parameter;
626} reference_T;
627
628/* Registered entries (for user-defined callbacks) */
629typedef struct _userdef_T {
630 struct _userdef_T *next;
631 trio_callback_t callback;
632 char *name;
633} userdef_T;
634
Daniel Veillard92ad2102001-03-27 12:47:33 +0000635
636/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000637 * Internal variables
Daniel Veillard92ad2102001-03-27 12:47:33 +0000638 */
639
640#if defined(PLATFORM_UNIX)
641extern int errno;
642#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000643static const char null[] = "(nil)";
644
Bjorn Reese70a9da52001-04-21 16:57:29 +0000645#if defined(USE_LOCALE)
646static struct lconv *internalLocaleValues = NULL;
647#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000648
Bjorn Reese70a9da52001-04-21 16:57:29 +0000649/*
650 * UNIX98 says "in a locale where the radix character is not defined,
651 * the radix character defaults to a period (.)"
652 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000653static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
654static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000655static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
656
657static const char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
658static const char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Bjorn Reese70a9da52001-04-21 16:57:29 +0000659static BOOLEAN_T internalDigitsUnconverted = TRUE;
660static int internalDigitArray[128];
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000661#if TRIO_EXTENSION
662static BOOLEAN_T internalCollationUnconverted = TRUE;
663static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
664#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000665
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000666static volatile trio_callback_t internalEnterCriticalRegion = NULL;
667static volatile trio_callback_t internalLeaveCriticalRegion = NULL;
668static userdef_T *internalUserDef = NULL;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000669
670
671/*************************************************************************
672 * trio_strerror [public]
673 */
674const char *trio_strerror(int errorcode)
675{
676 /* Textual versions of the error codes */
677 switch (TRIO_ERROR_CODE(errorcode))
678 {
679 case TRIO_EOF:
680 return "End of file";
681 case TRIO_EINVAL:
682 return "Invalid argument";
683 case TRIO_ETOOMANY:
684 return "Too many arguments";
685 case TRIO_EDBLREF:
686 return "Double reference";
687 case TRIO_EGAP:
688 return "Reference gap";
689 case TRIO_ENOMEM:
690 return "Out of memory";
691 case TRIO_ERANGE:
692 return "Invalid range";
693 default:
694 return "Unknown";
695 }
696}
Daniel Veillard92ad2102001-03-27 12:47:33 +0000697
698/*************************************************************************
699 * TrioIsQualifier [private]
700 *
701 * Description:
702 * Remember to add all new qualifiers to this function.
703 * QUALIFIER_POSITION must not be added.
704 */
705static BOOLEAN_T
706TrioIsQualifier(const char ch)
707{
708 /* QUALIFIER_POSITION is not included */
709 switch (ch)
710 {
711 case '0': case '1': case '2': case '3': case '4':
712 case '5': case '6': case '7': case '8': case '9':
713 case QUALIFIER_PLUS:
714 case QUALIFIER_MINUS:
715 case QUALIFIER_SPACE:
716 case QUALIFIER_DOT:
717 case QUALIFIER_STAR:
718 case QUALIFIER_ALTERNATIVE:
719 case QUALIFIER_SHORT:
720 case QUALIFIER_LONG:
721 case QUALIFIER_LONG_UPPER:
722 case QUALIFIER_CIRCUMFLEX:
723#if defined(QUALIFIER_SIZE_T)
724 case QUALIFIER_SIZE_T:
725#endif
726#if defined(QUALIFIER_PTRDIFF_T)
727 case QUALIFIER_PTRDIFF_T:
728#endif
729#if defined(QUALIFIER_INTMAX_T)
730 case QUALIFIER_INTMAX_T:
731#endif
732#if defined(QUALIFIER_QUAD)
733 case QUALIFIER_QUAD:
734#endif
735#if defined(QUALIFIER_SIZE_T_UPPER)
736 case QUALIFIER_SIZE_T_UPPER:
737#endif
738#if defined(QUALIFIER_WIDECHAR)
739 case QUALIFIER_WIDECHAR:
740#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000741#if defined(QUALIFIER_QUOTE)
742 case QUALIFIER_QUOTE:
743#endif
744#if defined(QUALIFIER_STICKY)
745 case QUALIFIER_STICKY:
746#endif
747#if defined(QUALIFIER_VARSIZE)
748 case QUALIFIER_VARSIZE:
749#endif
750#if defined(QUALIFIER_PARAM)
751 case QUALIFIER_PARAM:
752#endif
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000753#if defined(QUALIFIER_FIXED_SIZE)
754 case QUALIFIER_FIXED_SIZE:
755#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000756 return TRUE;
757 default:
758 return FALSE;
759 }
760}
761
762/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000763 * TrioSetLocale [private]
764 */
765#if defined(USE_LOCALE)
766static void
767TrioSetLocale(void)
768{
769 internalLocaleValues = (struct lconv *)localeconv();
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000770 if (internalLocaleValues)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000771 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000772 if ((internalLocaleValues->decimal_point) &&
773 (internalLocaleValues->decimal_point[0] != NIL))
774 {
775 StrCopyMax(internalDecimalPoint,
776 sizeof(internalDecimalPoint),
777 internalLocaleValues->decimal_point);
778 }
779 if ((internalLocaleValues->thousands_sep) &&
780 (internalLocaleValues->thousands_sep[0] != NIL))
781 {
782 StrCopyMax(internalThousandSeparator,
783 sizeof(internalThousandSeparator),
784 internalLocaleValues->thousands_sep);
785 }
786 if ((internalLocaleValues->grouping) &&
787 (internalLocaleValues->grouping[0] != NIL))
788 {
789 StrCopyMax(internalGrouping,
790 sizeof(internalGrouping),
791 internalLocaleValues->grouping);
792 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000793 }
794}
795#endif /* defined(USE_LOCALE) */
796
797/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000798 * TrioGetPosition [private]
799 *
800 * Get the %n$ position.
801 */
802static int
Bjorn Reese70a9da52001-04-21 16:57:29 +0000803TrioGetPosition(const char *format,
804 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000805{
806 char *tmpformat;
807 int number = 0;
808 int index = *indexPointer;
809
810 number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
811 index = (int)(tmpformat - format);
812 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
813 {
814 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000815 /*
816 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000817 * the array it is indexing starts from 0.
818 */
819 return number - 1;
820 }
821 return NO_POSITION;
822}
823
824/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000825 * TrioFindNamespace [private]
826 *
827 * Find registered user-defined specifier.
828 * The prev argument is used for optimisation only.
829 */
830static userdef_T *
831TrioFindNamespace(const char *name, userdef_T **prev)
832{
833 userdef_T *def;
834
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000835 if (internalEnterCriticalRegion)
836 (void)internalEnterCriticalRegion(NULL);
837
Bjorn Reese70a9da52001-04-21 16:57:29 +0000838 for (def = internalUserDef; def; def = def->next)
839 {
840 /* Case-sensitive string comparison */
841 if (StrEqualCase(def->name, name))
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000842 break;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000843
844 if (prev)
845 *prev = def;
846 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000847
848 if (internalLeaveCriticalRegion)
849 (void)internalLeaveCriticalRegion(NULL);
850
Bjorn Reese70a9da52001-04-21 16:57:29 +0000851 return def;
852}
853
854/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000855 * TrioPreprocess [private]
856 *
857 * Description:
858 * Parse the format string
859 */
860static int
861TrioPreprocess(int type,
862 const char *format,
863 parameter_T *parameters,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000864 va_list arglist,
865 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000866{
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000867#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +0000868 /* Count the number of times a parameter is referenced */
869 unsigned short usedEntries[MAX_PARAMETERS];
870#endif
871 /* Parameter counters */
872 int parameterPosition;
873 int currentParam;
874 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000875 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000876 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000877 int width;
878 int precision;
879 int varsize;
880 int base;
881 int index; /* Index into formatting string */
882 int dots; /* Count number of dots in modifier part */
883 BOOLEAN_T positional; /* Does the specifier have a positional? */
884 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000885 /*
886 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +0000887 * read from the va_args (this is necessary to handle positionals)
888 */
889 int indices[MAX_PARAMETERS];
890 int pos = 0;
891 /* Various variables */
892 char ch;
893 int charlen;
894 int i = -1;
895 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000896 char *tmpformat;
897
898
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000899#if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +0000900 /*
901 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +0000902 * know which entries we have used.
903 */
904 memset(usedEntries, 0, sizeof(usedEntries));
905#endif
906
907 index = 0;
908 parameterPosition = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000909#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000910 mblen(NULL, 0);
911#endif
912
913 while (format[index])
914 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000915#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000916 if (! isascii(format[index]))
917 {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000918 /*
919 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +0000920 * modifiers, so we skip over them.
921 */
922 charlen = mblen(&format[index], MB_LEN_MAX);
923 index += (charlen > 0) ? charlen : 1;
924 continue; /* while */
925 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +0000926#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000927 if (CHAR_IDENTIFIER == format[index++])
928 {
929 if (CHAR_IDENTIFIER == format[index])
930 {
931 index++;
932 continue; /* while */
933 }
934
935 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000936 dots = 0;
937 currentParam = TrioGetPosition(format, &index);
938 positional = (NO_POSITION != currentParam);
939 if (!positional)
940 {
941 /* We have no positional, get the next counter */
942 currentParam = parameterPosition;
943 }
944 if(currentParam >= MAX_PARAMETERS)
945 {
946 /* Bail out completely to make the error more obvious */
947 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
948 }
949
950 if (currentParam > maxParam)
951 maxParam = currentParam;
952
953 /* Default values */
954 width = NO_WIDTH;
955 precision = NO_PRECISION;
956 base = NO_BASE;
957 varsize = NO_SIZE;
958
Bjorn Reese70a9da52001-04-21 16:57:29 +0000959 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +0000960 {
961 ch = format[index++];
962
Daniel Veillard92ad2102001-03-27 12:47:33 +0000963 switch (ch)
964 {
Daniel Veillard92ad2102001-03-27 12:47:33 +0000965 case QUALIFIER_SPACE:
966 flags |= FLAGS_SPACE;
967 break;
968
969 case QUALIFIER_PLUS:
970 flags |= FLAGS_SHOWSIGN;
971 break;
972
973 case QUALIFIER_MINUS:
974 flags |= FLAGS_LEFTADJUST;
975 flags &= ~FLAGS_NILPADDING;
976 break;
977
978 case QUALIFIER_ALTERNATIVE:
979 flags |= FLAGS_ALTERNATIVE;
980 break;
981
982 case QUALIFIER_DOT:
983 if (dots == 0) /* Precision */
984 {
985 dots++;
986
987 /* Skip if no precision */
988 if (QUALIFIER_DOT == format[index])
989 break;
990
991 /* After the first dot we have the precision */
992 flags |= FLAGS_PRECISION;
993 if ((QUALIFIER_STAR == format[index]) ||
994 (QUALIFIER_PARAM == format[index]))
995 {
996 index++;
997 flags |= FLAGS_PRECISION_PARAMETER;
998
999 precision = TrioGetPosition(format, &index);
1000 if (precision == NO_POSITION)
1001 {
1002 parameterPosition++;
1003 if (positional)
1004 precision = parameterPosition;
1005 else
1006 {
1007 precision = currentParam;
1008 currentParam = precision + 1;
1009 }
1010 }
1011 else
1012 {
1013 if (! positional)
1014 currentParam = precision + 1;
1015 if (width > maxParam)
1016 maxParam = precision;
1017 }
1018 if (currentParam > maxParam)
1019 maxParam = currentParam;
1020 }
1021 else
1022 {
1023 precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1024 index = (int)(tmpformat - format);
1025 }
1026 }
1027 else if (dots == 1) /* Base */
1028 {
1029 dots++;
1030
1031 /* After the second dot we have the base */
1032 flags |= FLAGS_BASE;
1033 if ((QUALIFIER_STAR == format[index]) ||
1034 (QUALIFIER_PARAM == format[index]))
1035 {
1036 index++;
1037 flags |= FLAGS_BASE_PARAMETER;
1038 base = TrioGetPosition(format, &index);
1039 if (base == NO_POSITION)
1040 {
1041 parameterPosition++;
1042 if (positional)
1043 base = parameterPosition;
1044 else
1045 {
1046 base = currentParam;
1047 currentParam = base + 1;
1048 }
1049 }
1050 else
1051 {
1052 if (! positional)
1053 currentParam = base + 1;
1054 if (base > maxParam)
1055 maxParam = base;
1056 }
1057 if (currentParam > maxParam)
1058 maxParam = currentParam;
1059 }
1060 else
1061 {
1062 base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
1063 if (base > MAX_BASE)
1064 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1065 index = (int)(tmpformat - format);
1066 }
1067 }
1068 else
1069 {
1070 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1071 }
1072 break; /* QUALIFIER_DOT */
1073
1074 case QUALIFIER_PARAM:
1075 type = TYPE_PRINT;
1076 /* FALLTHROUGH */
1077 case QUALIFIER_STAR:
1078 /* This has different meanings for print and scan */
1079 if (TYPE_PRINT == type)
1080 {
1081 /* Read with from parameter */
1082 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1083 width = TrioGetPosition(format, &index);
1084 if (width == NO_POSITION)
1085 {
1086 parameterPosition++;
1087 if (positional)
1088 width = parameterPosition;
1089 else
1090 {
1091 width = currentParam;
1092 currentParam = width + 1;
1093 }
1094 }
1095 else
1096 {
1097 if (! positional)
1098 currentParam = width + 1;
1099 if (width > maxParam)
1100 maxParam = width;
1101 }
1102 if (currentParam > maxParam)
1103 maxParam = currentParam;
1104 }
1105 else
1106 {
1107 /* Scan, but do not store result */
1108 flags |= FLAGS_IGNORE;
1109 }
1110
1111 break; /* QUALIFIER_STAR */
1112
1113 case '0':
1114 if (! (flags & FLAGS_LEFTADJUST))
1115 flags |= FLAGS_NILPADDING;
1116 /* FALLTHROUGH */
1117 case '1': case '2': case '3': case '4':
1118 case '5': case '6': case '7': case '8': case '9':
1119 flags |= FLAGS_WIDTH;
1120 /* &format[index - 1] is used to "rewind" the read
1121 * character from format
1122 */
1123 width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
1124 index = (int)(tmpformat - format);
1125 break;
1126
1127 case QUALIFIER_SHORT:
1128 if (flags & FLAGS_SHORTSHORT)
1129 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1130 else if (flags & FLAGS_SHORT)
1131 flags |= FLAGS_SHORTSHORT;
1132 else
1133 flags |= FLAGS_SHORT;
1134 break;
1135
1136 case QUALIFIER_LONG:
1137 if (flags & FLAGS_QUAD)
1138 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1139 else if (flags & FLAGS_LONG)
1140 flags |= FLAGS_QUAD;
1141 else
1142 flags |= FLAGS_LONG;
1143 break;
1144
1145 case QUALIFIER_LONG_UPPER:
1146 flags |= FLAGS_LONGDOUBLE;
1147 break;
1148
1149#if defined(QUALIFIER_SIZE_T)
1150 case QUALIFIER_SIZE_T:
1151 flags |= FLAGS_SIZE_T;
1152 /* Modify flags for later truncation of number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001153 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001154 flags |= FLAGS_QUAD;
1155 else if (sizeof(size_t) == sizeof(long))
1156 flags |= FLAGS_LONG;
1157 break;
1158#endif
1159
1160#if defined(QUALIFIER_PTRDIFF_T)
1161 case QUALIFIER_PTRDIFF_T:
1162 flags |= FLAGS_PTRDIFF_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001163 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001164 flags |= FLAGS_QUAD;
1165 else if (sizeof(ptrdiff_t) == sizeof(long))
1166 flags |= FLAGS_LONG;
1167 break;
1168#endif
1169
1170#if defined(QUALIFIER_INTMAX_T)
1171 case QUALIFIER_INTMAX_T:
1172 flags |= FLAGS_INTMAX_T;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001173 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001174 flags |= FLAGS_QUAD;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001175 else if (sizeof(trio_intmax_t) == sizeof(long))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001176 flags |= FLAGS_LONG;
1177 break;
1178#endif
1179
1180#if defined(QUALIFIER_QUAD)
1181 case QUALIFIER_QUAD:
1182 flags |= FLAGS_QUAD;
1183 break;
1184#endif
1185
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001186#if defined(QUALIFIER_FIXED_SIZE)
1187 case QUALIFIER_FIXED_SIZE:
1188 if (flags & FLAGS_FIXED_SIZE)
1189 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1190
1191 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1192 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1193 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1194
1195 if ((format[index] == '6') &&
1196 (format[index + 1] == '4'))
1197 {
1198 varsize = sizeof(trio_int64_t);
1199 index += 2;
1200 }
1201 else if ((format[index] == '3') &&
1202 (format[index + 1] == '2'))
1203 {
1204 varsize = sizeof(trio_int32_t);
1205 index += 2;
1206 }
1207 else if ((format[index] == '1') &&
1208 (format[index + 1] == '6'))
1209 {
1210 varsize = sizeof(trio_int16_t);
1211 index += 2;
1212 }
1213 else if (format[index] == '8')
1214 {
1215 varsize = sizeof(trio_int8_t);
1216 index++;
1217 }
1218 else
1219 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1220
1221 flags |= FLAGS_FIXED_SIZE;
1222 break;
1223#endif
1224
Daniel Veillard92ad2102001-03-27 12:47:33 +00001225#if defined(QUALIFIER_WIDECHAR)
1226 case QUALIFIER_WIDECHAR:
1227 flags |= FLAGS_WIDECHAR;
1228 break;
1229#endif
1230
1231#if defined(QUALIFIER_SIZE_T_UPPER)
1232 case QUALIFIER_SIZE_T_UPPER:
1233 break;
1234#endif
1235
1236#if defined(QUALIFIER_QUOTE)
1237 case QUALIFIER_QUOTE:
1238 flags |= FLAGS_QUOTE;
1239 break;
1240#endif
1241
1242#if defined(QUALIFIER_STICKY)
1243 case QUALIFIER_STICKY:
1244 flags |= FLAGS_STICKY;
1245 got_sticky = TRUE;
1246 break;
1247#endif
1248
1249#if defined(QUALIFIER_VARSIZE)
1250 case QUALIFIER_VARSIZE:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001251 flags |= FLAGS_VARSIZE_PARAMETER;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001252 parameterPosition++;
1253 if (positional)
1254 varsize = parameterPosition;
1255 else
1256 {
1257 varsize = currentParam;
1258 currentParam = varsize + 1;
1259 }
1260 if (currentParam > maxParam)
1261 maxParam = currentParam;
1262 break;
1263#endif
1264
1265 default:
1266 /* Bail out completely to make the error more obvious */
1267 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1268 }
1269 } /* while qualifier */
1270
Bjorn Reese70a9da52001-04-21 16:57:29 +00001271 /*
1272 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001273 * read later.
1274 */
1275 if (flags & FLAGS_WIDTH_PARAMETER)
1276 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001277#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001278 usedEntries[width] += 1;
1279#endif
1280 parameters[pos].type = FORMAT_PARAMETER;
1281 indices[width] = pos;
1282 width = pos++;
1283 }
1284 if (flags & FLAGS_PRECISION_PARAMETER)
1285 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001286#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001287 usedEntries[precision] += 1;
1288#endif
1289 parameters[pos].type = FORMAT_PARAMETER;
1290 indices[precision] = pos;
1291 precision = pos++;
1292 }
1293 if (flags & FLAGS_BASE_PARAMETER)
1294 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001295#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001296 usedEntries[base] += 1;
1297#endif
1298 parameters[pos].type = FORMAT_PARAMETER;
1299 indices[base] = pos;
1300 base = pos++;
1301 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001302 if (flags & FLAGS_VARSIZE_PARAMETER)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001303 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001304#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001305 usedEntries[varsize] += 1;
1306#endif
1307 parameters[pos].type = FORMAT_PARAMETER;
1308 indices[varsize] = pos;
1309 varsize = pos++;
1310 }
1311
1312 indices[currentParam] = pos;
1313
1314 switch (format[index++])
1315 {
1316#if defined(SPECIFIER_CHAR_UPPER)
1317 case SPECIFIER_CHAR_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001318 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001319 /* FALLTHROUGH */
1320#endif
1321 case SPECIFIER_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001322 if (flags & FLAGS_LONG)
1323 flags |= FLAGS_WIDECHAR;
1324 else if (flags & FLAGS_SHORT)
1325 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001326 parameters[pos].type = FORMAT_CHAR;
1327 break;
1328
1329#if defined(SPECIFIER_STRING_UPPER)
1330 case SPECIFIER_STRING_UPPER:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001331 flags |= FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001332 /* FALLTHROUGH */
1333#endif
1334 case SPECIFIER_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001335 if (flags & FLAGS_LONG)
1336 flags |= FLAGS_WIDECHAR;
1337 else if (flags & FLAGS_SHORT)
1338 flags &= ~FLAGS_WIDECHAR;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001339 parameters[pos].type = FORMAT_STRING;
1340 break;
1341
1342 case SPECIFIER_GROUP:
1343 if (TYPE_SCAN == type)
1344 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001345 int depth = 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001346 parameters[pos].type = FORMAT_GROUP;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001347 if (format[index] == QUALIFIER_CIRCUMFLEX)
1348 index++;
1349 if (format[index] == SPECIFIER_UNGROUP)
1350 index++;
1351 if (format[index] == QUALIFIER_MINUS)
1352 index++;
1353 /* Skip nested brackets */
1354 while (format[index] != NIL)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001355 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001356 if (format[index] == SPECIFIER_GROUP)
1357 {
1358 depth++;
1359 }
1360 else if (format[index] == SPECIFIER_UNGROUP)
1361 {
1362 if (--depth <= 0)
1363 {
1364 index++;
1365 break;
1366 }
1367 }
1368 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001369 }
1370 }
1371 break;
1372
1373 case SPECIFIER_INTEGER:
1374 parameters[pos].type = FORMAT_INT;
1375 break;
1376
1377 case SPECIFIER_UNSIGNED:
1378 flags |= FLAGS_UNSIGNED;
1379 parameters[pos].type = FORMAT_INT;
1380 break;
1381
1382 case SPECIFIER_DECIMAL:
1383 /* Disable base modifier */
1384 flags &= ~FLAGS_BASE_PARAMETER;
1385 base = BASE_DECIMAL;
1386 parameters[pos].type = FORMAT_INT;
1387 break;
1388
1389 case SPECIFIER_OCTAL:
1390 flags &= ~FLAGS_BASE_PARAMETER;
1391 base = BASE_OCTAL;
1392 parameters[pos].type = FORMAT_INT;
1393 break;
1394
1395#if defined(SPECIFIER_BINARY)
1396 case SPECIFIER_BINARY_UPPER:
1397 flags |= FLAGS_UPPER;
1398 /* FALLTHROUGH */
1399 case SPECIFIER_BINARY:
1400 flags |= FLAGS_NILPADDING;
1401 flags &= ~FLAGS_BASE_PARAMETER;
1402 base = BASE_BINARY;
1403 parameters[pos].type = FORMAT_INT;
1404 break;
1405#endif
1406
1407 case SPECIFIER_HEX_UPPER:
1408 flags |= FLAGS_UPPER;
1409 /* FALLTHROUGH */
1410 case SPECIFIER_HEX:
1411 flags |= FLAGS_UNSIGNED;
1412 flags &= ~FLAGS_BASE_PARAMETER;
1413 base = BASE_HEX;
1414 parameters[pos].type = FORMAT_INT;
1415 break;
1416
1417 case SPECIFIER_FLOAT_E_UPPER:
1418 flags |= FLAGS_UPPER;
1419 /* FALLTHROUGH */
1420 case SPECIFIER_FLOAT_E:
1421 flags |= FLAGS_FLOAT_E;
1422 parameters[pos].type = FORMAT_DOUBLE;
1423 break;
1424
1425 case SPECIFIER_FLOAT_G_UPPER:
1426 flags |= FLAGS_UPPER;
1427 /* FALLTHROUGH */
1428 case SPECIFIER_FLOAT_G:
1429 flags |= FLAGS_FLOAT_G;
1430 parameters[pos].type = FORMAT_DOUBLE;
1431 break;
1432
1433 case SPECIFIER_FLOAT_F_UPPER:
1434 flags |= FLAGS_UPPER;
1435 /* FALLTHROUGH */
1436 case SPECIFIER_FLOAT_F:
1437 parameters[pos].type = FORMAT_DOUBLE;
1438 break;
1439
1440 case SPECIFIER_POINTER:
1441 parameters[pos].type = FORMAT_POINTER;
1442 break;
1443
1444 case SPECIFIER_COUNT:
1445 parameters[pos].type = FORMAT_COUNT;
1446 break;
1447
1448#if defined(SPECIFIER_HEXFLOAT)
1449# if defined(SPECIFIER_HEXFLOAT_UPPER)
1450 case SPECIFIER_HEXFLOAT_UPPER:
1451 flags |= FLAGS_UPPER;
1452 /* FALLTHROUGH */
1453# endif
1454 case SPECIFIER_HEXFLOAT:
1455 base = BASE_HEX;
1456 parameters[pos].type = FORMAT_DOUBLE;
1457 break;
1458#endif
1459
1460#if defined(FORMAT_ERRNO)
1461 case SPECIFIER_ERRNO:
1462 parameters[pos].type = FORMAT_ERRNO;
1463 break;
1464#endif
1465
Bjorn Reese70a9da52001-04-21 16:57:29 +00001466#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1467 case SPECIFIER_USER_DEFINED_BEGIN:
1468 {
1469 unsigned int max;
1470 int without_namespace = TRUE;
1471
1472 parameters[pos].type = FORMAT_USER_DEFINED;
1473 parameters[pos].user_name[0] = NIL;
1474 tmpformat = (char *)&format[index];
1475
1476 while ((ch = format[index]))
1477 {
1478 index++;
1479 if (ch == SPECIFIER_USER_DEFINED_END)
1480 {
1481 if (without_namespace)
1482 {
1483 /* We must get the handle first */
1484 parameters[pos].type = FORMAT_PARAMETER;
1485 parameters[pos].indexAfterSpecifier = index;
1486 parameters[pos].flags = FLAGS_USER_DEFINED;
1487 /* Adjust parameters for insertion of new one */
1488 pos++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001489# if TRIO_ERRORS
Bjorn Reese70a9da52001-04-21 16:57:29 +00001490 usedEntries[currentParam] += 1;
1491# endif
1492 parameters[pos].type = FORMAT_USER_DEFINED;
1493 currentParam++;
1494 indices[currentParam] = pos;
1495 if (currentParam > maxParam)
1496 maxParam = currentParam;
1497 }
1498 /* Copy the user data */
1499 max = (unsigned int)(&format[index] - tmpformat);
1500 if (max > MAX_USER_DATA)
1501 max = MAX_USER_DATA;
1502 StrCopyMax(parameters[pos].user_data,
1503 max,
1504 tmpformat);
1505 break; /* while */
1506 }
1507 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1508 {
1509 without_namespace = FALSE;
1510 /* Copy the namespace for later looking-up */
1511 max = (int)(&format[index] - tmpformat);
1512 if (max > MAX_USER_NAME)
1513 max = MAX_USER_NAME;
1514 StrCopyMax(parameters[pos].user_name,
1515 max,
1516 tmpformat);
1517 tmpformat = (char *)&format[index];
1518 }
1519 }
1520 if (ch != SPECIFIER_USER_DEFINED_END)
1521 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1522 }
1523 break;
1524#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1525
Daniel Veillard92ad2102001-03-27 12:47:33 +00001526 default:
1527 /* Bail out completely to make the error more obvious */
1528 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1529 }
1530
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001531#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001532 /* Count the number of times this entry has been used */
1533 usedEntries[currentParam] += 1;
1534#endif
1535
1536 /* Find last sticky parameters */
1537 if (got_sticky && !(flags & FLAGS_STICKY))
1538 {
1539 for (i = pos - 1; i >= 0; i--)
1540 {
1541 if (parameters[i].type == FORMAT_PARAMETER)
1542 continue;
1543 if ((parameters[i].flags & FLAGS_STICKY) &&
1544 (parameters[i].type == parameters[pos].type))
1545 {
1546 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001547 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001548 if (width == NO_WIDTH)
1549 width = parameters[i].width;
1550 if (precision == NO_PRECISION)
1551 precision = parameters[i].precision;
1552 if (base == NO_BASE)
1553 base = parameters[i].base;
1554 break;
1555 }
1556 }
1557 }
1558
1559 parameters[pos].indexAfterSpecifier = index;
1560 parameters[pos].flags = flags;
1561 parameters[pos].width = width;
1562 parameters[pos].precision = precision;
1563 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1564 parameters[pos].varsize = varsize;
1565 pos++;
1566
Bjorn Reese70a9da52001-04-21 16:57:29 +00001567 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001568 parameterPosition++;
1569
1570 } /* if identifier */
1571
1572 } /* while format characters left */
1573
1574 for (num = 0; num <= maxParam; num++)
1575 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001576#if TRIO_ERRORS
Daniel Veillard92ad2102001-03-27 12:47:33 +00001577 if (usedEntries[num] != 1)
1578 {
1579 if (usedEntries[num] == 0) /* gap detected */
1580 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1581 else /* double references detected */
1582 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1583 }
1584#endif
1585
1586 i = indices[num];
1587
Bjorn Reese70a9da52001-04-21 16:57:29 +00001588 /*
1589 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001590 * so it makes no sense to check the ignore flag (besides,
1591 * the flags variable is not set for that particular type)
1592 */
1593 if ((parameters[i].type != FORMAT_PARAMETER) &&
1594 (parameters[i].flags & FLAGS_IGNORE))
1595 continue; /* for all arguments */
1596
Bjorn Reese70a9da52001-04-21 16:57:29 +00001597 /*
1598 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001599 * default argument promotions:
1600 *
1601 * char = int
1602 * short = int
1603 * unsigned char = unsigned int
1604 * unsigned short = unsigned int
1605 * float = double
1606 *
1607 * In addition to the ANSI C89 these types are read (the
1608 * default argument promotions of C99 has not been
1609 * considered yet)
1610 *
1611 * long long
1612 * long double
1613 * size_t
1614 * ptrdiff_t
1615 * intmax_t
1616 */
1617 switch (parameters[i].type)
1618 {
1619 case FORMAT_GROUP:
1620 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001621#if TRIO_WIDECHAR
1622 if (flags & FLAGS_WIDECHAR)
1623 {
1624 parameters[i].data.wstring = (argarray == NULL)
1625 ? va_arg(arglist, wchar_t *)
1626 : (wchar_t *)(argarray[num]);
1627 }
1628 else
1629#endif
1630 {
1631 parameters[i].data.string = (argarray == NULL)
1632 ? va_arg(arglist, char *)
1633 : (char *)(argarray[num]);
1634 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001635 break;
1636
1637 case FORMAT_POINTER:
1638 case FORMAT_COUNT:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001639 case FORMAT_USER_DEFINED:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001640 case FORMAT_UNKNOWN:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001641 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001642 ? va_arg(arglist, void *)
1643 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001644 break;
1645
1646 case FORMAT_CHAR:
1647 case FORMAT_INT:
1648 if (TYPE_SCAN == type)
1649 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001650 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001651 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001652 (trio_uintmax_t *)va_arg(arglist, void *);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001653 else
1654 {
1655 if (parameters[i].type == FORMAT_CHAR)
1656 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001657 (trio_uintmax_t *)((char *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001658 else if (parameters[i].flags & FLAGS_SHORT)
1659 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001660 (trio_uintmax_t *)((short *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001661 else
1662 parameters[i].data.pointer =
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001663 (trio_uintmax_t *)((int *)argarray[num]);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001664 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001665 }
1666 else
1667 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001668#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
1669 if ((parameters[i].flags & FLAGS_VARSIZE_PARAMETER) ||
1670 (parameters[i].flags & FLAGS_FIXED_SIZE))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001671 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001672 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1673 {
1674 /*
1675 * Variable sizes are mapped onto the fixed sizes, in
1676 * accordance with integer promotion.
1677 *
1678 * Please note that this may not be portable, as we
1679 * only guess the size, not the layout of the numbers.
1680 * For example, if int is little-endian, and long is
1681 * big-endian, then this will fail.
1682 */
1683 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1684 }
1685 else
1686 {
1687 /* Used for the I<bits> modifiers */
1688 varsize = parameters[i].varsize;
1689 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001690 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001691
Daniel Veillard92ad2102001-03-27 12:47:33 +00001692 if (varsize <= (int)sizeof(int))
1693 ;
1694 else if (varsize <= (int)sizeof(long))
1695 parameters[i].flags |= FLAGS_LONG;
1696#if defined(QUALIFIER_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001697 else if (varsize <= (int)sizeof(trio_longlong_t))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001698 parameters[i].flags |= FLAGS_QUAD;
1699 else
1700 parameters[i].flags |= FLAGS_INTMAX_T;
1701#else
1702 else
1703 parameters[i].flags |= FLAGS_QUAD;
1704#endif
1705 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001706#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001707#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1708 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001709 parameters[i].data.number.as_unsigned = (argarray == NULL)
1710 ? (trio_uintmax_t)va_arg(arglist, size_t)
1711 : (trio_uintmax_t)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001712 else
1713#endif
1714#if defined(QUALIFIER_PTRDIFF_T)
1715 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001716 parameters[i].data.number.as_unsigned = (argarray == NULL)
1717 ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
1718 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001719 else
1720#endif
1721#if defined(QUALIFIER_INTMAX_T)
1722 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001723 parameters[i].data.number.as_unsigned = (argarray == NULL)
1724 ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
1725 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001726 else
1727#endif
1728 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001729 parameters[i].data.number.as_unsigned = (argarray == NULL)
1730 ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
1731 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001732 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001733 parameters[i].data.number.as_unsigned = (argarray == NULL)
1734 ? (trio_uintmax_t)va_arg(arglist, long)
1735 : (trio_uintmax_t)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001736 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001737 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001738 if (argarray == NULL)
1739 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001740 else
1741 {
1742 if (parameters[i].type == FORMAT_CHAR)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001743 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001744 else if (parameters[i].flags & FLAGS_SHORT)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001745 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001746 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001747 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
Bjorn Reese70a9da52001-04-21 16:57:29 +00001748 }
1749 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001750 }
1751 break;
1752
1753 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001754 /*
1755 * The parameter for the user-defined specifier is a pointer,
1756 * whereas the rest (width, precision, base) uses an integer.
1757 */
1758 if (parameters[i].flags & FLAGS_USER_DEFINED)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001759 parameters[i].data.pointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001760 ? va_arg(arglist, void *)
1761 : argarray[num];
1762 else
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001763 parameters[i].data.number.as_unsigned = (argarray == NULL)
1764 ? (trio_uintmax_t)va_arg(arglist, int)
1765 : (trio_uintmax_t)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001766 break;
1767
1768 case FORMAT_DOUBLE:
1769 if (TYPE_SCAN == type)
1770 {
1771 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001772 parameters[i].data.longdoublePointer = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001773 ? va_arg(arglist, long double *)
1774 : (long double *)((long double *)argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001775 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001776 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001777 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001778 parameters[i].data.doublePointer =
1779 va_arg(arglist, double *);
1780 else
1781 {
1782 if (parameters[i].flags & FLAGS_SHORT)
1783 parameters[i].data.doublePointer =
1784 (double *)((float *)argarray[num]);
1785 else
1786 parameters[i].data.doublePointer =
1787 (double *)((double *)argarray[num]);
1788 }
1789 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001790 }
1791 else
1792 {
1793 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001794 parameters[i].data.longdoubleNumber = (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001795 ? va_arg(arglist, long double)
1796 : (long double)(*((long double *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001797 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001798 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001799 if (argarray == NULL)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001800 parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
1801 else
1802 {
1803 if (parameters[i].flags & FLAGS_SHORT)
1804 parameters[i].data.longdoubleNumber = (long double)(*((float *)argarray[num]));
1805 else
1806 parameters[i].data.longdoubleNumber = (long double)(long double)(*((double *)argarray[num]));
1807 }
1808 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001809 }
1810 break;
1811
1812#if defined(FORMAT_ERRNO)
1813 case FORMAT_ERRNO:
1814 parameters[i].data.errorNumber = errno;
1815 break;
1816#endif
1817
1818 default:
1819 break;
1820 }
1821 } /* for all specifiers */
1822 return num;
1823}
1824
1825
1826/*************************************************************************
1827 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00001828 * @FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00001829 *
1830 ************************************************************************/
1831
1832
1833/*************************************************************************
1834 * TrioWriteNumber [private]
1835 *
1836 * Description:
1837 * Output a number.
1838 * The complexity of this function is a result of the complexity
1839 * of the dependencies of the flags.
1840 */
1841static void
1842TrioWriteNumber(trio_T *self,
Bjorn Reese45029602001-08-21 09:23:53 +00001843 trio_intmax_t snumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001844 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001845 int width,
1846 int precision,
1847 int base)
1848{
1849 BOOLEAN_T isNegative;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001850 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001851 char *bufferend;
1852 char *pointer;
1853 const char *digits;
Bjorn Reese45029602001-08-21 09:23:53 +00001854 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001855 int i;
1856 int length;
1857 char *p;
1858 int charsPerThousand;
1859 int groupingIndex;
1860 int count;
1861
1862 assert(VALID(self));
1863 assert(VALID(self->OutStream));
1864 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
1865
Bjorn Reese70a9da52001-04-21 16:57:29 +00001866 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001867
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001868 isNegative = (flags & FLAGS_UNSIGNED)
1869 ? FALSE
Bjorn Reese45029602001-08-21 09:23:53 +00001870 : (snumber < 0);
1871 number = (isNegative) ? -snumber : snumber;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001872
1873 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00001874 number &= (trio_ulonglong_t)-1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001875 else if (flags & FLAGS_LONG)
1876 number &= (unsigned long)-1;
1877 else
1878 number &= (unsigned int)-1;
1879
1880 /* Build number */
1881 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1882 *pointer-- = NIL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001883 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001884 groupingIndex = 1;
1885 for (i = 1; i < (int)sizeof(buffer); i++)
1886 {
1887 *pointer-- = digits[number % base];
1888 number /= base;
1889 if (number == 0)
1890 break;
1891
1892 if ((flags & FLAGS_QUOTE)
1893 && (charsPerThousand != NO_GROUPING)
1894 && (i % charsPerThousand == 0))
1895 {
1896 /*
1897 * We are building the number from the least significant
1898 * to the most significant digit, so we have to copy the
1899 * thousand separator backwards
1900 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001901 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001902 if (((int)(pointer - buffer) - length) > 0)
1903 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001904 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001905 while (length-- > 0)
1906 *pointer-- = *p--;
1907 }
1908
1909 /* Advance to next grouping number */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001910 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00001911 {
1912 case CHAR_MAX: /* Disable grouping */
1913 charsPerThousand = NO_GROUPING;
1914 break;
1915 case 0: /* Repeat last group */
1916 break;
1917 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001918 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001919 break;
1920 }
1921 }
1922 }
1923
1924 /* Adjust width */
1925 width -= (bufferend - pointer) - 1;
1926
1927 /* Adjust precision */
1928 if (NO_PRECISION != precision)
1929 {
1930 precision -= (bufferend - pointer) - 1;
1931 if (precision < 0)
1932 precision = 0;
1933 flags |= FLAGS_NILPADDING;
1934 }
1935
1936 /* Adjust width further */
1937 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
1938 width--;
1939 if (flags & FLAGS_ALTERNATIVE)
1940 {
1941 switch (base)
1942 {
1943 case BASE_BINARY:
1944 case BASE_HEX:
1945 width -= 2;
1946 break;
1947 case BASE_OCTAL:
1948 width--;
1949 break;
1950 default:
1951 break;
1952 }
1953 }
1954
1955 /* Output prefixes spaces if needed */
1956 if (! ((flags & FLAGS_LEFTADJUST) ||
1957 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
1958 {
1959 count = (precision == NO_PRECISION) ? 0 : precision;
1960 while (width-- > count)
1961 self->OutStream(self, CHAR_ADJUST);
1962 }
1963
1964 /* width has been adjusted for signs and alternatives */
1965 if (isNegative)
1966 self->OutStream(self, '-');
1967 else if (flags & FLAGS_SHOWSIGN)
1968 self->OutStream(self, '+');
1969 else if (flags & FLAGS_SPACE)
1970 self->OutStream(self, ' ');
1971
1972 if (flags & FLAGS_ALTERNATIVE)
1973 {
1974 switch (base)
1975 {
1976 case BASE_BINARY:
1977 self->OutStream(self, '0');
1978 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
1979 break;
1980
1981 case BASE_OCTAL:
1982 self->OutStream(self, '0');
1983 break;
1984
1985 case BASE_HEX:
1986 self->OutStream(self, '0');
1987 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
1988 break;
1989
1990 default:
1991 break;
1992 } /* switch base */
1993 }
1994
1995 /* Output prefixed zero padding if needed */
1996 if (flags & FLAGS_NILPADDING)
1997 {
1998 if (precision == NO_PRECISION)
1999 precision = width;
2000 while (precision-- > 0)
2001 {
2002 self->OutStream(self, '0');
2003 width--;
2004 }
2005 }
2006
2007 /* Output the number itself */
2008 while (*(++pointer))
2009 {
2010 self->OutStream(self, *pointer);
2011 }
2012
2013 /* Output trailing spaces if needed */
2014 if (flags & FLAGS_LEFTADJUST)
2015 {
2016 while (width-- > 0)
2017 self->OutStream(self, CHAR_ADJUST);
2018 }
2019}
2020
2021/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002022 * TrioWriteStringCharacter [private]
2023 *
2024 * Description:
2025 * Output a single character of a string
2026 */
2027static void
2028TrioWriteStringCharacter(trio_T *self,
2029 int ch,
2030 unsigned long flags)
2031{
2032 if (flags & FLAGS_ALTERNATIVE)
2033 {
2034 if (! (isprint(ch) || isspace(ch)))
2035 {
2036 /*
2037 * Non-printable characters are converted to C escapes or
2038 * \number, if no C escape exists.
2039 */
2040 self->OutStream(self, CHAR_BACKSLASH);
2041 switch (ch)
2042 {
2043 case '\007': self->OutStream(self, 'a'); break;
2044 case '\b': self->OutStream(self, 'b'); break;
2045 case '\f': self->OutStream(self, 'f'); break;
2046 case '\n': self->OutStream(self, 'n'); break;
2047 case '\r': self->OutStream(self, 'r'); break;
2048 case '\t': self->OutStream(self, 't'); break;
2049 case '\v': self->OutStream(self, 'v'); break;
2050 case '\\': self->OutStream(self, '\\'); break;
2051 default:
2052 self->OutStream(self, 'x');
2053 TrioWriteNumber(self, (trio_intmax_t)ch,
2054 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2055 2, 2, BASE_HEX);
2056 break;
2057 }
2058 }
2059 else if (ch == CHAR_BACKSLASH)
2060 {
2061 self->OutStream(self, CHAR_BACKSLASH);
2062 self->OutStream(self, CHAR_BACKSLASH);
2063 }
2064 else
2065 {
2066 self->OutStream(self, ch);
2067 }
2068 }
2069 else
2070 {
2071 self->OutStream(self, ch);
2072 }
2073}
2074
2075/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002076 * TrioWriteString [private]
2077 *
2078 * Description:
2079 * Output a string
2080 */
2081static void
2082TrioWriteString(trio_T *self,
2083 const char *string,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002084 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002085 int width,
2086 int precision)
2087{
2088 int length;
2089 int ch;
2090
2091 assert(VALID(self));
2092 assert(VALID(self->OutStream));
2093
2094 if (string == NULL)
2095 {
2096 string = null;
2097 length = sizeof(null) - 1;
2098 /* Disable quoting for the null pointer */
2099 flags &= (~FLAGS_QUOTE);
2100 width = 0;
2101 }
2102 else
2103 {
2104 length = StrLength(string);
2105 }
2106 if ((NO_PRECISION != precision) &&
2107 (precision < length))
2108 {
2109 length = precision;
2110 }
2111 width -= length;
2112
2113 if (flags & FLAGS_QUOTE)
2114 self->OutStream(self, CHAR_QUOTE);
2115
2116 if (! (flags & FLAGS_LEFTADJUST))
2117 {
2118 while (width-- > 0)
2119 self->OutStream(self, CHAR_ADJUST);
2120 }
2121
2122 while (length-- > 0)
2123 {
2124 /* The ctype parameters must be an unsigned char (or EOF) */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002125 ch = (int)((unsigned char)(*string++));
2126 TrioWriteStringCharacter(self, ch, flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002127 }
2128
2129 if (flags & FLAGS_LEFTADJUST)
2130 {
2131 while (width-- > 0)
2132 self->OutStream(self, CHAR_ADJUST);
2133 }
2134 if (flags & FLAGS_QUOTE)
2135 self->OutStream(self, CHAR_QUOTE);
2136}
2137
2138/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002139 * TrioWriteWideStringCharacter [private]
2140 *
2141 * Description:
2142 * Output a wide string as a multi-byte sequence
2143 */
2144#if TRIO_WIDECHAR
2145static int
2146TrioWriteWideStringCharacter(trio_T *self,
2147 wchar_t wch,
2148 unsigned long flags,
2149 int width)
2150{
2151 int size;
2152 int i;
2153 int ch;
2154 char *string;
2155 char buffer[MB_LEN_MAX + 1];
2156
2157 if (width == NO_WIDTH)
2158 width = sizeof(buffer);
2159
2160 size = wctomb(buffer, wch);
2161 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2162 return 0;
2163
2164 string = buffer;
2165 i = size;
2166 while ((width >= i) && (width-- > 0) && (i-- > 0))
2167 {
2168 /* The ctype parameters must be an unsigned char (or EOF) */
2169 ch = (int)((unsigned char)(*string++));
2170 TrioWriteStringCharacter(self, ch, flags);
2171 }
2172 return size;
2173}
2174#endif /* TRIO_WIDECHAR */
2175
2176/*************************************************************************
2177 * TrioWriteString [private]
2178 *
2179 * Description:
2180 * Output a wide character string as a multi-byte string
2181 */
2182#if TRIO_WIDECHAR
2183static void
2184TrioWriteWideString(trio_T *self,
2185 const wchar_t *wstring,
2186 unsigned long flags,
2187 int width,
2188 int precision)
2189{
2190 int length;
2191 int size;
2192
2193 assert(VALID(self));
2194 assert(VALID(self->OutStream));
2195
2196#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2197 mblen(NULL, 0);
2198#endif
2199
2200 if (wstring == NULL)
2201 {
2202 TrioWriteString(self, NULL, flags, width, precision);
2203 return;
2204 }
2205
2206 if (NO_PRECISION == precision)
2207 {
2208 length = INT_MAX;
2209 }
2210 else
2211 {
2212 length = precision;
2213 width -= length;
2214 }
2215
2216 if (flags & FLAGS_QUOTE)
2217 self->OutStream(self, CHAR_QUOTE);
2218
2219 if (! (flags & FLAGS_LEFTADJUST))
2220 {
2221 while (width-- > 0)
2222 self->OutStream(self, CHAR_ADJUST);
2223 }
2224
2225 while (length > 0)
2226 {
2227 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2228 if (size == 0)
2229 break; /* while */
2230 length -= size;
2231 }
2232
2233 if (flags & FLAGS_LEFTADJUST)
2234 {
2235 while (width-- > 0)
2236 self->OutStream(self, CHAR_ADJUST);
2237 }
2238 if (flags & FLAGS_QUOTE)
2239 self->OutStream(self, CHAR_QUOTE);
2240}
2241#endif /* TRIO_WIDECHAR */
2242
2243/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002244 * TrioWriteDouble [private]
2245 */
2246static void
2247TrioWriteDouble(trio_T *self,
2248 long double longdoubleNumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002249 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002250 int width,
2251 int precision,
2252 int base)
2253{
2254 int charsPerThousand;
2255 int length;
2256 double number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002257 double workNumber;
2258 int integerDigits;
2259 int fractionDigits;
2260 int exponentDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002261 int expectedWidth;
2262 int exponent;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002263 unsigned int uExponent = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002264 double dblBase;
2265 BOOLEAN_T isNegative;
2266 BOOLEAN_T isExponentNegative = FALSE;
2267 BOOLEAN_T isHex;
2268 const char *digits;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002269 char numberBuffer[MAX_MANTISSA_DIGITS
2270 * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002271 char *numberPointer;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002272 char exponentBuffer[MAX_EXPONENT_DIGITS + 1];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002273 char *exponentPointer = NULL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002274 int groupingIndex;
2275 char *work;
2276 int i;
2277 BOOLEAN_T onlyzero;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002278 int zeroes = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002279
2280 assert(VALID(self));
2281 assert(VALID(self->OutStream));
2282 assert(base == BASE_DECIMAL || base == BASE_HEX);
2283
2284 number = (double)longdoubleNumber;
2285
Bjorn Reese70a9da52001-04-21 16:57:29 +00002286 /* Look for infinite numbers and non-a-number first */
Bjorn Reese45029602001-08-21 09:23:53 +00002287 switch (trio_isinf(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002288 {
2289 case 1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002290 /* Positive infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002291 TrioWriteString(self,
2292 (flags & FLAGS_UPPER)
2293 ? INFINITE_UPPER
2294 : INFINITE_LOWER,
2295 flags, width, precision);
2296 return;
2297
2298 case -1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002299 /* Negative infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002300 TrioWriteString(self,
2301 (flags & FLAGS_UPPER)
2302 ? "-" INFINITE_UPPER
2303 : "-" INFINITE_LOWER,
2304 flags, width, precision);
2305 return;
2306
2307 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002308 /* Finitude */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002309 break;
2310 }
Bjorn Reese45029602001-08-21 09:23:53 +00002311 if (trio_isnan(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002312 {
2313 TrioWriteString(self,
2314 (flags & FLAGS_UPPER)
2315 ? NAN_UPPER
2316 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002317 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002318 return;
2319 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002320
2321 /* Normal numbers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002322 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002323 isHex = (base == BASE_HEX);
2324 dblBase = (double)base;
2325
2326 if (precision == NO_PRECISION)
2327 precision = FLT_DIG;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002328
2329 isNegative = (number < 0.0);
2330 if (isNegative)
2331 number = -number;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002332
Daniel Veillard92ad2102001-03-27 12:47:33 +00002333 if ((flags & FLAGS_FLOAT_G) || isHex)
2334 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00002335 if (precision == 0)
2336 precision = 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002337
2338 if ((number < 1.0e-4) || (number > pow(10.0, (double)precision)))
2339 {
2340 /* Use scientific notation */
2341 flags |= FLAGS_FLOAT_E;
2342 }
2343 else if (number < 1.0)
2344 {
2345 /*
2346 * Use normal notation. If the integer part of the number is
2347 * zero, then adjust the precision to include leading fractional
2348 * zeros.
2349 */
2350 workNumber = fabs(guarded_log10(number));
2351 if (workNumber - floor(workNumber) < 0.001)
2352 workNumber--;
2353 zeroes = (int)floor(workNumber);
2354 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002355 }
2356
2357 if (flags & FLAGS_FLOAT_E)
2358 {
2359 /* Scale the number */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002360 workNumber = guarded_log10(number);
Bjorn Reese45029602001-08-21 09:23:53 +00002361 if (trio_isinf(workNumber) == -1)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002362 {
2363 exponent = 0;
2364 /* Undo setting */
2365 if (flags & FLAGS_FLOAT_G)
2366 flags &= ~FLAGS_FLOAT_E;
2367 }
2368 else
2369 {
2370 exponent = (int)floor(workNumber);
2371 number /= pow(10.0, (double)exponent);
2372 isExponentNegative = (exponent < 0);
2373 uExponent = (isExponentNegative) ? -exponent : exponent;
2374 /* No thousand separators */
2375 flags &= ~FLAGS_QUOTE;
2376 }
2377 }
2378
2379 /*
2380 * Truncated number.
2381 *
2382 * precision is number of significant digits for FLOAT_G
2383 * and number of fractional digits for others
2384 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002385 integerDigits = (floor(number) > DBL_EPSILON)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002386 ? 1 + (int)guarded_log10(floor(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002387 : 1;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002388 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002389 ? precision - integerDigits
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002390 : zeroes + precision;
2391
2392 number = floor(0.5 + number * pow(dblBase, (double)fractionDigits));
2393 workNumber = (isHex
2394 ? guarded_log16(0.5 + number)
2395 : guarded_log10(0.5 + number));
2396 if ((int)workNumber + 1 > integerDigits + fractionDigits)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002397 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002398 if (flags & FLAGS_FLOAT_E)
2399 {
2400 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2401 exponent--;
2402 uExponent -= (isExponentNegative) ? 1 : -1;
2403 number /= dblBase;
2404 }
2405 else
2406 {
2407 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2408 integerDigits++;
2409 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002410 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002411
2412 /* Build the fraction part */
2413 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
2414 *numberPointer = NIL;
2415 onlyzero = TRUE;
2416 for (i = 0; i < fractionDigits; i++)
2417 {
2418 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2419 number = floor(number / dblBase);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002420
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002421 if ((flags & FLAGS_FLOAT_G) && !(flags & FLAGS_ALTERNATIVE))
2422 {
2423 /* Prune trailing zeroes */
2424 if (numberPointer[0] != digits[0])
2425 onlyzero = FALSE;
2426 else if (onlyzero && (numberPointer[0] == digits[0]))
2427 numberPointer++;
2428 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002429 else
2430 onlyzero = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002431 }
2432
2433 /* Insert decimal point */
2434 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
2435 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002436 i = StrLength(internalDecimalPoint);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002437 while (i> 0)
2438 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002439 *(--numberPointer) = internalDecimalPoint[--i];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002440 }
2441 }
2442 /* Insert the integer part and thousand separators */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002443 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002444 groupingIndex = 1;
2445 for (i = 1; i < integerDigits + 1; i++)
2446 {
2447 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2448 number = floor(number / dblBase);
2449 if (number < DBL_EPSILON)
2450 break;
2451
2452 if ((i > 0)
2453 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2454 && (charsPerThousand != NO_GROUPING)
2455 && (i % charsPerThousand == 0))
2456 {
2457 /*
2458 * We are building the number from the least significant
2459 * to the most significant digit, so we have to copy the
2460 * thousand separator backwards
2461 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002462 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002463 integerDigits += length;
2464 if (((int)(numberPointer - numberBuffer) - length) > 0)
2465 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002466 work = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002467 while (length-- > 0)
2468 *(--numberPointer) = *work--;
2469 }
2470
2471 /* Advance to next grouping number */
2472 if (charsPerThousand != NO_GROUPING)
2473 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002474 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002475 {
2476 case CHAR_MAX: /* Disable grouping */
2477 charsPerThousand = NO_GROUPING;
2478 break;
2479 case 0: /* Repeat last group */
2480 break;
2481 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002482 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002483 break;
2484 }
2485 }
2486 }
2487 }
2488
2489 /* Build the exponent */
2490 exponentDigits = 0;
2491 if (flags & FLAGS_FLOAT_E)
2492 {
2493 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2494 *exponentPointer-- = NIL;
2495 do {
2496 *exponentPointer-- = digits[uExponent % base];
2497 uExponent /= base;
2498 exponentDigits++;
2499 } while (uExponent);
2500 }
2501
Bjorn Reese70a9da52001-04-21 16:57:29 +00002502 /*
2503 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002504 * sign + integer part + thousands separators + decimal point
2505 * + fraction + exponent
2506 */
2507 expectedWidth = StrLength(numberPointer);
2508 if (isNegative || (flags & FLAGS_SHOWSIGN))
2509 expectedWidth += sizeof("-") - 1;
2510 if (exponentDigits > 0)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002511 expectedWidth += exponentDigits +
2512 ((exponentDigits > 1) ? sizeof("E+") : sizeof("E+0")) - 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002513 if (isHex)
2514 expectedWidth += sizeof("0X") - 1;
2515
2516 /* Output prefixing */
2517 if (flags & FLAGS_NILPADDING)
2518 {
2519 /* Leading zeros must be after sign */
2520 if (isNegative)
2521 self->OutStream(self, '-');
2522 else if (flags & FLAGS_SHOWSIGN)
2523 self->OutStream(self, '+');
2524 if (isHex)
2525 {
2526 self->OutStream(self, '0');
2527 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2528 }
2529 if (!(flags & FLAGS_LEFTADJUST))
2530 {
2531 for (i = expectedWidth; i < width; i++)
2532 {
2533 self->OutStream(self, '0');
2534 }
2535 }
2536 }
2537 else
2538 {
2539 /* Leading spaces must be before sign */
2540 if (!(flags & FLAGS_LEFTADJUST))
2541 {
2542 for (i = expectedWidth; i < width; i++)
2543 {
2544 self->OutStream(self, CHAR_ADJUST);
2545 }
2546 }
2547 if (isNegative)
2548 self->OutStream(self, '-');
2549 else if (flags & FLAGS_SHOWSIGN)
2550 self->OutStream(self, '+');
2551 if (isHex)
2552 {
2553 self->OutStream(self, '0');
2554 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2555 }
2556 }
2557 /* Output number */
2558 for (i = 0; numberPointer[i]; i++)
2559 {
2560 self->OutStream(self, numberPointer[i]);
2561 }
2562 /* Output exponent */
2563 if (exponentDigits > 0)
2564 {
2565 self->OutStream(self,
2566 isHex
2567 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2568 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2569 self->OutStream(self, (isExponentNegative) ? '-' : '+');
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002570
2571 /* The exponent must contain at least two digits */
2572 if (exponentDigits == 1)
2573 self->OutStream(self, '0');
2574
Daniel Veillard92ad2102001-03-27 12:47:33 +00002575 for (i = 0; i < exponentDigits; i++)
2576 {
2577 self->OutStream(self, exponentPointer[i + 1]);
2578 }
2579 }
2580 /* Output trailing spaces */
2581 if (flags & FLAGS_LEFTADJUST)
2582 {
2583 for (i = expectedWidth; i < width; i++)
2584 {
2585 self->OutStream(self, CHAR_ADJUST);
2586 }
2587 }
2588}
2589
2590/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002591 * TrioFormatProcess [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +00002592 */
2593static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002594TrioFormatProcess(trio_T *data,
2595 const char *format,
2596 parameter_T *parameters)
2597
Daniel Veillard92ad2102001-03-27 12:47:33 +00002598{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002599#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002600 int charlen;
2601#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00002602 int i;
2603 const char *string;
2604 void *pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002605 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002606 int width;
2607 int precision;
2608 int base;
2609 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002610
Daniel Veillard92ad2102001-03-27 12:47:33 +00002611 index = 0;
2612 i = 0;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002613#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002614 mblen(NULL, 0);
2615#endif
2616
2617 while (format[index])
2618 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002619#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002620 if (! isascii(format[index]))
2621 {
2622 charlen = mblen(&format[index], MB_LEN_MAX);
2623 while (charlen-- > 0)
2624 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002625 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002626 }
2627 continue; /* while */
2628 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002629#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002630 if (CHAR_IDENTIFIER == format[index])
2631 {
2632 if (CHAR_IDENTIFIER == format[index + 1])
2633 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002634 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002635 index += 2;
2636 }
2637 else
2638 {
2639 /* Skip the parameter entries */
2640 while (parameters[i].type == FORMAT_PARAMETER)
2641 i++;
2642
2643 flags = parameters[i].flags;
2644
2645 /* Find width */
2646 width = parameters[i].width;
2647 if (flags & FLAGS_WIDTH_PARAMETER)
2648 {
2649 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002650 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002651 }
2652
2653 /* Find precision */
2654 if (flags & FLAGS_PRECISION)
2655 {
2656 precision = parameters[i].precision;
2657 if (flags & FLAGS_PRECISION_PARAMETER)
2658 {
2659 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002660 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002661 }
2662 }
2663 else
2664 {
2665 precision = NO_PRECISION;
2666 }
2667
2668 /* Find base */
2669 base = parameters[i].base;
2670 if (flags & FLAGS_BASE_PARAMETER)
2671 {
2672 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002673 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002674 }
2675
2676 switch (parameters[i].type)
2677 {
2678 case FORMAT_CHAR:
2679 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002680 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002681 if (! (flags & FLAGS_LEFTADJUST))
2682 {
2683 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002684 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002685 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002686#if TRIO_WIDECHAR
2687 if (flags & FLAGS_WIDECHAR)
2688 {
2689 TrioWriteWideStringCharacter(data,
2690 (wchar_t)parameters[i].data.number.as_signed,
2691 flags,
2692 NO_WIDTH);
2693 }
2694 else
2695#endif
2696 TrioWriteStringCharacter(data,
2697 (int)parameters[i].data.number.as_signed,
2698 flags);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002699
2700 if (flags & FLAGS_LEFTADJUST)
2701 {
2702 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002703 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002704 }
2705 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002706 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002707
2708 break; /* FORMAT_CHAR */
2709
2710 case FORMAT_INT:
2711 if (base == NO_BASE)
2712 base = BASE_DECIMAL;
2713
2714 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 parameters[i].data.number.as_signed,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002716 flags,
2717 width,
2718 precision,
2719 base);
2720
2721 break; /* FORMAT_INT */
2722
2723 case FORMAT_DOUBLE:
2724 TrioWriteDouble(data,
2725 parameters[i].data.longdoubleNumber,
2726 flags,
2727 width,
2728 precision,
2729 base);
2730 break; /* FORMAT_DOUBLE */
2731
2732 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002733#if TRIO_WIDECHAR
2734 if (flags & FLAGS_WIDECHAR)
2735 {
2736 TrioWriteWideString(data,
2737 parameters[i].data.wstring,
2738 flags,
2739 width,
2740 precision);
2741 }
2742 else
2743#endif
2744 {
2745 TrioWriteString(data,
2746 parameters[i].data.string,
2747 flags,
2748 width,
2749 precision);
2750 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002751 break; /* FORMAT_STRING */
2752
2753 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002754 {
2755 reference_T reference;
2756
2757 reference.data = data;
2758 reference.parameter = &parameters[i];
2759 trio_print_pointer(&reference, parameters[i].data.pointer);
2760 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002761 break; /* FORMAT_POINTER */
2762
2763 case FORMAT_COUNT:
2764 pointer = parameters[i].data.pointer;
2765 if (NULL != pointer)
2766 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002767 /*
2768 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00002769 * characters written to the output stream so far by
2770 * this call", which is data->committed
2771 */
2772#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2773 if (flags & FLAGS_SIZE_T)
2774 *(size_t *)pointer = (size_t)data->committed;
2775 else
2776#endif
2777#if defined(QUALIFIER_PTRDIFF_T)
2778 if (flags & FLAGS_PTRDIFF_T)
2779 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2780 else
2781#endif
2782#if defined(QUALIFIER_INTMAX_T)
2783 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002784 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002785 else
2786#endif
2787 if (flags & FLAGS_QUAD)
2788 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002789 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002790 }
2791 else if (flags & FLAGS_LONG)
2792 {
2793 *(long int *)pointer = (long int)data->committed;
2794 }
2795 else if (flags & FLAGS_SHORT)
2796 {
2797 *(short int *)pointer = (short int)data->committed;
2798 }
2799 else
2800 {
2801 *(int *)pointer = (int)data->committed;
2802 }
2803 }
2804 break; /* FORMAT_COUNT */
2805
2806 case FORMAT_PARAMETER:
2807 break; /* FORMAT_PARAMETER */
2808
2809#if defined(FORMAT_ERRNO)
2810 case FORMAT_ERRNO:
2811 string = StrError(parameters[i].data.errorNumber);
2812 if (string)
2813 {
2814 TrioWriteString(data,
2815 string,
2816 flags,
2817 width,
2818 precision);
2819 }
2820 else
2821 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002822 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002823 TrioWriteNumber(data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00002824 (trio_intmax_t)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002825 flags,
2826 width,
2827 precision,
2828 BASE_DECIMAL);
2829 }
2830 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002831#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002832
Bjorn Reese70a9da52001-04-21 16:57:29 +00002833#if defined(FORMAT_USER_DEFINED)
2834 case FORMAT_USER_DEFINED:
2835 {
2836 reference_T reference;
2837 userdef_T *def = NULL;
2838
2839 if (parameters[i].user_name[0] == NIL)
2840 {
2841 /* Use handle */
2842 if ((i > 0) ||
2843 (parameters[i - 1].type == FORMAT_PARAMETER))
2844 def = (userdef_T *)parameters[i - 1].data.pointer;
2845 }
2846 else
2847 {
2848 /* Look up namespace */
2849 def = TrioFindNamespace(parameters[i].user_name, NULL);
2850 }
2851 if (def) {
2852 reference.data = data;
2853 reference.parameter = &parameters[i];
2854 def->callback(&reference);
2855 }
2856 }
2857 break;
2858#endif /* defined(FORMAT_USER_DEFINED) */
2859
Daniel Veillard92ad2102001-03-27 12:47:33 +00002860 default:
2861 break;
2862 } /* switch parameter type */
2863
2864 /* Prepare for next */
2865 index = parameters[i].indexAfterSpecifier;
2866 i++;
2867 }
2868 }
2869 else /* not identifier */
2870 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002871 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002872 }
2873 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 return data->processed;
2875}
2876
2877/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002878 * TrioFormatRef [private]
2879 */
2880static int
2881TrioFormatRef(reference_T *reference,
2882 const char *format,
2883 va_list arglist,
2884 void **argarray)
2885{
2886 int status;
2887 parameter_T parameters[MAX_PARAMETERS];
2888
2889 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2890 if (status < 0)
2891 return status;
2892
2893 return TrioFormatProcess(reference->data, format, parameters);
2894}
2895
2896/*************************************************************************
2897 * TrioFormat [private]
2898 *
2899 * Description:
2900 * This is the main engine for formatting output
2901 */
2902static int
2903TrioFormat(void *destination,
2904 size_t destinationSize,
2905 void (*OutStream)(trio_T *, int),
2906 const char *format,
2907 va_list arglist,
2908 void **argarray)
2909{
2910 int status;
2911 trio_T data;
2912 parameter_T parameters[MAX_PARAMETERS];
2913
2914 assert(VALID(OutStream));
2915 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00002916
2917 memset(&data, 0, sizeof(data));
2918 data.OutStream = OutStream;
2919 data.location = destination;
2920 data.max = destinationSize;
2921
2922#if defined(USE_LOCALE)
2923 if (NULL == internalLocaleValues)
2924 {
2925 TrioSetLocale();
2926 }
2927#endif
2928
2929 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2930 if (status < 0)
2931 return status;
2932
2933 return TrioFormatProcess(&data, format, parameters);
2934}
2935
2936/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002937 * TrioOutStreamFile [private]
2938 */
2939static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002940TrioOutStreamFile(trio_T *self,
2941 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002942{
2943 FILE *file = (FILE *)self->location;
2944
2945 assert(VALID(self));
2946 assert(VALID(file));
2947
2948 self->processed++;
2949 self->committed++;
2950 (void)fputc(output, file);
2951}
2952
2953/*************************************************************************
2954 * TrioOutStreamFileDescriptor [private]
2955 */
2956static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002957TrioOutStreamFileDescriptor(trio_T *self,
2958 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002959{
2960 int fd = *((int *)self->location);
2961 char ch;
2962
2963 assert(VALID(self));
2964
2965 ch = (char)output;
2966 (void)write(fd, &ch, sizeof(char));
2967 self->processed++;
2968 self->committed++;
2969}
2970
2971/*************************************************************************
2972 * TrioOutStreamString [private]
2973 */
2974static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002975TrioOutStreamString(trio_T *self,
2976 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002977{
2978 char **buffer = (char **)self->location;
2979
2980 assert(VALID(self));
2981 assert(VALID(buffer));
2982
2983 **buffer = (char)output;
2984 (*buffer)++;
2985 self->processed++;
2986 self->committed++;
2987}
2988
2989/*************************************************************************
2990 * TrioOutStreamStringMax [private]
2991 */
2992static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002993TrioOutStreamStringMax(trio_T *self,
2994 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002995{
2996 char **buffer;
2997
2998 assert(VALID(self));
2999 buffer = (char **)self->location;
3000 assert(VALID(buffer));
3001
3002 if (self->processed < self->max)
3003 {
3004 **buffer = (char)output;
3005 (*buffer)++;
3006 self->committed++;
3007 }
3008 self->processed++;
3009}
3010
3011/*************************************************************************
3012 * TrioOutStreamStringDynamic [private]
3013 */
3014#define DYNAMIC_START_SIZE 32
3015struct dynamicBuffer {
3016 char *buffer;
3017 size_t length;
3018 size_t allocated;
3019};
3020
3021static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00003022TrioOutStreamStringDynamic(trio_T *self,
3023 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003024{
3025 struct dynamicBuffer *infop;
3026
3027 assert(VALID(self));
3028 assert(VALID(self->location));
3029
3030 infop = (struct dynamicBuffer *)self->location;
3031
3032 if (infop->buffer == NULL)
3033 {
3034 /* Start with a reasonable size */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003035 infop->buffer = (char *)TRIO_MALLOC(DYNAMIC_START_SIZE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003036 if (infop->buffer == NULL)
3037 return; /* fail */
3038
3039 infop->allocated = DYNAMIC_START_SIZE;
3040 self->processed = 0;
3041 self->committed = 0;
3042 }
3043 else if (self->committed + sizeof(NIL) >= infop->allocated)
3044 {
3045 char *newptr;
3046
3047 /* Allocate increasing chunks */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003048 newptr = (char *)TRIO_REALLOC(infop->buffer, infop->allocated * 2);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003049
3050 if (newptr == NULL)
3051 return;
3052
3053 infop->buffer = newptr;
3054 infop->allocated *= 2;
3055 }
3056
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003057 infop->buffer[self->committed] = (char)output;
Daniel Veillard92ad2102001-03-27 12:47:33 +00003058 self->committed++;
3059 self->processed++;
3060
3061 infop->length = self->committed;
3062}
3063
Daniel Veillard92ad2102001-03-27 12:47:33 +00003064/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003065 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003066 */
3067int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003068trio_printf(const char *format,
3069 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003070{
3071 int status;
3072 va_list args;
3073
3074 assert(VALID(format));
3075
3076 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003077 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003078 va_end(args);
3079 return status;
3080}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003081
Bjorn Reese70a9da52001-04-21 16:57:29 +00003082int
3083trio_vprintf(const char *format,
3084 va_list args)
3085{
3086 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003087
3088 return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
3089}
3090
3091int
3092trio_printfv(const char *format,
3093 void ** args)
3094{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003095 va_list dummy;
3096
Bjorn Reese70a9da52001-04-21 16:57:29 +00003097 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003098
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003099 return TrioFormat(stdout, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003100}
3101
Daniel Veillard92ad2102001-03-27 12:47:33 +00003102/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003103 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003104 */
3105int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003106trio_fprintf(FILE *file,
3107 const char *format,
3108 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003109{
3110 int status;
3111 va_list args;
3112
3113 assert(VALID(file));
3114 assert(VALID(format));
3115
3116 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003117 status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003118 va_end(args);
3119 return status;
3120}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003121
Daniel Veillard92ad2102001-03-27 12:47:33 +00003122int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003123trio_vfprintf(FILE *file,
3124 const char *format,
3125 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003126{
3127 assert(VALID(file));
3128 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003129
Bjorn Reese70a9da52001-04-21 16:57:29 +00003130 return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003131}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003132
Bjorn Reese70a9da52001-04-21 16:57:29 +00003133int
3134trio_fprintfv(FILE *file,
3135 const char *format,
3136 void ** args)
3137{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003138 va_list dummy;
3139
Bjorn Reese70a9da52001-04-21 16:57:29 +00003140 assert(VALID(file));
3141 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003142
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003143 return TrioFormat(file, 0, TrioOutStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003144}
3145
Daniel Veillard92ad2102001-03-27 12:47:33 +00003146/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003147 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003148 */
3149int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003150trio_dprintf(int fd,
3151 const char *format,
3152 ...)
3153{
3154 int status;
3155 va_list args;
3156
3157 assert(VALID(format));
3158
3159 va_start(args, format);
3160 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3161 va_end(args);
3162 return status;
3163}
3164
3165int
3166trio_vdprintf(int fd,
3167 const char *format,
3168 va_list args)
3169{
3170 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003171
3172 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
3173}
3174
3175int
3176trio_dprintfv(int fd,
3177 const char *format,
3178 void **args)
3179{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003180 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003181
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003182 assert(VALID(format));
3183
3184 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003185}
3186
3187/*************************************************************************
3188 * sprintf
3189 */
3190int
3191trio_sprintf(char *buffer,
3192 const char *format,
3193 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003194{
3195 int status;
3196 va_list args;
3197
3198 assert(VALID(buffer));
3199 assert(VALID(format));
3200
3201 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003202 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003203 *buffer = NIL; /* Terminate with NIL character */
3204 va_end(args);
3205 return status;
3206}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003207
Daniel Veillard92ad2102001-03-27 12:47:33 +00003208int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003209trio_vsprintf(char *buffer,
3210 const char *format,
3211 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003212{
3213 int status;
3214
3215 assert(VALID(buffer));
3216 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003217
Bjorn Reese70a9da52001-04-21 16:57:29 +00003218 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003219 *buffer = NIL;
3220 return status;
3221}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003222
Bjorn Reese70a9da52001-04-21 16:57:29 +00003223int
3224trio_sprintfv(char *buffer,
3225 const char *format,
3226 void **args)
3227{
3228 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003229 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003230
3231 assert(VALID(buffer));
3232 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003233
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003234 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003235 *buffer = NIL;
3236 return status;
3237}
3238
Daniel Veillard92ad2102001-03-27 12:47:33 +00003239/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00003240 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00003241 */
3242int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003243trio_snprintf(char *buffer,
3244 size_t bufferSize,
3245 const char *format,
3246 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003247{
3248 int status;
3249 va_list args;
3250
3251 assert(VALID(buffer));
3252 assert(VALID(format));
3253
3254 va_start(args, format);
3255 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003256 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003257 if (bufferSize > 0)
3258 *buffer = NIL;
3259 va_end(args);
3260 return status;
3261}
Daniel Veillard92ad2102001-03-27 12:47:33 +00003262
Daniel Veillard92ad2102001-03-27 12:47:33 +00003263int
Bjorn Reese70a9da52001-04-21 16:57:29 +00003264trio_vsnprintf(char *buffer,
3265 size_t bufferSize,
3266 const char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003267 va_list args)
3268{
3269 int status;
3270
3271 assert(VALID(buffer));
3272 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00003273
3274 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003275 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00003276 if (bufferSize > 0)
3277 *buffer = NIL;
3278 return status;
3279}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003280
3281int
3282trio_snprintfv(char *buffer,
3283 size_t bufferSize,
3284 const char *format,
3285 void **args)
3286{
3287 int status;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003288 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00003289
3290 assert(VALID(buffer));
3291 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003292
3293 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003294 TrioOutStreamStringMax, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003295 if (bufferSize > 0)
3296 *buffer = NIL;
3297 return status;
3298}
3299
3300/*************************************************************************
3301 * snprintfcat
3302 * Appends the new string to the buffer string overwriting the '\0'
3303 * character at the end of buffer.
3304 */
3305int
3306trio_snprintfcat(char *buffer,
3307 size_t bufferSize,
3308 const char *format,
3309 ...)
3310{
3311 int status;
3312 va_list args;
3313 size_t buf_len;
3314
3315 va_start(args, format);
3316
3317 assert(VALID(buffer));
3318 assert(VALID(format));
3319
3320 buf_len = strlen(buffer);
3321 buffer = &buffer[buf_len];
3322
3323 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3324 TrioOutStreamStringMax, format, args, NULL);
3325 va_end(args);
3326 *buffer = NIL;
3327 return status;
3328}
3329
3330int
3331trio_vsnprintfcat(char *buffer,
3332 size_t bufferSize,
3333 const char *format,
3334 va_list args)
3335{
3336 int status;
3337 size_t buf_len;
3338 assert(VALID(buffer));
3339 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003340
3341 buf_len = strlen(buffer);
3342 buffer = &buffer[buf_len];
3343 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3344 TrioOutStreamStringMax, format, args, NULL);
3345 *buffer = NIL;
3346 return status;
3347}
3348
3349/*************************************************************************
3350 * trio_aprintf
3351 */
3352
3353/* Deprecated */
3354char *
3355trio_aprintf(const char *format,
3356 ...)
3357{
3358 va_list args;
3359 struct dynamicBuffer info;
3360
3361 assert(VALID(format));
3362
3363 info.buffer = NULL;
3364 info.length = 0;
3365 info.allocated = 0;
3366
3367 va_start(args, format);
3368 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3369 va_end(args);
3370 if (info.length) {
3371 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3372 return info.buffer;
3373 }
3374 else
3375 return NULL;
3376}
3377
3378/* Deprecated */
3379char *
3380trio_vaprintf(const char *format,
3381 va_list args)
3382{
3383 struct dynamicBuffer info;
3384
3385 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003386
3387 info.buffer = NULL;
3388 info.length = 0;
3389 info.allocated = 0;
3390
3391 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3392 if (info.length) {
3393 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3394 return info.buffer;
3395 }
3396 else
3397 return NULL;
3398}
3399
3400int
3401trio_asprintf(char **result,
3402 const char *format,
3403 ...)
3404{
3405 va_list args;
3406 int status;
3407 struct dynamicBuffer info;
3408
3409 assert(VALID(format));
3410
3411 info.buffer = NULL;
3412 info.length = 0;
3413 info.allocated = 0;
3414
3415 va_start(args, format);
3416 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3417 va_end(args);
3418 if (status < 0) {
3419 *result = NULL;
3420 return status;
3421 }
3422 if (info.length == 0) {
3423 /*
3424 * If the length is zero, no characters have been written and therefore
3425 * no memory has been allocated, but we must to allocate and return an
3426 * empty string.
3427 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003428 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003429 if (info.buffer == NULL) {
3430 *result = NULL;
3431 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3432 }
3433 }
3434 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3435 *result = info.buffer;
3436
3437 return status;
3438}
3439
3440int
3441trio_vasprintf(char **result,
3442 const char *format,
3443 va_list args)
3444{
3445 int status;
3446 struct dynamicBuffer info;
3447
3448 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003449
3450 info.buffer = NULL;
3451 info.length = 0;
3452 info.allocated = 0;
3453
3454 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3455 if (status < 0) {
3456 *result = NULL;
3457 return status;
3458 }
3459 if (info.length == 0) {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003460 info.buffer = (char *)TRIO_MALLOC(sizeof(char));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003461 if (info.buffer == NULL) {
3462 *result = NULL;
3463 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3464 }
3465 }
3466 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3467 *result = info.buffer;
3468
3469 return status;
3470}
3471
Daniel Veillard92ad2102001-03-27 12:47:33 +00003472
3473/*************************************************************************
3474 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003475 * @CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00003476 *
3477 ************************************************************************/
3478
Bjorn Reese70a9da52001-04-21 16:57:29 +00003479
3480/*************************************************************************
3481 * trio_register [public]
3482 */
3483void *
3484trio_register(trio_callback_t callback,
3485 const char *name)
3486{
3487 userdef_T *def;
3488 userdef_T *prev = NULL;
3489
3490 if (callback == NULL)
3491 return NULL;
3492
3493 if (name)
3494 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003495 /* Handle built-in namespaces */
3496 if (name[0] == ':')
3497 {
3498 if (StrEqual(name, ":enter"))
3499 {
3500 internalEnterCriticalRegion = callback;
3501 }
3502 else if (StrEqual(name, ":leave"))
3503 {
3504 internalLeaveCriticalRegion = callback;
3505 }
3506 return NULL;
3507 }
3508
Bjorn Reese70a9da52001-04-21 16:57:29 +00003509 /* Bail out if namespace is too long */
3510 if (StrLength(name) >= MAX_USER_NAME)
3511 return NULL;
3512
3513 /* Bail out if namespace already is registered */
3514 def = TrioFindNamespace(name, &prev);
3515 if (def)
3516 return NULL;
3517 }
3518
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003519 def = (userdef_T *)TRIO_MALLOC(sizeof(userdef_T));
Bjorn Reese70a9da52001-04-21 16:57:29 +00003520 if (def)
3521 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003522 if (internalEnterCriticalRegion)
3523 (void)internalEnterCriticalRegion(NULL);
3524
Bjorn Reese70a9da52001-04-21 16:57:29 +00003525 if (name)
3526 {
3527 /* Link into internal list */
3528 if (prev == NULL)
3529 internalUserDef = def;
3530 else
3531 prev->next = def;
3532 }
3533 /* Initialize */
3534 def->callback = callback;
3535 def->name = (name == NULL)
3536 ? NULL
3537 : StrDuplicate(name);
3538 def->next = NULL;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003539
3540 if (internalLeaveCriticalRegion)
3541 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003542 }
3543 return def;
3544}
3545
3546/*************************************************************************
3547 * trio_unregister [public]
3548 */
3549void
3550trio_unregister(void *handle)
3551{
3552 userdef_T *self = (userdef_T *)handle;
3553 userdef_T *def;
3554 userdef_T *prev = NULL;
3555
3556 assert(VALID(self));
3557
3558 if (self->name)
3559 {
3560 def = TrioFindNamespace(self->name, &prev);
3561 if (def)
3562 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003563 if (internalEnterCriticalRegion)
3564 (void)internalEnterCriticalRegion(NULL);
3565
Bjorn Reese70a9da52001-04-21 16:57:29 +00003566 if (prev == NULL)
3567 internalUserDef = NULL;
3568 else
3569 prev->next = def->next;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003570
3571 if (internalLeaveCriticalRegion)
3572 (void)internalLeaveCriticalRegion(NULL);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003573 }
3574 StrFree(self->name);
3575 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003576 TRIO_FREE(self);
Bjorn Reese70a9da52001-04-21 16:57:29 +00003577}
3578
3579/*************************************************************************
3580 * trio_get_format [public]
3581 */
3582const char *
3583trio_get_format(void *ref)
3584{
3585 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3586
3587 return (((reference_T *)ref)->parameter->user_data);
3588}
3589
3590/*************************************************************************
3591 * trio_get_argument [public]
3592 */
3593void *
3594trio_get_argument(void *ref)
3595{
3596 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3597
3598 return ((reference_T *)ref)->parameter->data.pointer;
3599}
3600
3601/*************************************************************************
3602 * trio_get_width / trio_set_width [public]
3603 */
3604int
3605trio_get_width(void *ref)
3606{
3607 return ((reference_T *)ref)->parameter->width;
3608}
3609
3610void
3611trio_set_width(void *ref,
3612 int width)
3613{
3614 ((reference_T *)ref)->parameter->width = width;
3615}
3616
3617/*************************************************************************
3618 * trio_get_precision / trio_set_precision [public]
3619 */
3620int
3621trio_get_precision(void *ref)
3622{
3623 return (((reference_T *)ref)->parameter->precision);
3624}
3625
3626void
3627trio_set_precision(void *ref,
3628 int precision)
3629{
3630 ((reference_T *)ref)->parameter->precision = precision;
3631}
3632
3633/*************************************************************************
3634 * trio_get_base / trio_set_base [public]
3635 */
3636int
3637trio_get_base(void *ref)
3638{
3639 return (((reference_T *)ref)->parameter->base);
3640}
3641
3642void
3643trio_set_base(void *ref,
3644 int base)
3645{
3646 ((reference_T *)ref)->parameter->base = base;
3647}
3648
3649/*************************************************************************
3650 * trio_get_long / trio_set_long [public]
3651 */
3652int
3653trio_get_long(void *ref)
3654{
3655 return (((reference_T *)ref)->parameter->flags & FLAGS_LONG);
3656}
3657
3658void
3659trio_set_long(void *ref,
3660 int is_long)
3661{
3662 if (is_long)
3663 ((reference_T *)ref)->parameter->flags |= FLAGS_LONG;
3664 else
3665 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONG;
3666}
3667
3668/*************************************************************************
3669 * trio_get_longlong / trio_set_longlong [public]
3670 */
3671int
3672trio_get_longlong(void *ref)
3673{
3674 return (((reference_T *)ref)->parameter->flags & FLAGS_QUAD);
3675}
3676
3677void
3678trio_set_longlong(void *ref,
3679 int is_longlong)
3680{
3681 if (is_longlong)
3682 ((reference_T *)ref)->parameter->flags |= FLAGS_QUAD;
3683 else
3684 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUAD;
3685}
3686
3687/*************************************************************************
3688 * trio_get_longdouble / trio_set_longdouble [public]
3689 */
3690int
3691trio_get_longdouble(void *ref)
3692{
3693 return (((reference_T *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
3694}
3695
3696void
3697trio_set_longdouble(void *ref,
3698 int is_longdouble)
3699{
3700 if (is_longdouble)
3701 ((reference_T *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
3702 else
3703 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
3704}
3705
3706/*************************************************************************
3707 * trio_get_short / trio_set_short [public]
3708 */
3709int
3710trio_get_short(void *ref)
3711{
3712 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORT);
3713}
3714
3715void
3716trio_set_short(void *ref,
3717 int is_short)
3718{
3719 if (is_short)
3720 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORT;
3721 else
3722 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORT;
3723}
3724
3725/*************************************************************************
3726 * trio_get_shortshort / trio_set_shortshort [public]
3727 */
3728int
3729trio_get_shortshort(void *ref)
3730{
3731 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORTSHORT);
3732}
3733
3734void
3735trio_set_shortshort(void *ref,
3736 int is_shortshort)
3737{
3738 if (is_shortshort)
3739 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
3740 else
3741 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
3742}
3743
3744/*************************************************************************
3745 * trio_get_alternative / trio_set_alternative [public]
3746 */
3747int
3748trio_get_alternative(void *ref)
3749{
3750 return (((reference_T *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
3751}
3752
3753void
3754trio_set_alternative(void *ref,
3755 int is_alternative)
3756{
3757 if (is_alternative)
3758 ((reference_T *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
3759 else
3760 ((reference_T *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
3761}
3762
3763/*************************************************************************
3764 * trio_get_alignment / trio_set_alignment [public]
3765 */
3766int
3767trio_get_alignment(void *ref)
3768{
3769 return (((reference_T *)ref)->parameter->flags & FLAGS_LEFTADJUST);
3770}
3771
3772void
3773trio_set_alignment(void *ref,
3774 int is_leftaligned)
3775{
3776 if (is_leftaligned)
3777 ((reference_T *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
3778 else
3779 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
3780}
3781
3782/*************************************************************************
3783 * trio_get_spacing /trio_set_spacing [public]
3784 */
3785int
3786trio_get_spacing(void *ref)
3787{
3788 return (((reference_T *)ref)->parameter->flags & FLAGS_SPACE);
3789}
3790
3791void
3792trio_set_spacing(void *ref,
3793 int is_space)
3794{
3795 if (is_space)
3796 ((reference_T *)ref)->parameter->flags |= FLAGS_SPACE;
3797 else
3798 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SPACE;
3799}
3800
3801/*************************************************************************
3802 * trio_get_sign / trio_set_sign [public]
3803 */
3804int
3805trio_get_sign(void *ref)
3806{
3807 return (((reference_T *)ref)->parameter->flags & FLAGS_SHOWSIGN);
3808}
3809
3810void
3811trio_set_sign(void *ref,
3812 int is_sign)
3813{
3814 if (is_sign)
3815 ((reference_T *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
3816 else
3817 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
3818}
3819
3820/*************************************************************************
3821 * trio_get_padding / trio_set_padding [public]
3822 */
3823int
3824trio_get_padding(void *ref)
3825{
3826 return (((reference_T *)ref)->parameter->flags & FLAGS_NILPADDING);
3827}
3828
3829void
3830trio_set_padding(void *ref,
3831 int is_padding)
3832{
3833 if (is_padding)
3834 ((reference_T *)ref)->parameter->flags |= FLAGS_NILPADDING;
3835 else
3836 ((reference_T *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
3837}
3838
3839/*************************************************************************
3840 * trio_get_quote / trio_set_quote [public]
3841 */
3842int
3843trio_get_quote(void *ref)
3844{
3845 return (((reference_T *)ref)->parameter->flags & FLAGS_QUOTE);
3846}
3847
3848void
3849trio_set_quote(void *ref,
3850 int is_quote)
3851{
3852 if (is_quote)
3853 ((reference_T *)ref)->parameter->flags |= FLAGS_QUOTE;
3854 else
3855 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUOTE;
3856}
3857
3858/*************************************************************************
3859 * trio_get_upper / trio_set_upper [public]
3860 */
3861int
3862trio_get_upper(void *ref)
3863{
3864 return (((reference_T *)ref)->parameter->flags & FLAGS_UPPER);
3865}
3866
3867void
3868trio_set_upper(void *ref,
3869 int is_upper)
3870{
3871 if (is_upper)
3872 ((reference_T *)ref)->parameter->flags |= FLAGS_UPPER;
3873 else
3874 ((reference_T *)ref)->parameter->flags &= ~FLAGS_UPPER;
3875}
3876
3877/*************************************************************************
3878 * trio_get_largest / trio_set_largest [public]
3879 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003880#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00003881int
3882trio_get_largest(void *ref)
3883{
3884 return (((reference_T *)ref)->parameter->flags & FLAGS_INTMAX_T);
3885}
3886
3887void
3888trio_set_largest(void *ref,
3889 int is_largest)
3890{
3891 if (is_largest)
3892 ((reference_T *)ref)->parameter->flags |= FLAGS_INTMAX_T;
3893 else
3894 ((reference_T *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
3895}
3896#endif
3897
3898/*************************************************************************
3899 * trio_get_ptrdiff / trio_set_ptrdiff [public]
3900 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00003901int
3902trio_get_ptrdiff(void *ref)
3903{
3904 return (((reference_T *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
3905}
3906
3907void
3908trio_set_ptrdiff(void *ref,
3909 int is_ptrdiff)
3910{
3911 if (is_ptrdiff)
3912 ((reference_T *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
3913 else
3914 ((reference_T *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
3915}
Bjorn Reese70a9da52001-04-21 16:57:29 +00003916
3917/*************************************************************************
3918 * trio_get_size / trio_set_size [public]
3919 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003920#if TRIO_C99
Bjorn Reese70a9da52001-04-21 16:57:29 +00003921int
3922trio_get_size(void *ref)
3923{
3924 return (((reference_T *)ref)->parameter->flags & FLAGS_SIZE_T);
3925}
3926
3927void
3928trio_set_size(void *ref,
3929 int is_size)
3930{
3931 if (is_size)
3932 ((reference_T *)ref)->parameter->flags |= FLAGS_SIZE_T;
3933 else
3934 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
3935}
3936#endif
3937
3938/*************************************************************************
3939 * trio_print_int [public]
3940 */
3941void
3942trio_print_int(void *ref,
3943 int number)
3944{
3945 reference_T *self = (reference_T *)ref;
3946
3947 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003948 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003949 self->parameter->flags,
3950 self->parameter->width,
3951 self->parameter->precision,
3952 self->parameter->base);
3953}
3954
3955/*************************************************************************
3956 * trio_print_uint [public]
3957 */
3958void
3959trio_print_uint(void *ref,
3960 unsigned int number)
3961{
3962 reference_T *self = (reference_T *)ref;
3963
3964 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00003965 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00003966 self->parameter->flags | FLAGS_UNSIGNED,
3967 self->parameter->width,
3968 self->parameter->precision,
3969 self->parameter->base);
3970}
3971
3972/*************************************************************************
3973 * trio_print_double [public]
3974 */
3975void
3976trio_print_double(void *ref,
3977 double number)
3978{
3979 reference_T *self = (reference_T *)ref;
3980
3981 TrioWriteDouble(self->data,
3982 number,
3983 self->parameter->flags,
3984 self->parameter->width,
3985 self->parameter->precision,
3986 self->parameter->base);
3987}
3988
3989/*************************************************************************
3990 * trio_print_string [public]
3991 */
3992void
3993trio_print_string(void *ref,
3994 char *string)
3995{
3996 reference_T *self = (reference_T *)ref;
3997
3998 TrioWriteString(self->data,
3999 string,
4000 self->parameter->flags,
4001 self->parameter->width,
4002 self->parameter->precision);
4003}
4004
4005/*************************************************************************
4006 * trio_print_pointer [public]
4007 */
4008void
4009trio_print_pointer(void *ref,
4010 void *pointer)
4011{
4012 reference_T *self = (reference_T *)ref;
4013 unsigned long flags;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004014 trio_uintmax_t number;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004015
4016 if (NULL == pointer)
4017 {
4018 const char *string = null;
4019 while (*string)
4020 self->data->OutStream(self->data, *string++);
4021 }
4022 else
4023 {
4024 /*
4025 * The subtraction of the null pointer is a workaround
4026 * to avoid a compiler warning. The performance overhead
4027 * is negligible (and likely to be removed by an
4028 * optimising compiler). The (char *) casting is done
4029 * to please ANSI C++.
4030 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004031 number = (trio_uintmax_t)((char *)pointer - (char *)0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004032 /* Shrink to size of pointer */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004033 number &= (trio_uintmax_t)-1;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004034 flags = self->parameter->flags;
4035 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4036 FLAGS_NILPADDING);
4037 TrioWriteNumber(self->data,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004038 (trio_intmax_t)number,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004039 flags,
4040 POINTER_WIDTH,
4041 NO_PRECISION,
4042 BASE_HEX);
4043 }
4044}
4045
4046/*************************************************************************
4047 * trio_print_ref [public]
4048 */
4049int
4050trio_print_ref(void *ref,
4051 const char *format,
4052 ...)
4053{
4054 int status;
4055 va_list arglist;
4056
4057 assert(VALID(format));
4058
4059 va_start(arglist, format);
4060 status = TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4061 va_end(arglist);
4062 return status;
4063}
4064
4065/*************************************************************************
4066 * trio_vprint_ref [public]
4067 */
4068int
4069trio_vprint_ref(void *ref,
4070 const char *format,
4071 va_list arglist)
4072{
4073 assert(VALID(format));
4074
4075 return TrioFormatRef((reference_T *)ref, format, arglist, NULL);
4076}
4077
4078/*************************************************************************
4079 * trio_printv_ref [public]
4080 */
4081int
4082trio_printv_ref(void *ref,
4083 const char *format,
4084 void **argarray)
4085{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004086 va_list dummy;
4087
Bjorn Reese70a9da52001-04-21 16:57:29 +00004088 assert(VALID(format));
4089
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004090 return TrioFormatRef((reference_T *)ref, format, dummy, argarray);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004091}
4092
4093
4094/*************************************************************************
4095 *
4096 * @SCANNING
4097 *
4098 ************************************************************************/
4099
Daniel Veillard92ad2102001-03-27 12:47:33 +00004100
4101/*************************************************************************
4102 * TrioSkipWhitespaces [private]
4103 */
4104static int
4105TrioSkipWhitespaces(trio_T *self)
4106{
4107 int ch;
4108
4109 ch = self->current;
4110 while (isspace(ch))
4111 {
4112 self->InStream(self, &ch);
4113 }
4114 return ch;
4115}
4116
4117/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004118 * TrioGetCollation [private]
4119 */
4120#if TRIO_EXTENSION
4121static void
4122TrioGetCollation()
4123{
4124 int i;
4125 int j;
4126 int k;
4127 char first[2];
4128 char second[2];
4129
4130 /* This is computational expensive */
4131 first[1] = NIL;
4132 second[1] = NIL;
4133 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4134 {
4135 k = 0;
4136 first[0] = (char)i;
4137 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
4138 {
4139 second[0] = (char)j;
4140 if (StrEqualLocale(first, second))
4141 internalCollationArray[i][k++] = (char)j;
4142 }
4143 internalCollationArray[i][k] = NIL;
4144 }
4145}
4146#endif
4147
4148/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004149 * TrioGetCharacterClass [private]
4150 *
4151 * FIXME:
4152 * multibyte
4153 */
4154static int
4155TrioGetCharacterClass(const char *format,
4156 int *indexPointer,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004157 unsigned long *flagsPointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004158 int *characterclass)
4159{
4160 int index = *indexPointer;
4161 int i;
4162 char ch;
4163 char range_begin;
4164 char range_end;
4165
4166 *flagsPointer &= ~FLAGS_EXCLUDE;
4167
4168 if (format[index] == QUALIFIER_CIRCUMFLEX)
4169 {
4170 *flagsPointer |= FLAGS_EXCLUDE;
4171 index++;
4172 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004173 /*
4174 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004175 * it will be part of the class, and a second ungroup character
4176 * must follow to end the group.
4177 */
4178 if (format[index] == SPECIFIER_UNGROUP)
4179 {
4180 characterclass[(int)SPECIFIER_UNGROUP]++;
4181 index++;
4182 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004183 /*
4184 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004185 * it must be at the beginning of the list
4186 */
4187 if (format[index] == QUALIFIER_MINUS)
4188 {
4189 characterclass[(int)QUALIFIER_MINUS]++;
4190 index++;
4191 }
4192 /* Collect characters */
4193 for (ch = format[index];
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004194 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004195 ch = format[++index])
4196 {
4197 switch (ch)
4198 {
4199 case QUALIFIER_MINUS: /* Scanlist ranges */
4200
Bjorn Reese70a9da52001-04-21 16:57:29 +00004201 /*
4202 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00004203 * defined.
4204 *
4205 * We support the following behaviour (although this may
4206 * change as we become wiser)
4207 * - only increasing ranges, ie. [a-b] but not [b-a]
4208 * - transitive ranges, ie. [a-b-c] == [a-c]
4209 * - trailing minus, ie. [a-] is interpreted as an 'a'
4210 * and a '-'
4211 * - duplicates (although we can easily convert these
4212 * into errors)
4213 */
4214 range_begin = format[index - 1];
4215 range_end = format[++index];
4216 if (range_end == SPECIFIER_UNGROUP)
4217 {
4218 /* Trailing minus is included */
4219 characterclass[(int)ch]++;
4220 ch = range_end;
4221 break; /* for */
4222 }
4223 if (range_end == NIL)
4224 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4225 if (range_begin > range_end)
4226 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
4227
4228 for (i = (int)range_begin; i <= (int)range_end; i++)
4229 characterclass[i]++;
4230
4231 ch = range_end;
4232 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004233
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004234#if TRIO_EXTENSION
4235
4236 case SPECIFIER_GROUP:
4237
4238 switch (format[index + 1])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004239 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004240 case QUALIFIER_DOT: /* Collating symbol */
4241 /*
4242 * FIXME: This will be easier to implement when multibyte
4243 * characters have been implemented. Until now, we ignore
4244 * this feature.
4245 */
4246 for (i = index + 2; ; i++)
4247 {
4248 if (format[i] == NIL)
4249 /* Error in syntax */
4250 return -1;
4251 else if (format[i] == QUALIFIER_DOT)
4252 break; /* for */
4253 }
4254 if (format[++i] != SPECIFIER_UNGROUP)
4255 return -1;
4256
4257 index = i;
4258 break;
4259
4260 case QUALIFIER_EQUAL: /* Equivalence class expressions */
4261 {
4262 unsigned int j;
4263 unsigned int k;
4264
4265 if (internalCollationUnconverted)
4266 {
4267 /* Lazy evalutation of collation array */
4268 TrioGetCollation();
4269 internalCollationUnconverted = FALSE;
4270 }
4271 for (i = index + 2; ; i++)
4272 {
4273 if (format[i] == NIL)
4274 /* Error in syntax */
4275 return -1;
4276 else if (format[i] == QUALIFIER_EQUAL)
4277 break; /* for */
4278 else
4279 {
4280 /* Mark any equivalent character */
4281 k = (unsigned int)format[i];
4282 for (j = 0; internalCollationArray[k][j] != NIL; j++)
4283 characterclass[(int)internalCollationArray[k][j]]++;
4284 }
4285 }
4286 if (format[++i] != SPECIFIER_UNGROUP)
4287 return -1;
4288
4289 index = i;
4290 }
4291 break;
4292
4293 case QUALIFIER_COLON: /* Character class expressions */
4294
4295 if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
4296 &format[index]))
4297 {
4298 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4299 if (isalnum(i))
4300 characterclass[i]++;
4301 index += sizeof(CLASS_ALNUM) - 1;
4302 }
4303 else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
4304 &format[index]))
4305 {
4306 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4307 if (isalpha(i))
4308 characterclass[i]++;
4309 index += sizeof(CLASS_ALPHA) - 1;
4310 }
4311 else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
4312 &format[index]))
4313 {
4314 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4315 if (iscntrl(i))
4316 characterclass[i]++;
4317 index += sizeof(CLASS_CNTRL) - 1;
4318 }
4319 else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
4320 &format[index]))
4321 {
4322 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4323 if (isdigit(i))
4324 characterclass[i]++;
4325 index += sizeof(CLASS_DIGIT) - 1;
4326 }
4327 else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
4328 &format[index]))
4329 {
4330 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4331 if (isgraph(i))
4332 characterclass[i]++;
4333 index += sizeof(CLASS_GRAPH) - 1;
4334 }
4335 else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
4336 &format[index]))
4337 {
4338 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4339 if (islower(i))
4340 characterclass[i]++;
4341 index += sizeof(CLASS_LOWER) - 1;
4342 }
4343 else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
4344 &format[index]))
4345 {
4346 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4347 if (isprint(i))
4348 characterclass[i]++;
4349 index += sizeof(CLASS_PRINT) - 1;
4350 }
4351 else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
4352 &format[index]))
4353 {
4354 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4355 if (ispunct(i))
4356 characterclass[i]++;
4357 index += sizeof(CLASS_PUNCT) - 1;
4358 }
4359 else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
4360 &format[index]))
4361 {
4362 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4363 if (isspace(i))
4364 characterclass[i]++;
4365 index += sizeof(CLASS_SPACE) - 1;
4366 }
4367 else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
4368 &format[index]))
4369 {
4370 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4371 if (isupper(i))
4372 characterclass[i]++;
4373 index += sizeof(CLASS_UPPER) - 1;
4374 }
4375 else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
4376 &format[index]))
4377 {
4378 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
4379 if (isxdigit(i))
4380 characterclass[i]++;
4381 index += sizeof(CLASS_XDIGIT) - 1;
4382 }
4383 else
4384 {
4385 characterclass[(int)ch]++;
4386 }
4387 break;
4388
4389 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004390 characterclass[(int)ch]++;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004391 break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004392 }
4393 break;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004394
4395#endif /* TRIO_EXTENSION */
4396
Daniel Veillard92ad2102001-03-27 12:47:33 +00004397 default:
4398 characterclass[(int)ch]++;
4399 break;
4400 }
4401 }
4402 return 0;
4403}
4404
4405/*************************************************************************
4406 * TrioReadNumber [private]
4407 *
4408 * We implement our own number conversion in preference of strtol and
4409 * strtoul, because we must handle 'long long' and thousand separators.
4410 */
4411static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004412TrioReadNumber(trio_T *self,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004413 trio_uintmax_t *target,
4414 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004415 int width,
4416 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004417{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004418 trio_uintmax_t number = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004419 int digit;
4420 int count;
4421 BOOLEAN_T isNegative = FALSE;
4422 int j;
4423
4424 assert(VALID(self));
4425 assert(VALID(self->InStream));
4426 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
4427
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004428 if (internalDigitsUnconverted)
4429 {
4430 /* Lazy evaluation of digits array */
4431 memset(internalDigitArray, -1, sizeof(internalDigitArray));
4432 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
4433 {
4434 internalDigitArray[(int)internalDigitsLower[j]] = j;
4435 internalDigitArray[(int)internalDigitsUpper[j]] = j;
4436 }
4437 internalDigitsUnconverted = FALSE;
4438 }
4439
Daniel Veillard92ad2102001-03-27 12:47:33 +00004440 TrioSkipWhitespaces(self);
4441
4442 if (!(flags & FLAGS_UNSIGNED))
4443 {
4444 /* Leading sign */
4445 if (self->current == '+')
4446 {
4447 self->InStream(self, NULL);
4448 }
4449 else if (self->current == '-')
4450 {
4451 self->InStream(self, NULL);
4452 isNegative = TRUE;
4453 }
4454 }
4455
4456 count = self->processed;
4457
4458 if (flags & FLAGS_ALTERNATIVE)
4459 {
4460 switch (base)
4461 {
4462 case NO_BASE:
4463 case BASE_OCTAL:
4464 case BASE_HEX:
4465 case BASE_BINARY:
4466 if (self->current == '0')
4467 {
4468 self->InStream(self, NULL);
4469 if (self->current)
4470 {
4471 if ((base == BASE_HEX) &&
4472 (toupper(self->current) == 'X'))
4473 {
4474 self->InStream(self, NULL);
4475 }
4476 else if ((base == BASE_BINARY) &&
4477 (toupper(self->current) == 'B'))
4478 {
4479 self->InStream(self, NULL);
4480 }
4481 }
4482 }
4483 else
4484 return FALSE;
4485 break;
4486 default:
4487 break;
4488 }
4489 }
4490
4491 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
4492 (! ((self->current == EOF) || isspace(self->current))))
4493 {
4494 if (isascii(self->current))
4495 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004496 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00004497 /* Abort if digit is not allowed in the specified base */
4498 if ((digit == -1) || (digit >= base))
4499 break;
4500 }
4501 else if (flags & FLAGS_QUOTE)
4502 {
4503 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004504 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004505 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004506 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004507 break;
4508
4509 self->InStream(self, NULL);
4510 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004511 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004512 break; /* Mismatch */
4513 else
4514 continue; /* Match */
4515 }
4516 else
4517 break;
4518
4519 number *= base;
4520 number += digit;
4521
4522 self->InStream(self, NULL);
4523 }
4524
4525 /* Was anything read at all? */
4526 if (self->processed == count)
4527 return FALSE;
4528
4529 if (target)
4530 *target = (isNegative) ? -number : number;
4531 return TRUE;
4532}
4533
4534/*************************************************************************
4535 * TrioReadChar [private]
4536 */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004537static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004538TrioReadChar(trio_T *self,
4539 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004540 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004541 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004542{
4543 int i;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004544 char ch;
4545 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004546
4547 assert(VALID(self));
4548 assert(VALID(self->InStream));
4549
4550 for (i = 0;
4551 (self->current != EOF) && (i < width);
4552 i++)
4553 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004554 ch = (char)self->current;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004555 self->InStream(self, NULL);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004556 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
4557 {
4558 switch (self->current)
4559 {
4560 case '\\': ch = '\\'; break;
4561 case 'a': ch = '\007'; break;
4562 case 'b': ch = '\b'; break;
4563 case 'f': ch = '\f'; break;
4564 case 'n': ch = '\n'; break;
4565 case 'r': ch = '\r'; break;
4566 case 't': ch = '\t'; break;
4567 case 'v': ch = '\v'; break;
4568 default:
4569 if (isdigit(self->current))
4570 {
4571 /* Read octal number */
4572 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
4573 return 0;
4574 ch = (char)number;
4575 }
4576 else if (toupper(self->current) == 'X')
4577 {
4578 /* Read hexadecimal number */
4579 self->InStream(self, NULL);
4580 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
4581 return 0;
4582 ch = (char)number;
4583 }
4584 else
4585 {
4586 ch = (char)self->current;
4587 }
4588 break;
4589 }
4590 }
4591
4592 if (target)
4593 target[i] = ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004594 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004595 return i + 1;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004596}
4597
4598/*************************************************************************
4599 * TrioReadString [private]
4600 */
4601static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004602TrioReadString(trio_T *self,
4603 char *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004604 unsigned long flags,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004605 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004606{
4607 int i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004608
4609 assert(VALID(self));
4610 assert(VALID(self->InStream));
4611
4612 TrioSkipWhitespaces(self);
4613
Bjorn Reese70a9da52001-04-21 16:57:29 +00004614 /*
4615 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004616 * or width is exceeded
4617 */
4618 for (i = 0;
4619 ((width == NO_WIDTH) || (i < width)) &&
4620 (! ((self->current == EOF) || isspace(self->current)));
4621 i++)
4622 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004623 if (TrioReadChar(self, &target[i], flags, 1) == 0)
4624 break; /* for */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004625 }
4626 if (target)
4627 target[i] = NIL;
4628 return TRUE;
4629}
4630
4631/*************************************************************************
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004632 * TrioReadWideChar [private]
4633 */
4634#if TRIO_WIDECHAR
4635static int
4636TrioReadWideChar(trio_T *self,
4637 wchar_t *target,
4638 unsigned long flags,
4639 int width)
4640{
4641 int i;
4642 int j;
4643 int size;
4644 int amount = 0;
4645 wchar_t wch;
4646 char buffer[MB_LEN_MAX + 1];
4647
4648 assert(VALID(self));
4649 assert(VALID(self->InStream));
4650
4651 for (i = 0;
4652 (self->current != EOF) && (i < width);
4653 i++)
4654 {
4655 if (isascii(self->current))
4656 {
4657 if (TrioReadChar(self, buffer, flags, 1) == 0)
4658 return 0;
4659 buffer[1] = NIL;
4660 }
4661 else
4662 {
4663 /*
4664 * Collect a multibyte character, by enlarging buffer until
4665 * it contains a fully legal multibyte character, or the
4666 * buffer is full.
4667 */
4668 j = 0;
4669 do
4670 {
4671 buffer[j++] = (char)self->current;
4672 buffer[j] = NIL;
4673 self->InStream(self, NULL);
4674 }
4675 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
4676 }
4677 if (target)
4678 {
4679 size = mbtowc(&wch, buffer, sizeof(buffer));
4680 if (size > 0)
4681 target[i] = wch;
4682 }
4683 amount += size;
4684 self->InStream(self, NULL);
4685 }
4686 return amount;
4687}
4688#endif /* TRIO_WIDECHAR */
4689
4690/*************************************************************************
4691 * TrioReadWideString [private]
4692 */
4693#if TRIO_WIDECHAR
4694static BOOLEAN_T
4695TrioReadWideString(trio_T *self,
4696 wchar_t *target,
4697 unsigned long flags,
4698 int width)
4699{
4700 int i;
4701 int size;
4702
4703 assert(VALID(self));
4704 assert(VALID(self->InStream));
4705
4706 TrioSkipWhitespaces(self);
4707
4708#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
4709 mblen(NULL, 0);
4710#endif
4711
4712 /*
4713 * Continue until end of string is reached, a whitespace is encountered,
4714 * or width is exceeded
4715 */
4716 for (i = 0;
4717 ((width == NO_WIDTH) || (i < width)) &&
4718 (! ((self->current == EOF) || isspace(self->current)));
4719 )
4720 {
4721 size = TrioReadWideChar(self, &target[i], flags, 1);
4722 if (size == 0)
4723 break; /* for */
4724
4725 i += size;
4726 }
4727 if (target)
4728 target[i] = L'\0';
4729 return TRUE;
4730}
4731#endif /* TRIO_WIDECHAR */
4732
4733/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00004734 * TrioReadGroup [private]
4735 *
4736 * FIXME: characterclass does not work with multibyte characters
4737 */
4738static BOOLEAN_T
4739TrioReadGroup(trio_T *self,
4740 char *target,
4741 int *characterclass,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004742 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004743 int width)
4744{
Bjorn Reese70a9da52001-04-21 16:57:29 +00004745 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004746 int i;
4747
4748 assert(VALID(self));
4749 assert(VALID(self->InStream));
4750
4751 ch = self->current;
4752 for (i = 0;
4753 ((width == NO_WIDTH) || (i < width)) &&
4754 (! ((ch == EOF) ||
4755 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
4756 i++)
4757 {
4758 if (target)
4759 target[i] = (char)ch;
4760 self->InStream(self, &ch);
4761 }
4762
4763 if (target)
4764 target[i] = NIL;
4765 return TRUE;
4766}
4767
4768/*************************************************************************
4769 * TrioReadDouble [private]
4770 *
4771 * FIXME:
Daniel Veillard92ad2102001-03-27 12:47:33 +00004772 * add long double
4773 */
4774static BOOLEAN_T
4775TrioReadDouble(trio_T *self,
4776 double *target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004777 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004778 int width)
4779{
4780 int ch;
4781 char doubleString[512] = "";
4782 int index = 0;
4783 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004784 int j;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004785 BOOLEAN_T isHex = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004786
Bjorn Reese70a9da52001-04-21 16:57:29 +00004787 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004788 width = sizeof(doubleString) - 1;
4789
4790 TrioSkipWhitespaces(self);
4791
Bjorn Reese70a9da52001-04-21 16:57:29 +00004792 /*
4793 * Read entire double number from stream. StrToDouble requires a
Daniel Veillard92ad2102001-03-27 12:47:33 +00004794 * string as input, but InStream can be anything, so we have to
4795 * collect all characters.
4796 */
4797 ch = self->current;
4798 if ((ch == '+') || (ch == '-'))
4799 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004800 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004801 self->InStream(self, &ch);
4802 width--;
4803 }
4804
4805 start = index;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004806 switch (ch)
4807 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00004808 case 'n':
4809 case 'N':
4810 /* Not-a-number */
4811 if (index != 0)
4812 break;
4813 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004814 case 'i':
4815 case 'I':
4816 /* Infinity */
4817 while (isalpha(ch) && (index - start < width))
4818 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004819 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004820 self->InStream(self, &ch);
4821 }
4822 doubleString[index] = NIL;
4823
Daniel Veillard92ad2102001-03-27 12:47:33 +00004824 /* Case insensitive string comparison */
4825 if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
4826 StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
4827 {
4828 *target = ((start == 1 && doubleString[0] == '-'))
Bjorn Reese45029602001-08-21 09:23:53 +00004829 ? trio_ninf()
4830 : trio_pinf();
Daniel Veillard92ad2102001-03-27 12:47:33 +00004831 return TRUE;
4832 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004833 if (StrEqual(doubleString, NAN_LOWER))
4834 {
4835 /* NaN must not have a preceeding + nor - */
Bjorn Reese45029602001-08-21 09:23:53 +00004836 *target = trio_nan();
Daniel Veillard92ad2102001-03-27 12:47:33 +00004837 return TRUE;
4838 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004839 return FALSE;
4840
4841 default:
4842 break;
4843 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004844
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004845 if (ch == '0')
4846 {
4847 doubleString[index++] = (char)ch;
4848 self->InStream(self, &ch);
4849 if (toupper(ch) == 'X')
4850 {
4851 isHex = TRUE;
4852 doubleString[index++] = (char)ch;
4853 self->InStream(self, &ch);
4854 }
4855 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004856 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004857 {
4858 /* Integer part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004859 if (isHex ? isxdigit(ch) : isdigit(ch))
Bjorn Reese70a9da52001-04-21 16:57:29 +00004860 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004861 doubleString[index++] = (char)ch;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004862 self->InStream(self, &ch);
4863 }
4864 else if (flags & FLAGS_QUOTE)
4865 {
4866 /* Compare with thousands separator */
4867 for (j = 0; internalThousandSeparator[j] && self->current; j++)
4868 {
4869 if (internalThousandSeparator[j] != self->current)
4870 break;
4871
4872 self->InStream(self, &ch);
4873 }
4874 if (internalThousandSeparator[j])
4875 break; /* Mismatch */
4876 else
4877 continue; /* Match */
4878 }
4879 else
4880 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004881 }
4882 if (ch == '.')
4883 {
4884 /* Decimal part */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004885 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004886 self->InStream(self, &ch);
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004887 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4888 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004889 {
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 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004893 if (isHex ? (toupper(ch) == 'P') : (toupper(ch) == 'E'))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004894 {
4895 /* Exponent */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004896 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004897 self->InStream(self, &ch);
4898 if ((ch == '+') || (ch == '-'))
4899 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004900 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004901 self->InStream(self, &ch);
4902 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004903 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
4904 (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004905 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004906 doubleString[index++] = (char)ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004907 self->InStream(self, &ch);
4908 }
4909 }
4910 }
4911
4912 if ((index == start) || (*doubleString == NIL))
4913 return FALSE;
4914
4915 if (flags & FLAGS_LONGDOUBLE)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004916/* *longdoublePointer = StrToLongDouble()*/
4917 return FALSE; /* FIXME: Remove when long double is implemented */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004918 else
4919 {
4920 *target = StrToDouble(doubleString, NULL);
4921 }
4922 return TRUE;
4923}
4924
4925/*************************************************************************
4926 * TrioReadPointer [private]
4927 */
4928static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004929TrioReadPointer(trio_T *self,
4930 void **target,
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004931 unsigned long flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004932{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004933 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004934 char buffer[sizeof(null)];
4935
4936 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
4937
4938 if (TrioReadNumber(self,
4939 &number,
4940 flags,
4941 POINTER_WIDTH,
4942 BASE_HEX))
4943 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004944 /*
4945 * The strange assignment of number is a workaround for a compiler
4946 * warning
4947 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004948 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004949 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004950 return TRUE;
4951 }
4952 else if (TrioReadString(self,
4953 (flags & FLAGS_IGNORE)
4954 ? NULL
4955 : buffer,
4956 0,
4957 sizeof(null) - 1))
4958 {
4959 if (StrEqualCase(buffer, null))
4960 {
4961 if (target)
4962 *target = NULL;
4963 return TRUE;
4964 }
4965 }
4966 return FALSE;
4967}
4968
4969/*************************************************************************
4970 * TrioScan [private]
4971 */
4972static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004973TrioScan(const void *source,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004974 size_t sourceSize,
4975 void (*InStream)(trio_T *, int *),
4976 const char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004977 va_list arglist,
4978 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004979{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004980#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004981 int charlen;
4982#endif
4983 int status;
4984 int assignment;
4985 parameter_T parameters[MAX_PARAMETERS];
4986 trio_T internalData;
4987 trio_T *data;
4988 int ch;
4989 int cnt;
4990 int index; /* Index of format string */
4991 int i; /* Index of current parameter */
Bjorn Reese906ec8a2001-06-05 12:46:33 +00004992 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004993 int width;
4994 int base;
4995 void *pointer;
4996
4997 assert(VALID(InStream));
4998 assert(VALID(format));
Daniel Veillard92ad2102001-03-27 12:47:33 +00004999
5000 memset(&internalData, 0, sizeof(internalData));
5001 data = &internalData;
5002 data->InStream = InStream;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005003 data->location = (void *)source;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005004 data->max = sourceSize;
5005
5006#if defined(USE_LOCALE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00005007 if (NULL == internalLocaleValues)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005008 {
5009 TrioSetLocale();
5010 }
5011#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00005012
Bjorn Reese70a9da52001-04-21 16:57:29 +00005013 status = TrioPreprocess(TYPE_SCAN, format, parameters, arglist, argarray);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005014 if (status < 0)
5015 return status;
5016
5017 assignment = 0;
5018 i = 0;
5019 index = 0;
5020 data->InStream(data, &ch);
5021
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005022#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005023 mblen(NULL, 0);
5024#endif
5025
5026 while (format[index])
5027 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005028#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005029 if (! isascii(format[index]))
5030 {
5031 charlen = mblen(&format[index], MB_LEN_MAX);
5032 /* Compare multibyte characters in format string */
5033 for (cnt = 0; cnt < charlen - 1; cnt++)
5034 {
5035 if (ch != format[index + cnt])
5036 {
5037 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5038 }
5039 data->InStream(data, &ch);
5040 }
5041 continue; /* while */
5042 }
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005043#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
Daniel Veillard92ad2102001-03-27 12:47:33 +00005044 if (EOF == ch)
5045 return EOF;
5046
5047 if (CHAR_IDENTIFIER == format[index])
5048 {
5049 if (CHAR_IDENTIFIER == format[index + 1])
5050 {
5051 /* Two % in format matches one % in input stream */
5052 if (CHAR_IDENTIFIER == ch)
5053 {
5054 data->InStream(data, &ch);
5055 index += 2;
5056 continue; /* while format chars left */
5057 }
5058 else
5059 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5060 }
5061
5062 /* Skip the parameter entries */
5063 while (parameters[i].type == FORMAT_PARAMETER)
5064 i++;
5065
5066 flags = parameters[i].flags;
5067 /* Find width */
5068 width = parameters[i].width;
5069 if (flags & FLAGS_WIDTH_PARAMETER)
5070 {
5071 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005072 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005073 }
5074 /* Find base */
5075 base = parameters[i].base;
5076 if (flags & FLAGS_BASE_PARAMETER)
5077 {
5078 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00005079 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005080 }
5081
5082 switch (parameters[i].type)
5083 {
5084 case FORMAT_INT:
5085 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005086 trio_uintmax_t number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005087
5088 if (0 == base)
5089 base = BASE_DECIMAL;
5090
5091 if (!TrioReadNumber(data,
5092 &number,
5093 flags,
5094 width,
5095 base))
5096 return assignment;
5097 assignment++;
5098
5099 if (!(flags & FLAGS_IGNORE))
5100 {
5101 pointer = parameters[i].data.pointer;
5102#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5103 if (flags & FLAGS_SIZE_T)
5104 *(size_t *)pointer = (size_t)number;
5105 else
5106#endif
5107#if defined(QUALIFIER_PTRDIFF_T)
5108 if (flags & FLAGS_PTRDIFF_T)
5109 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
5110 else
5111#endif
5112#if defined(QUALIFIER_INTMAX_T)
5113 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005114 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005115 else
5116#endif
5117 if (flags & FLAGS_QUAD)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005118 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005119 else if (flags & FLAGS_LONG)
5120 *(long int *)pointer = (long int)number;
5121 else if (flags & FLAGS_SHORT)
5122 *(short int *)pointer = (short int)number;
5123 else
5124 *(int *)pointer = (int)number;
5125 }
5126 }
5127 break; /* FORMAT_INT */
5128
5129 case FORMAT_STRING:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005130#if TRIO_WIDECHAR
5131 if (flags & FLAGS_WIDECHAR)
5132 {
5133 if (!TrioReadWideString(data,
5134 (flags & FLAGS_IGNORE)
5135 ? NULL
5136 : parameters[i].data.wstring,
5137 flags,
5138 width))
5139 return assignment;
5140 }
5141 else
5142#endif
5143 {
5144 if (!TrioReadString(data,
5145 (flags & FLAGS_IGNORE)
5146 ? NULL
5147 : parameters[i].data.string,
5148 flags,
5149 width))
5150 return assignment;
5151 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005152 assignment++;
5153 break; /* FORMAT_STRING */
5154
5155 case FORMAT_DOUBLE:
5156 if (!TrioReadDouble(data,
5157 (flags & FLAGS_IGNORE)
5158 ? NULL
5159 : parameters[i].data.doublePointer,
5160 flags,
5161 width))
5162 return assignment;
5163 assignment++;
5164 break; /* FORMAT_DOUBLE */
5165
5166 case FORMAT_GROUP:
5167 {
5168 int characterclass[MAX_CHARACTER_CLASS + 1];
5169 int rc;
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005170
5171 /* Skip over modifiers */
5172 while (format[index] != SPECIFIER_GROUP)
5173 {
5174 index++;
5175 }
5176 /* Skip over group specifier */
5177 index++;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005178
Daniel Veillard92ad2102001-03-27 12:47:33 +00005179 memset(characterclass, 0, sizeof(characterclass));
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005180 rc = TrioGetCharacterClass(format,
5181 &index,
5182 &flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005183 characterclass);
5184 if (rc < 0)
5185 return rc;
5186
5187 if (!TrioReadGroup(data,
5188 (flags & FLAGS_IGNORE)
5189 ? NULL
5190 : parameters[i].data.string,
5191 characterclass,
5192 flags,
5193 parameters[i].width))
5194 return assignment;
5195 assignment++;
5196 }
5197 break; /* FORMAT_GROUP */
5198
5199 case FORMAT_COUNT:
5200 pointer = parameters[i].data.pointer;
5201 if (NULL != pointer)
5202 {
5203#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
5204 if (flags & FLAGS_SIZE_T)
5205 *(size_t *)pointer = (size_t)data->committed;
5206 else
5207#endif
5208#if defined(QUALIFIER_PTRDIFF_T)
5209 if (flags & FLAGS_PTRDIFF_T)
5210 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
5211 else
5212#endif
5213#if defined(QUALIFIER_INTMAX_T)
5214 if (flags & FLAGS_INTMAX_T)
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005215 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005216 else
5217#endif
5218 if (flags & FLAGS_QUAD)
5219 {
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005220 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00005221 }
5222 else if (flags & FLAGS_LONG)
5223 {
5224 *(long int *)pointer = (long int)data->committed;
5225 }
5226 else if (flags & FLAGS_SHORT)
5227 {
5228 *(short int *)pointer = (short int)data->committed;
5229 }
5230 else
5231 {
5232 *(int *)pointer = (int)data->committed;
5233 }
5234 }
5235 break; /* FORMAT_COUNT */
5236
5237 case FORMAT_CHAR:
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005238#if TRIO_WIDECHAR
5239 if (flags & FLAGS_WIDECHAR)
5240 {
5241 if (TrioReadWideChar(data,
5242 (flags & FLAGS_IGNORE)
5243 ? NULL
5244 : parameters[i].data.wstring,
5245 flags,
5246 (width == NO_WIDTH) ? 1 : width) > 0)
5247 return assignment;
5248 }
5249 else
5250#endif
5251 {
5252 if (TrioReadChar(data,
5253 (flags & FLAGS_IGNORE)
5254 ? NULL
5255 : parameters[i].data.string,
5256 flags,
5257 (width == NO_WIDTH) ? 1 : width) > 0)
5258 return assignment;
5259 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00005260 assignment++;
5261 break; /* FORMAT_CHAR */
5262
5263 case FORMAT_POINTER:
5264 if (!TrioReadPointer(data,
5265 (flags & FLAGS_IGNORE)
5266 ? NULL
Bjorn Reese70a9da52001-04-21 16:57:29 +00005267 : (void **)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00005268 flags))
5269 return assignment;
5270 assignment++;
5271 break; /* FORMAT_POINTER */
5272
5273 case FORMAT_PARAMETER:
5274 break; /* FORMAT_PARAMETER */
5275
5276 default:
5277 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5278 }
5279 ch = data->current;
5280 index = parameters[i].indexAfterSpecifier;
5281 i++;
5282 }
5283 else /* Not an % identifier */
5284 {
5285 if (isspace((int)format[index]))
5286 {
5287 /* Whitespaces may match any amount of whitespaces */
5288 ch = TrioSkipWhitespaces(data);
5289 }
5290 else if (ch == format[index])
5291 {
5292 data->InStream(data, &ch);
5293 }
5294 else
5295 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5296
5297 index++;
5298 }
5299 }
5300 return assignment;
5301}
5302
5303/*************************************************************************
5304 * TrioInStreamFile [private]
5305 */
5306static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005307TrioInStreamFile(trio_T *self,
5308 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005309{
5310 FILE *file = (FILE *)self->location;
5311
5312 assert(VALID(self));
5313 assert(VALID(file));
5314
5315 self->current = fgetc(file);
5316 self->processed++;
5317 self->committed++;
5318
5319 if (VALID(intPointer))
5320 {
5321 *intPointer = self->current;
5322 }
5323}
5324
5325/*************************************************************************
5326 * TrioInStreamFileDescriptor [private]
5327 */
5328static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005329TrioInStreamFileDescriptor(trio_T *self,
5330 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005331{
5332 int fd = *((int *)self->location);
5333 int size;
5334 unsigned char input;
5335
5336 assert(VALID(self));
5337
5338 size = read(fd, &input, sizeof(char));
5339 self->current = (size == 0) ? EOF : input;
5340 self->processed++;
5341 self->committed++;
5342
5343 if (VALID(intPointer))
5344 {
5345 *intPointer = self->current;
5346 }
5347}
5348
5349/*************************************************************************
5350 * TrioInStreamString [private]
5351 */
5352static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00005353TrioInStreamString(trio_T *self,
5354 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005355{
5356 unsigned char **buffer;
5357
5358 assert(VALID(self));
5359 assert(VALID(self->InStream));
5360 assert(VALID(self->location));
5361
5362 buffer = (unsigned char **)self->location;
5363 self->current = (*buffer)[0];
5364 if (self->current == NIL)
5365 self->current = EOF;
5366 (*buffer)++;
5367 self->processed++;
5368 self->committed++;
5369
5370 if (VALID(intPointer))
5371 {
5372 *intPointer = self->current;
5373 }
5374}
5375
5376/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00005377 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00005378 */
5379int
Bjorn Reese70a9da52001-04-21 16:57:29 +00005380trio_scanf(const char *format,
5381 ...)
5382{
5383 int status;
5384 va_list args;
5385
5386 assert(VALID(format));
5387
5388 va_start(args, format);
5389 status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5390 va_end(args);
5391 return status;
5392}
5393
5394int
5395trio_vscanf(const char *format,
5396 va_list args)
5397{
5398 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005399
5400 return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
5401}
5402
5403int
5404trio_scanfv(const char *format,
5405 void **args)
5406{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005407 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005408
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005409 assert(VALID(format));
5410
5411 return TrioScan(stdin, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005412}
5413
5414/*************************************************************************
5415 * fscanf
5416 */
5417int
5418trio_fscanf(FILE *file,
5419 const char *format,
5420 ...)
5421{
5422 int status;
5423 va_list args;
5424
5425 assert(VALID(file));
5426 assert(VALID(format));
5427
5428 va_start(args, format);
5429 status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5430 va_end(args);
5431 return status;
5432}
5433
5434int
5435trio_vfscanf(FILE *file,
5436 const char *format,
5437 va_list args)
5438{
5439 assert(VALID(file));
5440 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005441
5442 return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
5443}
5444
5445int
5446trio_fscanfv(FILE *file,
5447 const char *format,
5448 void **args)
5449{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005450 va_list dummy;
5451
Bjorn Reese70a9da52001-04-21 16:57:29 +00005452 assert(VALID(file));
5453 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005454
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005455 return TrioScan(file, 0, TrioInStreamFile, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005456}
5457
5458/*************************************************************************
5459 * dscanf
5460 */
5461int
5462trio_dscanf(int fd,
5463 const char *format,
5464 ...)
5465{
5466 int status;
5467 va_list args;
5468
5469 assert(VALID(format));
5470
5471 va_start(args, format);
5472 status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5473 va_end(args);
5474 return status;
5475}
5476
5477int
5478trio_vdscanf(int fd,
5479 const char *format,
5480 va_list args)
5481{
5482 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005483
5484 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
5485}
5486
5487int
5488trio_dscanfv(int fd,
5489 const char *format,
5490 void **args)
5491{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005492 va_list dummy;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005493
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005494 assert(VALID(format));
5495
5496 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005497}
5498
5499/*************************************************************************
5500 * sscanf
5501 */
5502int
5503trio_sscanf(const char *buffer,
5504 const char *format,
5505 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00005506{
5507 int status;
5508 va_list args;
5509
5510 assert(VALID(buffer));
5511 assert(VALID(format));
5512
5513 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005514 status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00005515 va_end(args);
5516 return status;
5517}
5518
Bjorn Reese70a9da52001-04-21 16:57:29 +00005519int
5520trio_vsscanf(const char *buffer,
5521 const char *format,
5522 va_list args)
5523{
5524 assert(VALID(buffer));
5525 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005526
5527 return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
5528}
5529
5530int
5531trio_sscanfv(const char *buffer,
5532 const char *format,
5533 void **args)
5534{
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005535 va_list dummy;
5536
Bjorn Reese70a9da52001-04-21 16:57:29 +00005537 assert(VALID(buffer));
5538 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00005539
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005540 return TrioScan(&buffer, 0, TrioInStreamString, format, dummy, args);
Bjorn Reese70a9da52001-04-21 16:57:29 +00005541}
Bjorn Reese906ec8a2001-06-05 12:46:33 +00005542