blob: 84b4a2b87b4b4338d4d8209afaf5a08f887f860b [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.
Bjorn Reese70a9da52001-04-21 16:57:29 +000030 * - Add hex-float to TrioReadDouble.
Daniel Veillard92ad2102001-03-27 12:47:33 +000031 * - C escapes in %#[] ?
Bjorn Reese70a9da52001-04-21 16:57:29 +000032 * - C99 support has not been properly tested.
Daniel Veillard92ad2102001-03-27 12:47:33 +000033 * - Multibyte characters (done for format parsing, except scan groups)
Daniel Veillard92ad2102001-03-27 12:47:33 +000034 * - Complex numbers? (C99 _Complex)
35 * - Boolean values? (C99 _Bool)
36 * - C99 NaN(n-char-sequence) missing
37 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
38 * for %a, because C99 used %a for other purposes. If specified as
39 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
40 * the C99 hex-float. This means that you cannot scan %as as a hex-float
41 * immediately followed by an 's'.
42 */
43
44static const char rcsid[] = "@(#)$Id$";
45
Daniel Veillard92ad2102001-03-27 12:47:33 +000046#if defined(unix) || defined(__xlC__) /* AIX xlC workaround */
47# define PLATFORM_UNIX
48#elif defined(AMIGA) && defined(__GNUC__)
49# define PLATFORM_UNIX
50#endif
51
52/*************************************************************************
53 * Include files
54 */
55
Daniel Veillard92ad2102001-03-27 12:47:33 +000056#include "trio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000057#include "triop.h"
Daniel Veillard92ad2102001-03-27 12:47:33 +000058#include "strio.h"
Bjorn Reese70a9da52001-04-21 16:57:29 +000059
60#if !defined(DEBUG) && !defined(NDEBUG)
61# define NDEBUG
62#endif
63#include <assert.h>
Daniel Veillard92ad2102001-03-27 12:47:33 +000064#include <ctype.h>
65#include <math.h>
66#include <limits.h>
67#include <float.h>
68#include <stdarg.h>
69#include <errno.h>
70#if defined(TRIO_C99)
71# include <stdint.h>
72#endif
73#if defined(PLATFORM_UNIX)
74# include <unistd.h>
75# include <locale.h>
76# define USE_LOCALE
77#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +000078
79#if defined(_MSC_VER)
80#include <io.h>
81#define read _read
82#define write _write
83#endif /* _MSC_VER */
Daniel Veillard92ad2102001-03-27 12:47:33 +000084
85/*************************************************************************
86 * Generic definitions
87 */
88
89#ifndef NULL
90# define NULL 0
91#endif
92#define NIL ((char)0)
93#ifdef __cplusplus
94# undef TRUE
95# undef FALSE
96# define TRUE true
97# define FALSE false
98# define BOOLEAN_T bool
99#else
100# ifndef FALSE
101# define FALSE (1 == 0)
102# define TRUE (! FALSE)
103# endif
104# define BOOLEAN_T int
105#endif
106
107/* mincore() can be used for debugging purposes */
108#define VALID(x) (NULL != (x))
109
Bjorn Reese70a9da52001-04-21 16:57:29 +0000110/*
111 * Encode the error code and the position. This is decoded
Daniel Veillard92ad2102001-03-27 12:47:33 +0000112 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
113 */
114#if defined(TRIO_ERRORS)
115# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
116#else
117# define TRIO_ERROR_RETURN(x,y) (-1)
118#endif
119
120/*************************************************************************
121 * Internal definitions
122 */
123
124#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX)
125# define USE_MULTIBYTE
126#endif
127
128#if !defined(USE_LONGLONG)
129# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
130# define USE_LONGLONG
131# elif defined(__SUNPRO_C)
132# define USE_LONGLONG
133# elif defined(_LONG_LONG) || defined(_LONGLONG)
134# define USE_LONGLONG
135# endif
136#endif
137
138/* The extra long numbers */
139#if defined(USE_LONGLONG)
140# define LONGLONG long long
141# define ULONGLONG unsigned long long
142#else
143# define LONGLONG long
144# define ULONGLONG unsigned long
145#endif
146
147/* The longest possible integer */
148#if defined(TRIO_C99)
149# define LONGEST uintmax_t
150# define SLONGEST intmax_t
151#else
152# define LONGEST ULONGLONG
153# define SLONGEST LONGLONG
154#endif
155
156/* The maximal number of digits are for base 2 */
157#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT + 1)
158/* The width of a pointer. The number of bits in a hex digit is 4 */
159#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
160
161/* Infinite and Not-A-Number for floating-point */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000162#define USE_NON_NUMBERS
163#ifndef NAN
164# define NAN (cos(HUGE_VAL))
Daniel Veillard92ad2102001-03-27 12:47:33 +0000165#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +0000166#define INFINITE_LOWER "inf"
167#define INFINITE_UPPER "INF"
168#define LONG_INFINITE_LOWER "infinite"
169#define LONG_INFINITE_UPPER "INFINITE"
170#define NAN_LOWER "nan"
171#define NAN_UPPER "NAN"
Daniel Veillard92ad2102001-03-27 12:47:33 +0000172
173/* Various constants */
174enum {
175 TYPE_PRINT = 1,
176 TYPE_SCAN = 2,
177
178 /* Flags. Use maximum 32 */
179 FLAGS_NEW = 0,
180 FLAGS_STICKY = 1,
181 FLAGS_SPACE = 2 * FLAGS_STICKY,
182 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
183 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
184 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
185 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
186 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
187 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
188 FLAGS_QUAD = 2 * FLAGS_LONG,
189 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
190 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
191 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
192 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
193 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
194 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
195 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
196 FLAGS_WIDTH = 2 * FLAGS_UPPER,
197 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
198 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
199 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
200 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
201 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
202 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
203 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
204 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
205 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
206 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
207 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
208 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
209 FLAGS_SIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
210 /* Reused flags */
211 FLAGS_EXCLUDE = FLAGS_SHORT,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000212 FLAGS_USER_DEFINED = FLAGS_IGNORE,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000213 /* Compounded flags */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000214 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000215
216 NO_POSITION = -1,
217 NO_WIDTH = 0,
218 NO_PRECISION = -1,
219 NO_SIZE = -1,
220
221 NO_BASE = -1,
222 MIN_BASE = 2,
223 MAX_BASE = 36,
224 BASE_BINARY = 2,
225 BASE_OCTAL = 8,
226 BASE_DECIMAL = 10,
227 BASE_HEX = 16,
228
229 /* Maximal number of allowed parameters */
230 MAX_PARAMETERS = 64,
231 /* Maximal number of characters in class */
232 MAX_CHARACTER_CLASS = UCHAR_MAX,
233
Bjorn Reese70a9da52001-04-21 16:57:29 +0000234 /* Maximal string lengths for user-defined specifiers */
235 MAX_USER_NAME = 64,
236 MAX_USER_DATA = 256,
237
Daniel Veillard92ad2102001-03-27 12:47:33 +0000238 /* Maximal length of locale separator strings */
239 MAX_LOCALE_SEPARATOR_LENGTH = 64,
240 /* Maximal number of integers in grouping */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000241 MAX_LOCALE_GROUPS = 64,
Daniel Veillard92ad2102001-03-27 12:47:33 +0000242};
243
244#define NO_GROUPING ((int)CHAR_MAX)
245
246/* Fundamental formatting parameter types */
247#define FORMAT_UNKNOWN 0
248#define FORMAT_INT 1
249#define FORMAT_DOUBLE 2
250#define FORMAT_CHAR 3
251#define FORMAT_STRING 4
252#define FORMAT_POINTER 5
253#define FORMAT_COUNT 6
254#define FORMAT_PARAMETER 7
255#define FORMAT_GROUP 8
256#if defined(TRIO_GNU)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000257# define FORMAT_ERRNO 9
258#endif
259#if defined(TRIO_EXTENSION)
260# define FORMAT_USER_DEFINED 10
Daniel Veillard92ad2102001-03-27 12:47:33 +0000261#endif
262
263/* Character constants */
264#define CHAR_IDENTIFIER '%'
265#define CHAR_BACKSLASH '\\'
266#define CHAR_QUOTE '\"'
267#define CHAR_ADJUST ' '
268
269/* Character class expressions */
270#define CLASS_ALNUM ":alnum:"
271#define CLASS_ALPHA ":alpha:"
272#define CLASS_CNTRL ":cntrl:"
273#define CLASS_DIGIT ":digit:"
274#define CLASS_GRAPH ":graph:"
275#define CLASS_LOWER ":lower:"
276#define CLASS_PRINT ":print:"
277#define CLASS_PUNCT ":punct:"
278#define CLASS_SPACE ":space:"
279#define CLASS_UPPER ":upper:"
280#define CLASS_XDIGIT ":xdigit:"
281
282/*
283 * SPECIFIERS:
284 *
285 *
286 * a Hex-float
287 * A Hex-float
288 * c Character
289 * C Widechar character (wint_t)
290 * d Decimal
291 * e Float
292 * E Float
293 * F Float
294 * F Float
295 * g Float
296 * G Float
297 * i Integer
298 * m Error message
299 * n Count
300 * o Octal
301 * p Pointer
302 * s String
303 * S Widechar string (wchar_t)
304 * u Unsigned
305 * x Hex
306 * X Hex
Bjorn Reese70a9da52001-04-21 16:57:29 +0000307 * [] Group
308 * <> User-defined
Daniel Veillard92ad2102001-03-27 12:47:33 +0000309 *
310 * Reserved:
311 *
312 * D Binary Coded Decimal %D(length,precision) (OS/390)
313 */
314#define SPECIFIER_CHAR 'c'
315#define SPECIFIER_STRING 's'
316#define SPECIFIER_DECIMAL 'd'
317#define SPECIFIER_INTEGER 'i'
318#define SPECIFIER_UNSIGNED 'u'
319#define SPECIFIER_OCTAL 'o'
320#define SPECIFIER_HEX 'x'
321#define SPECIFIER_HEX_UPPER 'X'
322#define SPECIFIER_FLOAT_E 'e'
323#define SPECIFIER_FLOAT_E_UPPER 'E'
324#define SPECIFIER_FLOAT_F 'f'
325#define SPECIFIER_FLOAT_F_UPPER 'F'
326#define SPECIFIER_FLOAT_G 'g'
327#define SPECIFIER_FLOAT_G_UPPER 'G'
328#define SPECIFIER_POINTER 'p'
329#define SPECIFIER_GROUP '['
330#define SPECIFIER_UNGROUP ']'
331#define SPECIFIER_COUNT 'n'
332#if defined(TRIO_UNIX98)
333# define SPECIFIER_CHAR_UPPER 'C'
334# define SPECIFIER_STRING_UPPER 'S'
335#endif
336#if defined(TRIO_C99)
337# define SPECIFIER_HEXFLOAT 'a'
338# define SPECIFIER_HEXFLOAT_UPPER 'A'
339#endif
340#if defined(TRIO_GNU)
341# define SPECIFIER_ERRNO 'm'
342#endif
343#if defined(TRIO_EXTENSION)
344# define SPECIFIER_BINARY 'b'
345# define SPECIFIER_BINARY_UPPER 'B'
Bjorn Reese70a9da52001-04-21 16:57:29 +0000346# define SPECIFIER_USER_DEFINED_BEGIN '<'
347# define SPECIFIER_USER_DEFINED_END '>'
348# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
Daniel Veillard92ad2102001-03-27 12:47:33 +0000349#endif
350
351/*
352 * QUALIFIERS:
353 *
354 *
355 * Numbers = d,i,o,u,x,X
356 * Float = a,A,e,E,f,F,g,G
357 * String = s
358 * Char = c
359 *
360 *
361 * 9$ Position
362 * Use the 9th parameter. 9 can be any number between 1 and
363 * the maximal argument
364 *
365 * 9 Width
366 * Set width to 9. 9 can be any number, but must not be postfixed
367 * by '$'
368 *
369 * h Short
370 * Numbers:
371 * (unsigned) short int
372 *
373 * hh Short short
374 * Numbers:
375 * (unsigned) char
376 *
377 * l Long
378 * Numbers:
379 * (unsigned) long int
380 * String:
381 * as the S specifier
382 * Char:
383 * as the C specifier
384 *
385 * ll Long Long
386 * Numbers:
387 * (unsigned) long long int
388 *
389 * L Long Double
390 * Float
391 * long double
392 *
393 * # Alternative
394 * Float:
395 * Decimal-point is always present
396 * String:
397 * non-printable characters are handled as \number
398 *
399 * Spacing
400 *
401 * + Sign
402 *
403 * - Alignment
404 *
405 * . Precision
406 *
407 * * Parameter
408 * print: use parameter
409 * scan: no parameter (ignore)
410 *
411 * q Quad
412 *
413 * Z size_t
414 *
415 * w Widechar
416 *
417 * ' Thousands/quote
418 * Numbers:
419 * Integer part grouped in thousands
420 * Binary numbers:
421 * Number grouped in nibbles (4 bits)
422 * String:
423 * Quoted string
424 *
425 * j intmax_t
426 * t prtdiff_t
427 * z size_t
428 *
429 * ! Sticky
430 * @ Parameter (for both print and scan)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000431 */
432#define QUALIFIER_POSITION '$'
433#define QUALIFIER_SHORT 'h'
434#define QUALIFIER_LONG 'l'
435#define QUALIFIER_LONG_UPPER 'L'
436#define QUALIFIER_ALTERNATIVE '#'
437#define QUALIFIER_SPACE ' '
438#define QUALIFIER_PLUS '+'
439#define QUALIFIER_MINUS '-'
440#define QUALIFIER_DOT '.'
441#define QUALIFIER_STAR '*'
442#define QUALIFIER_CIRCUMFLEX '^'
443#if defined(TRIO_C99)
444# define QUALIFIER_SIZE_T 'z'
445# define QUALIFIER_PTRDIFF_T 't'
446# define QUALIFIER_INTMAX_T 'j'
447#endif
448#if defined(TRIO_BSD) || defined(TRIO_GNU)
449# define QUALIFIER_QUAD 'q'
450#endif
451#if defined(TRIO_GNU)
452# define QUALIFIER_SIZE_T_UPPER 'Z'
453#endif
454#if defined(TRIO_MISC)
455# define QUALIFIER_WIDECHAR 'w'
456#endif
457#if defined(TRIO_EXTENSION)
458# define QUALIFIER_QUOTE '\''
459# define QUALIFIER_STICKY '!'
460# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
461# define QUALIFIER_PARAM '@' /* Experimental */
462# define QUALIFIER_COLON ':' /* For scanlists */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000463#endif
464
Bjorn Reese70a9da52001-04-21 16:57:29 +0000465
466/*************************************************************************
467 * Internal structures
468 */
469
470/* Parameters */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000471typedef struct {
472 int type;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000473 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000474 int width;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000475 int precision;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000476 int base;
477 int varsize;
478 int indexAfterSpecifier;
479 union {
480 char *string;
481 void *pointer;
482 union {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000483 SLONGEST as_signed;
484 LONGEST as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000485 } number;
486 double doubleNumber;
487 double *doublePointer;
488 long double longdoubleNumber;
489 long double *longdoublePointer;
490 int errorNumber;
491 } data;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000492 /* For the user-defined specifier */
493 char user_name[MAX_USER_NAME];
494 char user_data[MAX_USER_DATA];
Daniel Veillard92ad2102001-03-27 12:47:33 +0000495} parameter_T;
496
Bjorn Reese70a9da52001-04-21 16:57:29 +0000497/* General trio "class" */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000498typedef struct _trio_T {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000499 const void *location;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000500 void (*OutStream)(struct _trio_T *, int);
501 void (*InStream)(struct _trio_T *, int *);
Bjorn Reese70a9da52001-04-21 16:57:29 +0000502 /*
503 * The number of characters that would have been written/read if
Daniel Veillard92ad2102001-03-27 12:47:33 +0000504 * there had been sufficient space.
505 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000506 int processed;
507 /*
508 * The number of characters that are actually written/read.
Daniel Veillard92ad2102001-03-27 12:47:33 +0000509 * Processed and committed with only differ for the *nprintf
510 * and *nscanf functions.
511 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000512 int committed;
513 int max;
514 int current;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000515} trio_T;
516
Bjorn Reese70a9da52001-04-21 16:57:29 +0000517/* References (for user-defined callbacks) */
518typedef struct _reference_T {
519 trio_T *data;
520 parameter_T *parameter;
521} reference_T;
522
523/* Registered entries (for user-defined callbacks) */
524typedef struct _userdef_T {
525 struct _userdef_T *next;
526 trio_callback_t callback;
527 char *name;
528} userdef_T;
529
Daniel Veillard92ad2102001-03-27 12:47:33 +0000530
531/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000532 * Internal variables
Daniel Veillard92ad2102001-03-27 12:47:33 +0000533 */
534
535#if defined(PLATFORM_UNIX)
536extern int errno;
537#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000538static const char null[] = "(nil)";
539
Bjorn Reese70a9da52001-04-21 16:57:29 +0000540#if defined(USE_LOCALE)
541static struct lconv *internalLocaleValues = NULL;
542#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000543
Bjorn Reese70a9da52001-04-21 16:57:29 +0000544/*
545 * UNIX98 says "in a locale where the radix character is not defined,
546 * the radix character defaults to a period (.)"
547 */
548static char internalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH] = ".";
549static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH] = ",";
550static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
551
552static const char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
553static const char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
554static userdef_T *internalUserDef = NULL;
555static BOOLEAN_T internalDigitsUnconverted = TRUE;
556static int internalDigitArray[128];
557
558
559
560/*************************************************************************
561 * trio_strerror [public]
562 */
563const char *trio_strerror(int errorcode)
564{
565 /* Textual versions of the error codes */
566 switch (TRIO_ERROR_CODE(errorcode))
567 {
568 case TRIO_EOF:
569 return "End of file";
570 case TRIO_EINVAL:
571 return "Invalid argument";
572 case TRIO_ETOOMANY:
573 return "Too many arguments";
574 case TRIO_EDBLREF:
575 return "Double reference";
576 case TRIO_EGAP:
577 return "Reference gap";
578 case TRIO_ENOMEM:
579 return "Out of memory";
580 case TRIO_ERANGE:
581 return "Invalid range";
582 default:
583 return "Unknown";
584 }
585}
Daniel Veillard92ad2102001-03-27 12:47:33 +0000586
587/*************************************************************************
588 * TrioIsQualifier [private]
589 *
590 * Description:
591 * Remember to add all new qualifiers to this function.
592 * QUALIFIER_POSITION must not be added.
593 */
594static BOOLEAN_T
595TrioIsQualifier(const char ch)
596{
597 /* QUALIFIER_POSITION is not included */
598 switch (ch)
599 {
600 case '0': case '1': case '2': case '3': case '4':
601 case '5': case '6': case '7': case '8': case '9':
602 case QUALIFIER_PLUS:
603 case QUALIFIER_MINUS:
604 case QUALIFIER_SPACE:
605 case QUALIFIER_DOT:
606 case QUALIFIER_STAR:
607 case QUALIFIER_ALTERNATIVE:
608 case QUALIFIER_SHORT:
609 case QUALIFIER_LONG:
610 case QUALIFIER_LONG_UPPER:
611 case QUALIFIER_CIRCUMFLEX:
612#if defined(QUALIFIER_SIZE_T)
613 case QUALIFIER_SIZE_T:
614#endif
615#if defined(QUALIFIER_PTRDIFF_T)
616 case QUALIFIER_PTRDIFF_T:
617#endif
618#if defined(QUALIFIER_INTMAX_T)
619 case QUALIFIER_INTMAX_T:
620#endif
621#if defined(QUALIFIER_QUAD)
622 case QUALIFIER_QUAD:
623#endif
624#if defined(QUALIFIER_SIZE_T_UPPER)
625 case QUALIFIER_SIZE_T_UPPER:
626#endif
627#if defined(QUALIFIER_WIDECHAR)
628 case QUALIFIER_WIDECHAR:
629#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +0000630#if defined(QUALIFIER_QUOTE)
631 case QUALIFIER_QUOTE:
632#endif
633#if defined(QUALIFIER_STICKY)
634 case QUALIFIER_STICKY:
635#endif
636#if defined(QUALIFIER_VARSIZE)
637 case QUALIFIER_VARSIZE:
638#endif
639#if defined(QUALIFIER_PARAM)
640 case QUALIFIER_PARAM:
641#endif
642 return TRUE;
643 default:
644 return FALSE;
645 }
646}
647
648/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000649 * TrioIsNan [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +0000650 */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000651static int
652TrioIsNan(double number)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000653{
Bjorn Reese70a9da52001-04-21 16:57:29 +0000654#ifdef isnan
655 /* C99 defines isnan() as a macro */
656 return isnan(number);
657#else
658 double integral, fraction;
659
660 return (/* NaN is the only number which does not compare to itself */
661 (number != number) ||
662 /* Fallback solution if NaN compares to NaN */
663 ((number != 0.0) &&
664 (fraction = modf(number, &integral),
665 integral == fraction)));
Daniel Veillard92ad2102001-03-27 12:47:33 +0000666#endif
667}
668
669/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000670 * TrioIsInfinite [private]
671 */
672static int
673TrioIsInfinite(double number)
674{
675#ifdef isinf
676 /* C99 defines isinf() as a macro */
677 return isinf(number);
678#else
679 return ((number == HUGE_VAL) ? 1 : ((number == -HUGE_VAL) ? -1 : 0));
680#endif
681}
682
683/*************************************************************************
684 * TrioSetLocale [private]
685 */
686#if defined(USE_LOCALE)
687static void
688TrioSetLocale(void)
689{
690 internalLocaleValues = (struct lconv *)localeconv();
691 if (StrLength(internalLocaleValues->decimal_point) > 0)
692 {
693 StrCopyMax(internalDecimalPoint,
694 sizeof(internalDecimalPoint),
695 internalLocaleValues->decimal_point);
696 }
697 if (StrLength(internalLocaleValues->thousands_sep) > 0)
698 {
699 StrCopyMax(internalThousandSeparator,
700 sizeof(internalThousandSeparator),
701 internalLocaleValues->thousands_sep);
702 }
703 if (StrLength(internalLocaleValues->grouping) > 0)
704 {
705 StrCopyMax(internalGrouping,
706 sizeof(internalGrouping),
707 internalLocaleValues->grouping);
708 }
709}
710#endif /* defined(USE_LOCALE) */
711
712/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000713 * TrioGetPosition [private]
714 *
715 * Get the %n$ position.
716 */
717static int
Bjorn Reese70a9da52001-04-21 16:57:29 +0000718TrioGetPosition(const char *format,
719 int *indexPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000720{
721 char *tmpformat;
722 int number = 0;
723 int index = *indexPointer;
724
725 number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
726 index = (int)(tmpformat - format);
727 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
728 {
729 *indexPointer = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +0000730 /*
731 * number is decreased by 1, because n$ starts from 1, whereas
Daniel Veillard92ad2102001-03-27 12:47:33 +0000732 * the array it is indexing starts from 0.
733 */
734 return number - 1;
735 }
736 return NO_POSITION;
737}
738
739/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +0000740 * TrioFindNamespace [private]
741 *
742 * Find registered user-defined specifier.
743 * The prev argument is used for optimisation only.
744 */
745static userdef_T *
746TrioFindNamespace(const char *name, userdef_T **prev)
747{
748 userdef_T *def;
749
750 for (def = internalUserDef; def; def = def->next)
751 {
752 /* Case-sensitive string comparison */
753 if (StrEqualCase(def->name, name))
754 return def;
755
756 if (prev)
757 *prev = def;
758 }
759 return def;
760}
761
762/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +0000763 * TrioPreprocess [private]
764 *
765 * Description:
766 * Parse the format string
767 */
768static int
769TrioPreprocess(int type,
770 const char *format,
771 parameter_T *parameters,
Bjorn Reese70a9da52001-04-21 16:57:29 +0000772 va_list arglist,
773 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000774{
775#if defined(TRIO_ERRORS)
776 /* Count the number of times a parameter is referenced */
777 unsigned short usedEntries[MAX_PARAMETERS];
778#endif
779 /* Parameter counters */
780 int parameterPosition;
781 int currentParam;
782 int maxParam = -1;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000783 /* Utility variables */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000784 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000785 int width;
786 int precision;
787 int varsize;
788 int base;
789 int index; /* Index into formatting string */
790 int dots; /* Count number of dots in modifier part */
791 BOOLEAN_T positional; /* Does the specifier have a positional? */
792 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
Bjorn Reese70a9da52001-04-21 16:57:29 +0000793 /*
794 * indices specifies the order in which the parameters must be
Daniel Veillard92ad2102001-03-27 12:47:33 +0000795 * read from the va_args (this is necessary to handle positionals)
796 */
797 int indices[MAX_PARAMETERS];
798 int pos = 0;
799 /* Various variables */
800 char ch;
801 int charlen;
802 int i = -1;
803 int num;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000804 char *tmpformat;
805
806
807#if defined(TRIO_ERRORS)
Bjorn Reese70a9da52001-04-21 16:57:29 +0000808 /*
809 * The 'parameters' array is not initialized, but we need to
Daniel Veillard92ad2102001-03-27 12:47:33 +0000810 * know which entries we have used.
811 */
812 memset(usedEntries, 0, sizeof(usedEntries));
813#endif
814
815 index = 0;
816 parameterPosition = 0;
817#if defined(USE_MULTIBYTE)
818 mblen(NULL, 0);
819#endif
820
821 while (format[index])
822 {
823#if defined(USE_MULTIBYTE)
824 if (! isascii(format[index]))
825 {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000826 /*
827 * Multibyte characters cannot be legal specifiers or
Daniel Veillard92ad2102001-03-27 12:47:33 +0000828 * modifiers, so we skip over them.
829 */
830 charlen = mblen(&format[index], MB_LEN_MAX);
831 index += (charlen > 0) ? charlen : 1;
832 continue; /* while */
833 }
Bjorn Reese70a9da52001-04-21 16:57:29 +0000834#endif /* defined(USE_MULTIBYTE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +0000835 if (CHAR_IDENTIFIER == format[index++])
836 {
837 if (CHAR_IDENTIFIER == format[index])
838 {
839 index++;
840 continue; /* while */
841 }
842
843 flags = FLAGS_NEW;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000844 dots = 0;
845 currentParam = TrioGetPosition(format, &index);
846 positional = (NO_POSITION != currentParam);
847 if (!positional)
848 {
849 /* We have no positional, get the next counter */
850 currentParam = parameterPosition;
851 }
852 if(currentParam >= MAX_PARAMETERS)
853 {
854 /* Bail out completely to make the error more obvious */
855 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
856 }
857
858 if (currentParam > maxParam)
859 maxParam = currentParam;
860
861 /* Default values */
862 width = NO_WIDTH;
863 precision = NO_PRECISION;
864 base = NO_BASE;
865 varsize = NO_SIZE;
866
Bjorn Reese70a9da52001-04-21 16:57:29 +0000867 while (TrioIsQualifier(format[index]))
Daniel Veillard92ad2102001-03-27 12:47:33 +0000868 {
869 ch = format[index++];
870
Daniel Veillard92ad2102001-03-27 12:47:33 +0000871 switch (ch)
872 {
Daniel Veillard92ad2102001-03-27 12:47:33 +0000873 case QUALIFIER_SPACE:
874 flags |= FLAGS_SPACE;
875 break;
876
877 case QUALIFIER_PLUS:
878 flags |= FLAGS_SHOWSIGN;
879 break;
880
881 case QUALIFIER_MINUS:
882 flags |= FLAGS_LEFTADJUST;
883 flags &= ~FLAGS_NILPADDING;
884 break;
885
886 case QUALIFIER_ALTERNATIVE:
887 flags |= FLAGS_ALTERNATIVE;
888 break;
889
890 case QUALIFIER_DOT:
891 if (dots == 0) /* Precision */
892 {
893 dots++;
894
895 /* Skip if no precision */
896 if (QUALIFIER_DOT == format[index])
897 break;
898
899 /* After the first dot we have the precision */
900 flags |= FLAGS_PRECISION;
901 if ((QUALIFIER_STAR == format[index]) ||
902 (QUALIFIER_PARAM == format[index]))
903 {
904 index++;
905 flags |= FLAGS_PRECISION_PARAMETER;
906
907 precision = TrioGetPosition(format, &index);
908 if (precision == NO_POSITION)
909 {
910 parameterPosition++;
911 if (positional)
912 precision = parameterPosition;
913 else
914 {
915 precision = currentParam;
916 currentParam = precision + 1;
917 }
918 }
919 else
920 {
921 if (! positional)
922 currentParam = precision + 1;
923 if (width > maxParam)
924 maxParam = precision;
925 }
926 if (currentParam > maxParam)
927 maxParam = currentParam;
928 }
929 else
930 {
931 precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
932 index = (int)(tmpformat - format);
933 }
934 }
935 else if (dots == 1) /* Base */
936 {
937 dots++;
938
939 /* After the second dot we have the base */
940 flags |= FLAGS_BASE;
941 if ((QUALIFIER_STAR == format[index]) ||
942 (QUALIFIER_PARAM == format[index]))
943 {
944 index++;
945 flags |= FLAGS_BASE_PARAMETER;
946 base = TrioGetPosition(format, &index);
947 if (base == NO_POSITION)
948 {
949 parameterPosition++;
950 if (positional)
951 base = parameterPosition;
952 else
953 {
954 base = currentParam;
955 currentParam = base + 1;
956 }
957 }
958 else
959 {
960 if (! positional)
961 currentParam = base + 1;
962 if (base > maxParam)
963 maxParam = base;
964 }
965 if (currentParam > maxParam)
966 maxParam = currentParam;
967 }
968 else
969 {
970 base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
971 if (base > MAX_BASE)
972 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
973 index = (int)(tmpformat - format);
974 }
975 }
976 else
977 {
978 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
979 }
980 break; /* QUALIFIER_DOT */
981
982 case QUALIFIER_PARAM:
983 type = TYPE_PRINT;
984 /* FALLTHROUGH */
985 case QUALIFIER_STAR:
986 /* This has different meanings for print and scan */
987 if (TYPE_PRINT == type)
988 {
989 /* Read with from parameter */
990 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
991 width = TrioGetPosition(format, &index);
992 if (width == NO_POSITION)
993 {
994 parameterPosition++;
995 if (positional)
996 width = parameterPosition;
997 else
998 {
999 width = currentParam;
1000 currentParam = width + 1;
1001 }
1002 }
1003 else
1004 {
1005 if (! positional)
1006 currentParam = width + 1;
1007 if (width > maxParam)
1008 maxParam = width;
1009 }
1010 if (currentParam > maxParam)
1011 maxParam = currentParam;
1012 }
1013 else
1014 {
1015 /* Scan, but do not store result */
1016 flags |= FLAGS_IGNORE;
1017 }
1018
1019 break; /* QUALIFIER_STAR */
1020
1021 case '0':
1022 if (! (flags & FLAGS_LEFTADJUST))
1023 flags |= FLAGS_NILPADDING;
1024 /* FALLTHROUGH */
1025 case '1': case '2': case '3': case '4':
1026 case '5': case '6': case '7': case '8': case '9':
1027 flags |= FLAGS_WIDTH;
1028 /* &format[index - 1] is used to "rewind" the read
1029 * character from format
1030 */
1031 width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
1032 index = (int)(tmpformat - format);
1033 break;
1034
1035 case QUALIFIER_SHORT:
1036 if (flags & FLAGS_SHORTSHORT)
1037 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1038 else if (flags & FLAGS_SHORT)
1039 flags |= FLAGS_SHORTSHORT;
1040 else
1041 flags |= FLAGS_SHORT;
1042 break;
1043
1044 case QUALIFIER_LONG:
1045 if (flags & FLAGS_QUAD)
1046 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1047 else if (flags & FLAGS_LONG)
1048 flags |= FLAGS_QUAD;
1049 else
1050 flags |= FLAGS_LONG;
1051 break;
1052
1053 case QUALIFIER_LONG_UPPER:
1054 flags |= FLAGS_LONGDOUBLE;
1055 break;
1056
1057#if defined(QUALIFIER_SIZE_T)
1058 case QUALIFIER_SIZE_T:
1059 flags |= FLAGS_SIZE_T;
1060 /* Modify flags for later truncation of number */
1061 if (sizeof(size_t) == sizeof(ULONGLONG))
1062 flags |= FLAGS_QUAD;
1063 else if (sizeof(size_t) == sizeof(long))
1064 flags |= FLAGS_LONG;
1065 break;
1066#endif
1067
1068#if defined(QUALIFIER_PTRDIFF_T)
1069 case QUALIFIER_PTRDIFF_T:
1070 flags |= FLAGS_PTRDIFF_T;
1071 if (sizeof(ptrdiff_t) == sizeof(ULONGLONG))
1072 flags |= FLAGS_QUAD;
1073 else if (sizeof(ptrdiff_t) == sizeof(long))
1074 flags |= FLAGS_LONG;
1075 break;
1076#endif
1077
1078#if defined(QUALIFIER_INTMAX_T)
1079 case QUALIFIER_INTMAX_T:
1080 flags |= FLAGS_INTMAX_T;
1081 if (sizeof(intmax_t) == sizeof(ULONGLONG))
1082 flags |= FLAGS_QUAD;
1083 else if (sizeof(intmax_t) == sizeof(long))
1084 flags |= FLAGS_LONG;
1085 break;
1086#endif
1087
1088#if defined(QUALIFIER_QUAD)
1089 case QUALIFIER_QUAD:
1090 flags |= FLAGS_QUAD;
1091 break;
1092#endif
1093
1094#if defined(QUALIFIER_WIDECHAR)
1095 case QUALIFIER_WIDECHAR:
1096 flags |= FLAGS_WIDECHAR;
1097 break;
1098#endif
1099
1100#if defined(QUALIFIER_SIZE_T_UPPER)
1101 case QUALIFIER_SIZE_T_UPPER:
1102 break;
1103#endif
1104
1105#if defined(QUALIFIER_QUOTE)
1106 case QUALIFIER_QUOTE:
1107 flags |= FLAGS_QUOTE;
1108 break;
1109#endif
1110
1111#if defined(QUALIFIER_STICKY)
1112 case QUALIFIER_STICKY:
1113 flags |= FLAGS_STICKY;
1114 got_sticky = TRUE;
1115 break;
1116#endif
1117
1118#if defined(QUALIFIER_VARSIZE)
1119 case QUALIFIER_VARSIZE:
1120 flags |= FLAGS_SIZE_PARAMETER;
1121 parameterPosition++;
1122 if (positional)
1123 varsize = parameterPosition;
1124 else
1125 {
1126 varsize = currentParam;
1127 currentParam = varsize + 1;
1128 }
1129 if (currentParam > maxParam)
1130 maxParam = currentParam;
1131 break;
1132#endif
1133
1134 default:
1135 /* Bail out completely to make the error more obvious */
1136 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1137 }
1138 } /* while qualifier */
1139
Bjorn Reese70a9da52001-04-21 16:57:29 +00001140 /*
1141 * Parameters only need the type and value. The value is
Daniel Veillard92ad2102001-03-27 12:47:33 +00001142 * read later.
1143 */
1144 if (flags & FLAGS_WIDTH_PARAMETER)
1145 {
1146#if defined(TRIO_ERRORS)
1147 usedEntries[width] += 1;
1148#endif
1149 parameters[pos].type = FORMAT_PARAMETER;
1150 indices[width] = pos;
1151 width = pos++;
1152 }
1153 if (flags & FLAGS_PRECISION_PARAMETER)
1154 {
1155#if defined(TRIO_ERRORS)
1156 usedEntries[precision] += 1;
1157#endif
1158 parameters[pos].type = FORMAT_PARAMETER;
1159 indices[precision] = pos;
1160 precision = pos++;
1161 }
1162 if (flags & FLAGS_BASE_PARAMETER)
1163 {
1164#if defined(TRIO_ERRORS)
1165 usedEntries[base] += 1;
1166#endif
1167 parameters[pos].type = FORMAT_PARAMETER;
1168 indices[base] = pos;
1169 base = pos++;
1170 }
1171 if (flags & FLAGS_SIZE_PARAMETER)
1172 {
1173#if defined(TRIO_ERRORS)
1174 usedEntries[varsize] += 1;
1175#endif
1176 parameters[pos].type = FORMAT_PARAMETER;
1177 indices[varsize] = pos;
1178 varsize = pos++;
1179 }
1180
1181 indices[currentParam] = pos;
1182
1183 switch (format[index++])
1184 {
1185#if defined(SPECIFIER_CHAR_UPPER)
1186 case SPECIFIER_CHAR_UPPER:
1187 flags |= FLAGS_LONG;
1188 /* FALLTHROUGH */
1189#endif
1190 case SPECIFIER_CHAR:
1191 parameters[pos].type = FORMAT_CHAR;
1192 break;
1193
1194#if defined(SPECIFIER_STRING_UPPER)
1195 case SPECIFIER_STRING_UPPER:
1196 flags |= FLAGS_LONG;
1197 /* FALLTHROUGH */
1198#endif
1199 case SPECIFIER_STRING:
1200 parameters[pos].type = FORMAT_STRING;
1201 break;
1202
1203 case SPECIFIER_GROUP:
1204 if (TYPE_SCAN == type)
1205 {
1206 parameters[pos].type = FORMAT_GROUP;
1207 while (format[index])
1208 {
1209 if (format[index++] == SPECIFIER_UNGROUP)
1210 break; /* while */
1211 }
1212 }
1213 break;
1214
1215 case SPECIFIER_INTEGER:
1216 parameters[pos].type = FORMAT_INT;
1217 break;
1218
1219 case SPECIFIER_UNSIGNED:
1220 flags |= FLAGS_UNSIGNED;
1221 parameters[pos].type = FORMAT_INT;
1222 break;
1223
1224 case SPECIFIER_DECIMAL:
1225 /* Disable base modifier */
1226 flags &= ~FLAGS_BASE_PARAMETER;
1227 base = BASE_DECIMAL;
1228 parameters[pos].type = FORMAT_INT;
1229 break;
1230
1231 case SPECIFIER_OCTAL:
1232 flags &= ~FLAGS_BASE_PARAMETER;
1233 base = BASE_OCTAL;
1234 parameters[pos].type = FORMAT_INT;
1235 break;
1236
1237#if defined(SPECIFIER_BINARY)
1238 case SPECIFIER_BINARY_UPPER:
1239 flags |= FLAGS_UPPER;
1240 /* FALLTHROUGH */
1241 case SPECIFIER_BINARY:
1242 flags |= FLAGS_NILPADDING;
1243 flags &= ~FLAGS_BASE_PARAMETER;
1244 base = BASE_BINARY;
1245 parameters[pos].type = FORMAT_INT;
1246 break;
1247#endif
1248
1249 case SPECIFIER_HEX_UPPER:
1250 flags |= FLAGS_UPPER;
1251 /* FALLTHROUGH */
1252 case SPECIFIER_HEX:
1253 flags |= FLAGS_UNSIGNED;
1254 flags &= ~FLAGS_BASE_PARAMETER;
1255 base = BASE_HEX;
1256 parameters[pos].type = FORMAT_INT;
1257 break;
1258
1259 case SPECIFIER_FLOAT_E_UPPER:
1260 flags |= FLAGS_UPPER;
1261 /* FALLTHROUGH */
1262 case SPECIFIER_FLOAT_E:
1263 flags |= FLAGS_FLOAT_E;
1264 parameters[pos].type = FORMAT_DOUBLE;
1265 break;
1266
1267 case SPECIFIER_FLOAT_G_UPPER:
1268 flags |= FLAGS_UPPER;
1269 /* FALLTHROUGH */
1270 case SPECIFIER_FLOAT_G:
1271 flags |= FLAGS_FLOAT_G;
1272 parameters[pos].type = FORMAT_DOUBLE;
1273 break;
1274
1275 case SPECIFIER_FLOAT_F_UPPER:
1276 flags |= FLAGS_UPPER;
1277 /* FALLTHROUGH */
1278 case SPECIFIER_FLOAT_F:
1279 parameters[pos].type = FORMAT_DOUBLE;
1280 break;
1281
1282 case SPECIFIER_POINTER:
1283 parameters[pos].type = FORMAT_POINTER;
1284 break;
1285
1286 case SPECIFIER_COUNT:
1287 parameters[pos].type = FORMAT_COUNT;
1288 break;
1289
1290#if defined(SPECIFIER_HEXFLOAT)
1291# if defined(SPECIFIER_HEXFLOAT_UPPER)
1292 case SPECIFIER_HEXFLOAT_UPPER:
1293 flags |= FLAGS_UPPER;
1294 /* FALLTHROUGH */
1295# endif
1296 case SPECIFIER_HEXFLOAT:
1297 base = BASE_HEX;
1298 parameters[pos].type = FORMAT_DOUBLE;
1299 break;
1300#endif
1301
1302#if defined(FORMAT_ERRNO)
1303 case SPECIFIER_ERRNO:
1304 parameters[pos].type = FORMAT_ERRNO;
1305 break;
1306#endif
1307
Bjorn Reese70a9da52001-04-21 16:57:29 +00001308#if defined(SPECIFIER_USER_DEFINED_BEGIN)
1309 case SPECIFIER_USER_DEFINED_BEGIN:
1310 {
1311 unsigned int max;
1312 int without_namespace = TRUE;
1313
1314 parameters[pos].type = FORMAT_USER_DEFINED;
1315 parameters[pos].user_name[0] = NIL;
1316 tmpformat = (char *)&format[index];
1317
1318 while ((ch = format[index]))
1319 {
1320 index++;
1321 if (ch == SPECIFIER_USER_DEFINED_END)
1322 {
1323 if (without_namespace)
1324 {
1325 /* We must get the handle first */
1326 parameters[pos].type = FORMAT_PARAMETER;
1327 parameters[pos].indexAfterSpecifier = index;
1328 parameters[pos].flags = FLAGS_USER_DEFINED;
1329 /* Adjust parameters for insertion of new one */
1330 pos++;
1331# if defined(TRIO_ERRORS)
1332 usedEntries[currentParam] += 1;
1333# endif
1334 parameters[pos].type = FORMAT_USER_DEFINED;
1335 currentParam++;
1336 indices[currentParam] = pos;
1337 if (currentParam > maxParam)
1338 maxParam = currentParam;
1339 }
1340 /* Copy the user data */
1341 max = (unsigned int)(&format[index] - tmpformat);
1342 if (max > MAX_USER_DATA)
1343 max = MAX_USER_DATA;
1344 StrCopyMax(parameters[pos].user_data,
1345 max,
1346 tmpformat);
1347 break; /* while */
1348 }
1349 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1350 {
1351 without_namespace = FALSE;
1352 /* Copy the namespace for later looking-up */
1353 max = (int)(&format[index] - tmpformat);
1354 if (max > MAX_USER_NAME)
1355 max = MAX_USER_NAME;
1356 StrCopyMax(parameters[pos].user_name,
1357 max,
1358 tmpformat);
1359 tmpformat = (char *)&format[index];
1360 }
1361 }
1362 if (ch != SPECIFIER_USER_DEFINED_END)
1363 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1364 }
1365 break;
1366#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1367
Daniel Veillard92ad2102001-03-27 12:47:33 +00001368 default:
1369 /* Bail out completely to make the error more obvious */
1370 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1371 }
1372
1373#if defined(TRIO_ERRORS)
1374 /* Count the number of times this entry has been used */
1375 usedEntries[currentParam] += 1;
1376#endif
1377
1378 /* Find last sticky parameters */
1379 if (got_sticky && !(flags & FLAGS_STICKY))
1380 {
1381 for (i = pos - 1; i >= 0; i--)
1382 {
1383 if (parameters[i].type == FORMAT_PARAMETER)
1384 continue;
1385 if ((parameters[i].flags & FLAGS_STICKY) &&
1386 (parameters[i].type == parameters[pos].type))
1387 {
1388 /* Do not overwrite current qualifiers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001389 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001390 if (width == NO_WIDTH)
1391 width = parameters[i].width;
1392 if (precision == NO_PRECISION)
1393 precision = parameters[i].precision;
1394 if (base == NO_BASE)
1395 base = parameters[i].base;
1396 break;
1397 }
1398 }
1399 }
1400
1401 parameters[pos].indexAfterSpecifier = index;
1402 parameters[pos].flags = flags;
1403 parameters[pos].width = width;
1404 parameters[pos].precision = precision;
1405 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1406 parameters[pos].varsize = varsize;
1407 pos++;
1408
Bjorn Reese70a9da52001-04-21 16:57:29 +00001409 if (! positional)
Daniel Veillard92ad2102001-03-27 12:47:33 +00001410 parameterPosition++;
1411
1412 } /* if identifier */
1413
1414 } /* while format characters left */
1415
1416 for (num = 0; num <= maxParam; num++)
1417 {
1418#if defined(TRIO_ERRORS)
1419 if (usedEntries[num] != 1)
1420 {
1421 if (usedEntries[num] == 0) /* gap detected */
1422 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1423 else /* double references detected */
1424 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1425 }
1426#endif
1427
1428 i = indices[num];
1429
Bjorn Reese70a9da52001-04-21 16:57:29 +00001430 /*
1431 * FORMAT_PARAMETERS are only present if they must be read,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001432 * so it makes no sense to check the ignore flag (besides,
1433 * the flags variable is not set for that particular type)
1434 */
1435 if ((parameters[i].type != FORMAT_PARAMETER) &&
1436 (parameters[i].flags & FLAGS_IGNORE))
1437 continue; /* for all arguments */
1438
Bjorn Reese70a9da52001-04-21 16:57:29 +00001439 /*
1440 * The stack arguments are read according to ANSI C89
Daniel Veillard92ad2102001-03-27 12:47:33 +00001441 * default argument promotions:
1442 *
1443 * char = int
1444 * short = int
1445 * unsigned char = unsigned int
1446 * unsigned short = unsigned int
1447 * float = double
1448 *
1449 * In addition to the ANSI C89 these types are read (the
1450 * default argument promotions of C99 has not been
1451 * considered yet)
1452 *
1453 * long long
1454 * long double
1455 * size_t
1456 * ptrdiff_t
1457 * intmax_t
1458 */
1459 switch (parameters[i].type)
1460 {
1461 case FORMAT_GROUP:
1462 case FORMAT_STRING:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001463 parameters[i].data.string = (arglist != NULL)
1464 ? va_arg(arglist, char *)
1465 : (char *)(argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001466 break;
1467
1468 case FORMAT_POINTER:
1469 case FORMAT_COUNT:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001470 case FORMAT_USER_DEFINED:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001471 case FORMAT_UNKNOWN:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001472 parameters[i].data.pointer = (arglist != NULL)
1473 ? va_arg(arglist, void *)
1474 : argarray[num];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001475 break;
1476
1477 case FORMAT_CHAR:
1478 case FORMAT_INT:
1479 if (TYPE_SCAN == type)
1480 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001481 if (arglist != NULL)
1482 parameters[i].data.pointer =
1483 (LONGEST *)va_arg(arglist, void *);
1484 else
1485 {
1486 if (parameters[i].type == FORMAT_CHAR)
1487 parameters[i].data.pointer =
1488 (LONGEST *)((char *)argarray[num]);
1489 else if (parameters[i].flags & FLAGS_SHORT)
1490 parameters[i].data.pointer =
1491 (LONGEST *)((short *)argarray[num]);
1492 else
1493 parameters[i].data.pointer =
1494 (LONGEST *)((int *)argarray[num]);
1495 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001496 }
1497 else
1498 {
1499#if defined(QUALIFIER_VARSIZE)
1500 if (parameters[i].flags & FLAGS_SIZE_PARAMETER)
1501 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001502 /*
1503 * Variable sizes are mapped onto the fixed sizes, in
1504 * accordance with integer promotion.
1505 *
1506 * Please note that this may not be portable, as we
1507 * only guess the size, not the layout of the numbers.
1508 * For example, if int is little-endian, and long is
1509 * big-endian, then this will fail.
Daniel Veillard92ad2102001-03-27 12:47:33 +00001510 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001511 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
1512 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001513 if (varsize <= (int)sizeof(int))
1514 ;
1515 else if (varsize <= (int)sizeof(long))
1516 parameters[i].flags |= FLAGS_LONG;
1517#if defined(QUALIFIER_INTMAX_T)
1518 else if (varsize <= (int)sizeof(LONGLONG))
1519 parameters[i].flags |= FLAGS_QUAD;
1520 else
1521 parameters[i].flags |= FLAGS_INTMAX_T;
1522#else
1523 else
1524 parameters[i].flags |= FLAGS_QUAD;
1525#endif
1526 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001527#endif /* defined(QUALIFIER_VARSIZE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001528#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1529 if (parameters[i].flags & FLAGS_SIZE_T)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001530 parameters[i].data.number.as_unsigned = (arglist != NULL)
1531 ? (LONGEST)va_arg(arglist, size_t)
1532 : (LONGEST)(*((size_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001533 else
1534#endif
1535#if defined(QUALIFIER_PTRDIFF_T)
1536 if (parameters[i].flags & FLAGS_PTRDIFF_T)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001537 parameters[i].data.number.as_unsigned = (arglist != NULL)
1538 ? (LONGEST)va_arg(arglist, ptrdiff_t)
1539 : (LONGEST)(*((ptrdiff_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001540 else
1541#endif
1542#if defined(QUALIFIER_INTMAX_T)
1543 if (parameters[i].flags & FLAGS_INTMAX_T)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001544 parameters[i].data.number.as_unsigned = (arglist != NULL)
1545 ? (LONGEST)va_arg(arglist, intmax_t)
1546 : (LONGEST)(*((intmax_t *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001547 else
1548#endif
1549 if (parameters[i].flags & FLAGS_QUAD)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001550 parameters[i].data.number.as_unsigned = (arglist != NULL)
1551 ? (LONGEST)va_arg(arglist, ULONGLONG)
1552 : (LONGEST)(*((ULONGLONG *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001553 else if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001554 parameters[i].data.number.as_unsigned = (arglist != NULL)
1555 ? (LONGEST)va_arg(arglist, long)
1556 : (LONGEST)(*((long *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001557 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001558 {
1559 if (arglist != NULL)
1560 parameters[i].data.number.as_unsigned = (LONGEST)va_arg(arglist, int);
1561 else
1562 {
1563 if (parameters[i].type == FORMAT_CHAR)
1564 parameters[i].data.number.as_unsigned = (LONGEST)(*((char *)argarray[num]));
1565 else if (parameters[i].flags & FLAGS_SHORT)
1566 parameters[i].data.number.as_unsigned = (LONGEST)(*((short *)argarray[num]));
1567 else
1568 parameters[i].data.number.as_unsigned = (LONGEST)(*((int *)argarray[num]));
1569 }
1570 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001571 }
1572 break;
1573
1574 case FORMAT_PARAMETER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001575 /*
1576 * The parameter for the user-defined specifier is a pointer,
1577 * whereas the rest (width, precision, base) uses an integer.
1578 */
1579 if (parameters[i].flags & FLAGS_USER_DEFINED)
1580 parameters[i].data.pointer = (arglist != NULL)
1581 ? va_arg(arglist, void *)
1582 : argarray[num];
1583 else
1584 parameters[i].data.number.as_unsigned = (arglist != NULL)
1585 ? (LONGEST)va_arg(arglist, int)
1586 : (LONGEST)(*((int *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001587 break;
1588
1589 case FORMAT_DOUBLE:
1590 if (TYPE_SCAN == type)
1591 {
1592 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001593 parameters[i].data.longdoublePointer = (arglist != NULL)
1594 ? va_arg(arglist, long double *)
1595 : (long double *)((long double *)argarray[num]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001596 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001597 {
1598 if (arglist != NULL)
1599 parameters[i].data.doublePointer =
1600 va_arg(arglist, double *);
1601 else
1602 {
1603 if (parameters[i].flags & FLAGS_SHORT)
1604 parameters[i].data.doublePointer =
1605 (double *)((float *)argarray[num]);
1606 else
1607 parameters[i].data.doublePointer =
1608 (double *)((double *)argarray[num]);
1609 }
1610 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001611 }
1612 else
1613 {
1614 if (parameters[i].flags & FLAGS_LONG)
Bjorn Reese70a9da52001-04-21 16:57:29 +00001615 parameters[i].data.longdoubleNumber = (arglist != NULL)
1616 ? va_arg(arglist, long double)
1617 : (long double)(*((long double *)argarray[num]));
Daniel Veillard92ad2102001-03-27 12:47:33 +00001618 else
Bjorn Reese70a9da52001-04-21 16:57:29 +00001619 {
1620 if (arglist != NULL)
1621 parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
1622 else
1623 {
1624 if (parameters[i].flags & FLAGS_SHORT)
1625 parameters[i].data.longdoubleNumber = (long double)(*((float *)argarray[num]));
1626 else
1627 parameters[i].data.longdoubleNumber = (long double)(long double)(*((double *)argarray[num]));
1628 }
1629 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00001630 }
1631 break;
1632
1633#if defined(FORMAT_ERRNO)
1634 case FORMAT_ERRNO:
1635 parameters[i].data.errorNumber = errno;
1636 break;
1637#endif
1638
1639 default:
1640 break;
1641 }
1642 } /* for all specifiers */
1643 return num;
1644}
1645
1646
1647/*************************************************************************
1648 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00001649 * @FORMATTING
Daniel Veillard92ad2102001-03-27 12:47:33 +00001650 *
1651 ************************************************************************/
1652
1653
1654/*************************************************************************
1655 * TrioWriteNumber [private]
1656 *
1657 * Description:
1658 * Output a number.
1659 * The complexity of this function is a result of the complexity
1660 * of the dependencies of the flags.
1661 */
1662static void
1663TrioWriteNumber(trio_T *self,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001664 SLONGEST number,
1665 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001666 int width,
1667 int precision,
1668 int base)
1669{
1670 BOOLEAN_T isNegative;
1671 char buffer[MAX_CHARS_IN(LONGEST)
1672 * MAX_LOCALE_SEPARATOR_LENGTH
1673 * MAX_LOCALE_GROUPS];
1674 char *bufferend;
1675 char *pointer;
1676 const char *digits;
1677 int i;
1678 int length;
1679 char *p;
1680 int charsPerThousand;
1681 int groupingIndex;
1682 int count;
1683
1684 assert(VALID(self));
1685 assert(VALID(self->OutStream));
1686 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
1687
Bjorn Reese70a9da52001-04-21 16:57:29 +00001688 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001689
1690 if (flags & FLAGS_UNSIGNED)
1691 isNegative = FALSE;
1692 else if ((isNegative = (((SLONGEST)number) < 0)))
1693 number = -number;
1694
1695 if (flags & FLAGS_QUAD)
1696 number &= (ULONGLONG)-1;
1697 else if (flags & FLAGS_LONG)
1698 number &= (unsigned long)-1;
1699 else
1700 number &= (unsigned int)-1;
1701
1702 /* Build number */
1703 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1704 *pointer-- = NIL;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001705 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001706 groupingIndex = 1;
1707 for (i = 1; i < (int)sizeof(buffer); i++)
1708 {
1709 *pointer-- = digits[number % base];
1710 number /= base;
1711 if (number == 0)
1712 break;
1713
1714 if ((flags & FLAGS_QUOTE)
1715 && (charsPerThousand != NO_GROUPING)
1716 && (i % charsPerThousand == 0))
1717 {
1718 /*
1719 * We are building the number from the least significant
1720 * to the most significant digit, so we have to copy the
1721 * thousand separator backwards
1722 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001723 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00001724 if (((int)(pointer - buffer) - length) > 0)
1725 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001726 p = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001727 while (length-- > 0)
1728 *pointer-- = *p--;
1729 }
1730
1731 /* Advance to next grouping number */
Bjorn Reese70a9da52001-04-21 16:57:29 +00001732 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00001733 {
1734 case CHAR_MAX: /* Disable grouping */
1735 charsPerThousand = NO_GROUPING;
1736 break;
1737 case 0: /* Repeat last group */
1738 break;
1739 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001740 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00001741 break;
1742 }
1743 }
1744 }
1745
1746 /* Adjust width */
1747 width -= (bufferend - pointer) - 1;
1748
1749 /* Adjust precision */
1750 if (NO_PRECISION != precision)
1751 {
1752 precision -= (bufferend - pointer) - 1;
1753 if (precision < 0)
1754 precision = 0;
1755 flags |= FLAGS_NILPADDING;
1756 }
1757
1758 /* Adjust width further */
1759 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
1760 width--;
1761 if (flags & FLAGS_ALTERNATIVE)
1762 {
1763 switch (base)
1764 {
1765 case BASE_BINARY:
1766 case BASE_HEX:
1767 width -= 2;
1768 break;
1769 case BASE_OCTAL:
1770 width--;
1771 break;
1772 default:
1773 break;
1774 }
1775 }
1776
1777 /* Output prefixes spaces if needed */
1778 if (! ((flags & FLAGS_LEFTADJUST) ||
1779 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
1780 {
1781 count = (precision == NO_PRECISION) ? 0 : precision;
1782 while (width-- > count)
1783 self->OutStream(self, CHAR_ADJUST);
1784 }
1785
1786 /* width has been adjusted for signs and alternatives */
1787 if (isNegative)
1788 self->OutStream(self, '-');
1789 else if (flags & FLAGS_SHOWSIGN)
1790 self->OutStream(self, '+');
1791 else if (flags & FLAGS_SPACE)
1792 self->OutStream(self, ' ');
1793
1794 if (flags & FLAGS_ALTERNATIVE)
1795 {
1796 switch (base)
1797 {
1798 case BASE_BINARY:
1799 self->OutStream(self, '0');
1800 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
1801 break;
1802
1803 case BASE_OCTAL:
1804 self->OutStream(self, '0');
1805 break;
1806
1807 case BASE_HEX:
1808 self->OutStream(self, '0');
1809 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
1810 break;
1811
1812 default:
1813 break;
1814 } /* switch base */
1815 }
1816
1817 /* Output prefixed zero padding if needed */
1818 if (flags & FLAGS_NILPADDING)
1819 {
1820 if (precision == NO_PRECISION)
1821 precision = width;
1822 while (precision-- > 0)
1823 {
1824 self->OutStream(self, '0');
1825 width--;
1826 }
1827 }
1828
1829 /* Output the number itself */
1830 while (*(++pointer))
1831 {
1832 self->OutStream(self, *pointer);
1833 }
1834
1835 /* Output trailing spaces if needed */
1836 if (flags & FLAGS_LEFTADJUST)
1837 {
1838 while (width-- > 0)
1839 self->OutStream(self, CHAR_ADJUST);
1840 }
1841}
1842
1843/*************************************************************************
1844 * TrioWriteString [private]
1845 *
1846 * Description:
1847 * Output a string
1848 */
1849static void
1850TrioWriteString(trio_T *self,
1851 const char *string,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001852 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001853 int width,
1854 int precision)
1855{
1856 int length;
1857 int ch;
1858
1859 assert(VALID(self));
1860 assert(VALID(self->OutStream));
1861
1862 if (string == NULL)
1863 {
1864 string = null;
1865 length = sizeof(null) - 1;
1866 /* Disable quoting for the null pointer */
1867 flags &= (~FLAGS_QUOTE);
1868 width = 0;
1869 }
1870 else
1871 {
1872 length = StrLength(string);
1873 }
1874 if ((NO_PRECISION != precision) &&
1875 (precision < length))
1876 {
1877 length = precision;
1878 }
1879 width -= length;
1880
1881 if (flags & FLAGS_QUOTE)
1882 self->OutStream(self, CHAR_QUOTE);
1883
1884 if (! (flags & FLAGS_LEFTADJUST))
1885 {
1886 while (width-- > 0)
1887 self->OutStream(self, CHAR_ADJUST);
1888 }
1889
1890 while (length-- > 0)
1891 {
1892 /* The ctype parameters must be an unsigned char (or EOF) */
1893 ch = (unsigned char)(*string++);
1894 if (flags & FLAGS_ALTERNATIVE)
1895 {
1896 if (! (isprint(ch) || isspace(ch)))
1897 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001898 /*
1899 * Non-printable characters are converted to C escapes or
Daniel Veillard92ad2102001-03-27 12:47:33 +00001900 * \number, if no C escape exists.
1901 */
1902 self->OutStream(self, CHAR_BACKSLASH);
1903 switch (ch)
1904 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001905 case '\a': self->OutStream(self, 'a'); break;
1906 case '\b': self->OutStream(self, 'b'); break;
1907 case '\f': self->OutStream(self, 'f'); break;
1908 case '\n': self->OutStream(self, 'n'); break;
1909 case '\r': self->OutStream(self, 'r'); break;
1910 case '\t': self->OutStream(self, 't'); break;
1911 case '\v': self->OutStream(self, 'v'); break;
1912 case '\\': self->OutStream(self, '\\'); break;
1913 default:
Daniel Veillard92ad2102001-03-27 12:47:33 +00001914 self->OutStream(self, 'x');
Bjorn Reese70a9da52001-04-21 16:57:29 +00001915 TrioWriteNumber(self, (SLONGEST)ch,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001916 FLAGS_UNSIGNED | FLAGS_NILPADDING,
1917 2, 2, BASE_HEX);
1918 break;
1919 }
1920 }
1921 else if (ch == CHAR_BACKSLASH)
1922 {
1923 self->OutStream(self, CHAR_BACKSLASH);
1924 self->OutStream(self, CHAR_BACKSLASH);
1925 }
1926 else
1927 {
1928 self->OutStream(self, ch);
1929 }
1930 }
1931 else
1932 {
1933 self->OutStream(self, ch);
1934 }
1935 }
1936
1937 if (flags & FLAGS_LEFTADJUST)
1938 {
1939 while (width-- > 0)
1940 self->OutStream(self, CHAR_ADJUST);
1941 }
1942 if (flags & FLAGS_QUOTE)
1943 self->OutStream(self, CHAR_QUOTE);
1944}
1945
1946/*************************************************************************
1947 * TrioWriteDouble [private]
1948 */
1949static void
1950TrioWriteDouble(trio_T *self,
1951 long double longdoubleNumber,
Bjorn Reese70a9da52001-04-21 16:57:29 +00001952 unsigned long flags,
Daniel Veillard92ad2102001-03-27 12:47:33 +00001953 int width,
1954 int precision,
1955 int base)
1956{
1957 int charsPerThousand;
1958 int length;
1959 double number;
1960 double precisionPower;
1961 double workNumber;
1962 int integerDigits;
1963 int fractionDigits;
1964 int exponentDigits;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001965 int expectedWidth;
1966 int exponent;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001967 unsigned int uExponent = 0;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001968 double dblBase;
1969 BOOLEAN_T isNegative;
1970 BOOLEAN_T isExponentNegative = FALSE;
1971 BOOLEAN_T isHex;
1972 const char *digits;
1973 char numberBuffer[MAX_CHARS_IN(double)
1974 * MAX_LOCALE_SEPARATOR_LENGTH
1975 * MAX_LOCALE_GROUPS];
1976 char *numberPointer;
1977 char exponentBuffer[MAX_CHARS_IN(double)];
Bjorn Reese70a9da52001-04-21 16:57:29 +00001978 char *exponentPointer = NULL;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001979 int groupingIndex;
1980 char *work;
1981 int i;
1982 BOOLEAN_T onlyzero;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001983
1984 int set_precision = precision;
Daniel Veillard92ad2102001-03-27 12:47:33 +00001985
1986 assert(VALID(self));
1987 assert(VALID(self->OutStream));
1988 assert(base == BASE_DECIMAL || base == BASE_HEX);
1989
1990 number = (double)longdoubleNumber;
1991
Bjorn Reese70a9da52001-04-21 16:57:29 +00001992#if defined(USE_NON_NUMBERS)
1993 /* Look for infinite numbers and non-a-number first */
1994 switch (TrioIsInfinite(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00001995 {
1996 case 1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00001997 /* Positive infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00001998 TrioWriteString(self,
1999 (flags & FLAGS_UPPER)
2000 ? INFINITE_UPPER
2001 : INFINITE_LOWER,
2002 flags, width, precision);
2003 return;
2004
2005 case -1:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002006 /* Negative infinity */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002007 TrioWriteString(self,
2008 (flags & FLAGS_UPPER)
2009 ? "-" INFINITE_UPPER
2010 : "-" INFINITE_LOWER,
2011 flags, width, precision);
2012 return;
2013
2014 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002015 /* Finitude */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002016 break;
2017 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002018 if (TrioIsNan(number))
Daniel Veillard92ad2102001-03-27 12:47:33 +00002019 {
2020 TrioWriteString(self,
2021 (flags & FLAGS_UPPER)
2022 ? NAN_UPPER
2023 : NAN_LOWER,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002024 flags, width, precision);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002025 return;
2026 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002027#endif /* defined(USE_NON_NUMBERS) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002028
2029 /* Normal numbers */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002030 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002031 isHex = (base == BASE_HEX);
2032 dblBase = (double)base;
2033
2034 if (precision == NO_PRECISION)
2035 precision = FLT_DIG;
2036 precisionPower = pow(10.0, (double)precision);
2037
2038 isNegative = (number < 0.0);
2039 if (isNegative)
2040 number = -number;
2041
2042 if ((flags & FLAGS_FLOAT_G) || isHex)
2043 {
2044 if ((number < 1.0e-4) || (number > precisionPower))
2045 flags |= FLAGS_FLOAT_E;
2046#if defined(TRIO_UNIX98)
2047 if (precision == 0)
2048 precision = 1;
2049#endif
2050 }
2051
2052 if (flags & FLAGS_FLOAT_E)
2053 {
2054 /* Scale the number */
2055 workNumber = log10(number);
2056 if (workNumber == -HUGE_VAL)
2057 {
2058 exponent = 0;
2059 /* Undo setting */
2060 if (flags & FLAGS_FLOAT_G)
2061 flags &= ~FLAGS_FLOAT_E;
2062 }
2063 else
2064 {
2065 exponent = (int)floor(workNumber);
2066 number /= pow(10.0, (double)exponent);
2067 isExponentNegative = (exponent < 0);
2068 uExponent = (isExponentNegative) ? -exponent : exponent;
2069 /* No thousand separators */
2070 flags &= ~FLAGS_QUOTE;
2071 }
2072 }
2073
2074 /*
2075 * Truncated number.
2076 *
2077 * precision is number of significant digits for FLOAT_G
2078 * and number of fractional digits for others
2079 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002080 integerDigits = (floor(number) > DBL_EPSILON)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002081 ? 1 + (int)log10(floor(number))
2082 : 1;
2083 fractionDigits = (flags & FLAGS_FLOAT_G)
2084 ? precision - integerDigits
2085 : precision;
2086 number = floor(0.5 + number * pow(10.0, (double)fractionDigits));
2087 if ((int)log10(number) + 1 > integerDigits + fractionDigits)
2088 {
2089 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2090 integerDigits++;
2091 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002092
2093 /* Build the fraction part */
2094 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
2095 *numberPointer = NIL;
2096 onlyzero = TRUE;
2097 for (i = 0; i < fractionDigits; i++)
2098 {
2099 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2100 number = floor(number / dblBase);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002101
2102 if((set_precision == NO_PRECISION) || (flags & FLAGS_ALTERNATIVE)) {
2103 /* Prune trailing zeroes */
2104 if (numberPointer[0] != digits[0])
2105 onlyzero = FALSE;
2106 else if (onlyzero && (numberPointer[0] == digits[0]))
2107 numberPointer++;
2108 }
2109 else
2110 onlyzero = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002111 }
2112
2113 /* Insert decimal point */
2114 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
2115 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002116 i = StrLength(internalDecimalPoint);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002117 while (i> 0)
2118 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002119 *(--numberPointer) = internalDecimalPoint[--i];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002120 }
2121 }
2122 /* Insert the integer part and thousand separators */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002123 charsPerThousand = (int)internalGrouping[0];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002124 groupingIndex = 1;
2125 for (i = 1; i < integerDigits + 1; i++)
2126 {
2127 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2128 number = floor(number / dblBase);
2129 if (number < DBL_EPSILON)
2130 break;
2131
2132 if ((i > 0)
2133 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2134 && (charsPerThousand != NO_GROUPING)
2135 && (i % charsPerThousand == 0))
2136 {
2137 /*
2138 * We are building the number from the least significant
2139 * to the most significant digit, so we have to copy the
2140 * thousand separator backwards
2141 */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002142 length = StrLength(internalThousandSeparator);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002143 integerDigits += length;
2144 if (((int)(numberPointer - numberBuffer) - length) > 0)
2145 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002146 work = &internalThousandSeparator[length - 1];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002147 while (length-- > 0)
2148 *(--numberPointer) = *work--;
2149 }
2150
2151 /* Advance to next grouping number */
2152 if (charsPerThousand != NO_GROUPING)
2153 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002154 switch (internalGrouping[groupingIndex])
Daniel Veillard92ad2102001-03-27 12:47:33 +00002155 {
2156 case CHAR_MAX: /* Disable grouping */
2157 charsPerThousand = NO_GROUPING;
2158 break;
2159 case 0: /* Repeat last group */
2160 break;
2161 default:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002162 charsPerThousand = (int)internalGrouping[groupingIndex++];
Daniel Veillard92ad2102001-03-27 12:47:33 +00002163 break;
2164 }
2165 }
2166 }
2167 }
2168
2169 /* Build the exponent */
2170 exponentDigits = 0;
2171 if (flags & FLAGS_FLOAT_E)
2172 {
2173 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2174 *exponentPointer-- = NIL;
2175 do {
2176 *exponentPointer-- = digits[uExponent % base];
2177 uExponent /= base;
2178 exponentDigits++;
2179 } while (uExponent);
2180 }
2181
Bjorn Reese70a9da52001-04-21 16:57:29 +00002182 /*
2183 * Calculate expected width.
Daniel Veillard92ad2102001-03-27 12:47:33 +00002184 * sign + integer part + thousands separators + decimal point
2185 * + fraction + exponent
2186 */
2187 expectedWidth = StrLength(numberPointer);
2188 if (isNegative || (flags & FLAGS_SHOWSIGN))
2189 expectedWidth += sizeof("-") - 1;
2190 if (exponentDigits > 0)
2191 expectedWidth += exponentDigits + sizeof("E+") - 1;
2192 if (isExponentNegative)
2193 expectedWidth += sizeof('-') - 1;
2194 if (isHex)
2195 expectedWidth += sizeof("0X") - 1;
2196
2197 /* Output prefixing */
2198 if (flags & FLAGS_NILPADDING)
2199 {
2200 /* Leading zeros must be after sign */
2201 if (isNegative)
2202 self->OutStream(self, '-');
2203 else if (flags & FLAGS_SHOWSIGN)
2204 self->OutStream(self, '+');
2205 if (isHex)
2206 {
2207 self->OutStream(self, '0');
2208 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2209 }
2210 if (!(flags & FLAGS_LEFTADJUST))
2211 {
2212 for (i = expectedWidth; i < width; i++)
2213 {
2214 self->OutStream(self, '0');
2215 }
2216 }
2217 }
2218 else
2219 {
2220 /* Leading spaces must be before sign */
2221 if (!(flags & FLAGS_LEFTADJUST))
2222 {
2223 for (i = expectedWidth; i < width; i++)
2224 {
2225 self->OutStream(self, CHAR_ADJUST);
2226 }
2227 }
2228 if (isNegative)
2229 self->OutStream(self, '-');
2230 else if (flags & FLAGS_SHOWSIGN)
2231 self->OutStream(self, '+');
2232 if (isHex)
2233 {
2234 self->OutStream(self, '0');
2235 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2236 }
2237 }
2238 /* Output number */
2239 for (i = 0; numberPointer[i]; i++)
2240 {
2241 self->OutStream(self, numberPointer[i]);
2242 }
2243 /* Output exponent */
2244 if (exponentDigits > 0)
2245 {
2246 self->OutStream(self,
2247 isHex
2248 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2249 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2250 self->OutStream(self, (isExponentNegative) ? '-' : '+');
2251 for (i = 0; i < exponentDigits; i++)
2252 {
2253 self->OutStream(self, exponentPointer[i + 1]);
2254 }
2255 }
2256 /* Output trailing spaces */
2257 if (flags & FLAGS_LEFTADJUST)
2258 {
2259 for (i = expectedWidth; i < width; i++)
2260 {
2261 self->OutStream(self, CHAR_ADJUST);
2262 }
2263 }
2264}
2265
2266/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002267 * TrioFormatProcess [private]
Daniel Veillard92ad2102001-03-27 12:47:33 +00002268 */
2269static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002270TrioFormatProcess(trio_T *data,
2271 const char *format,
2272 parameter_T *parameters)
2273
Daniel Veillard92ad2102001-03-27 12:47:33 +00002274{
2275#if defined(USE_MULTIBYTE)
2276 int charlen;
2277#endif
Daniel Veillard92ad2102001-03-27 12:47:33 +00002278 int i;
2279 const char *string;
2280 void *pointer;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002281 unsigned long flags;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002282 int width;
2283 int precision;
2284 int base;
2285 int index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002286
Daniel Veillard92ad2102001-03-27 12:47:33 +00002287 index = 0;
2288 i = 0;
2289#if defined(USE_MULTIBYTE)
2290 mblen(NULL, 0);
2291#endif
2292
2293 while (format[index])
2294 {
2295#if defined(USE_MULTIBYTE)
2296 if (! isascii(format[index]))
2297 {
2298 charlen = mblen(&format[index], MB_LEN_MAX);
2299 while (charlen-- > 0)
2300 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002301 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002302 }
2303 continue; /* while */
2304 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002305#endif /* defined(USE_MULTIBYTE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002306 if (CHAR_IDENTIFIER == format[index])
2307 {
2308 if (CHAR_IDENTIFIER == format[index + 1])
2309 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002310 data->OutStream(data, CHAR_IDENTIFIER);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002311 index += 2;
2312 }
2313 else
2314 {
2315 /* Skip the parameter entries */
2316 while (parameters[i].type == FORMAT_PARAMETER)
2317 i++;
2318
2319 flags = parameters[i].flags;
2320
2321 /* Find width */
2322 width = parameters[i].width;
2323 if (flags & FLAGS_WIDTH_PARAMETER)
2324 {
2325 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002326 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002327 }
2328
2329 /* Find precision */
2330 if (flags & FLAGS_PRECISION)
2331 {
2332 precision = parameters[i].precision;
2333 if (flags & FLAGS_PRECISION_PARAMETER)
2334 {
2335 /* Get precision from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002336 precision = (int)parameters[precision].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002337 }
2338 }
2339 else
2340 {
2341 precision = NO_PRECISION;
2342 }
2343
2344 /* Find base */
2345 base = parameters[i].base;
2346 if (flags & FLAGS_BASE_PARAMETER)
2347 {
2348 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002349 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00002350 }
2351
2352 switch (parameters[i].type)
2353 {
2354 case FORMAT_CHAR:
2355 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002356 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002357 if (! (flags & FLAGS_LEFTADJUST))
2358 {
2359 while (--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002360 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002361 }
2362
Bjorn Reese70a9da52001-04-21 16:57:29 +00002363 data->OutStream(data,
2364 (char)parameters[i].data.number.as_signed);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002365
2366 if (flags & FLAGS_LEFTADJUST)
2367 {
2368 while(--width > 0)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002369 data->OutStream(data, CHAR_ADJUST);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002370 }
2371 if (flags & FLAGS_QUOTE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00002372 data->OutStream(data, CHAR_QUOTE);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002373
2374 break; /* FORMAT_CHAR */
2375
2376 case FORMAT_INT:
2377 if (base == NO_BASE)
2378 base = BASE_DECIMAL;
2379
2380 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002381 parameters[i].data.number.as_signed,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002382 flags,
2383 width,
2384 precision,
2385 base);
2386
2387 break; /* FORMAT_INT */
2388
2389 case FORMAT_DOUBLE:
2390 TrioWriteDouble(data,
2391 parameters[i].data.longdoubleNumber,
2392 flags,
2393 width,
2394 precision,
2395 base);
2396 break; /* FORMAT_DOUBLE */
2397
2398 case FORMAT_STRING:
2399 TrioWriteString(data,
2400 parameters[i].data.string,
2401 flags,
2402 width,
2403 precision);
2404 break; /* FORMAT_STRING */
2405
2406 case FORMAT_POINTER:
Bjorn Reese70a9da52001-04-21 16:57:29 +00002407 {
2408 reference_T reference;
2409
2410 reference.data = data;
2411 reference.parameter = &parameters[i];
2412 trio_print_pointer(&reference, parameters[i].data.pointer);
2413 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002414 break; /* FORMAT_POINTER */
2415
2416 case FORMAT_COUNT:
2417 pointer = parameters[i].data.pointer;
2418 if (NULL != pointer)
2419 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002420 /*
2421 * C99 paragraph 7.19.6.1.8 says "the number of
Daniel Veillard92ad2102001-03-27 12:47:33 +00002422 * characters written to the output stream so far by
2423 * this call", which is data->committed
2424 */
2425#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2426 if (flags & FLAGS_SIZE_T)
2427 *(size_t *)pointer = (size_t)data->committed;
2428 else
2429#endif
2430#if defined(QUALIFIER_PTRDIFF_T)
2431 if (flags & FLAGS_PTRDIFF_T)
2432 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2433 else
2434#endif
2435#if defined(QUALIFIER_INTMAX_T)
2436 if (flags & FLAGS_INTMAX_T)
2437 *(intmax_t *)pointer = (intmax_t)data->committed;
2438 else
2439#endif
2440 if (flags & FLAGS_QUAD)
2441 {
2442 *(ULONGLONG int *)pointer = (ULONGLONG)data->committed;
2443 }
2444 else if (flags & FLAGS_LONG)
2445 {
2446 *(long int *)pointer = (long int)data->committed;
2447 }
2448 else if (flags & FLAGS_SHORT)
2449 {
2450 *(short int *)pointer = (short int)data->committed;
2451 }
2452 else
2453 {
2454 *(int *)pointer = (int)data->committed;
2455 }
2456 }
2457 break; /* FORMAT_COUNT */
2458
2459 case FORMAT_PARAMETER:
2460 break; /* FORMAT_PARAMETER */
2461
2462#if defined(FORMAT_ERRNO)
2463 case FORMAT_ERRNO:
2464 string = StrError(parameters[i].data.errorNumber);
2465 if (string)
2466 {
2467 TrioWriteString(data,
2468 string,
2469 flags,
2470 width,
2471 precision);
2472 }
2473 else
2474 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002475 data->OutStream(data, '#');
Daniel Veillard92ad2102001-03-27 12:47:33 +00002476 TrioWriteNumber(data,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002477 (SLONGEST)parameters[i].data.errorNumber,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002478 flags,
2479 width,
2480 precision,
2481 BASE_DECIMAL);
2482 }
2483 break; /* FORMAT_ERRNO */
Bjorn Reese70a9da52001-04-21 16:57:29 +00002484#endif /* defined(FORMAT_ERRNO) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00002485
Bjorn Reese70a9da52001-04-21 16:57:29 +00002486#if defined(FORMAT_USER_DEFINED)
2487 case FORMAT_USER_DEFINED:
2488 {
2489 reference_T reference;
2490 userdef_T *def = NULL;
2491
2492 if (parameters[i].user_name[0] == NIL)
2493 {
2494 /* Use handle */
2495 if ((i > 0) ||
2496 (parameters[i - 1].type == FORMAT_PARAMETER))
2497 def = (userdef_T *)parameters[i - 1].data.pointer;
2498 }
2499 else
2500 {
2501 /* Look up namespace */
2502 def = TrioFindNamespace(parameters[i].user_name, NULL);
2503 }
2504 if (def) {
2505 reference.data = data;
2506 reference.parameter = &parameters[i];
2507 def->callback(&reference);
2508 }
2509 }
2510 break;
2511#endif /* defined(FORMAT_USER_DEFINED) */
2512
Daniel Veillard92ad2102001-03-27 12:47:33 +00002513 default:
2514 break;
2515 } /* switch parameter type */
2516
2517 /* Prepare for next */
2518 index = parameters[i].indexAfterSpecifier;
2519 i++;
2520 }
2521 }
2522 else /* not identifier */
2523 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002524 data->OutStream(data, format[index++]);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002525 }
2526 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00002527 return data->processed;
2528}
2529
2530/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002531 * TrioFormatRef [private]
2532 */
2533static int
2534TrioFormatRef(reference_T *reference,
2535 const char *format,
2536 va_list arglist,
2537 void **argarray)
2538{
2539 int status;
2540 parameter_T parameters[MAX_PARAMETERS];
2541
2542 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2543 if (status < 0)
2544 return status;
2545
2546 return TrioFormatProcess(reference->data, format, parameters);
2547}
2548
2549/*************************************************************************
2550 * TrioFormat [private]
2551 *
2552 * Description:
2553 * This is the main engine for formatting output
2554 */
2555static int
2556TrioFormat(void *destination,
2557 size_t destinationSize,
2558 void (*OutStream)(trio_T *, int),
2559 const char *format,
2560 va_list arglist,
2561 void **argarray)
2562{
2563 int status;
2564 trio_T data;
2565 parameter_T parameters[MAX_PARAMETERS];
2566
2567 assert(VALID(OutStream));
2568 assert(VALID(format));
2569 assert(VALID(arglist) || VALID(argarray));
2570
2571 memset(&data, 0, sizeof(data));
2572 data.OutStream = OutStream;
2573 data.location = destination;
2574 data.max = destinationSize;
2575
2576#if defined(USE_LOCALE)
2577 if (NULL == internalLocaleValues)
2578 {
2579 TrioSetLocale();
2580 }
2581#endif
2582
2583 status = TrioPreprocess(TYPE_PRINT, format, parameters, arglist, argarray);
2584 if (status < 0)
2585 return status;
2586
2587 return TrioFormatProcess(&data, format, parameters);
2588}
2589
2590/*************************************************************************
Daniel Veillard92ad2102001-03-27 12:47:33 +00002591 * TrioOutStreamFile [private]
2592 */
2593static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002594TrioOutStreamFile(trio_T *self,
2595 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002596{
2597 FILE *file = (FILE *)self->location;
2598
2599 assert(VALID(self));
2600 assert(VALID(file));
2601
2602 self->processed++;
2603 self->committed++;
2604 (void)fputc(output, file);
2605}
2606
2607/*************************************************************************
2608 * TrioOutStreamFileDescriptor [private]
2609 */
2610static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002611TrioOutStreamFileDescriptor(trio_T *self,
2612 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002613{
2614 int fd = *((int *)self->location);
2615 char ch;
2616
2617 assert(VALID(self));
2618
2619 ch = (char)output;
2620 (void)write(fd, &ch, sizeof(char));
2621 self->processed++;
2622 self->committed++;
2623}
2624
2625/*************************************************************************
2626 * TrioOutStreamString [private]
2627 */
2628static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002629TrioOutStreamString(trio_T *self,
2630 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002631{
2632 char **buffer = (char **)self->location;
2633
2634 assert(VALID(self));
2635 assert(VALID(buffer));
2636
2637 **buffer = (char)output;
2638 (*buffer)++;
2639 self->processed++;
2640 self->committed++;
2641}
2642
2643/*************************************************************************
2644 * TrioOutStreamStringMax [private]
2645 */
2646static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002647TrioOutStreamStringMax(trio_T *self,
2648 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002649{
2650 char **buffer;
2651
2652 assert(VALID(self));
2653 buffer = (char **)self->location;
2654 assert(VALID(buffer));
2655
2656 if (self->processed < self->max)
2657 {
2658 **buffer = (char)output;
2659 (*buffer)++;
2660 self->committed++;
2661 }
2662 self->processed++;
2663}
2664
2665/*************************************************************************
2666 * TrioOutStreamStringDynamic [private]
2667 */
2668#define DYNAMIC_START_SIZE 32
2669struct dynamicBuffer {
2670 char *buffer;
2671 size_t length;
2672 size_t allocated;
2673};
2674
2675static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00002676TrioOutStreamStringDynamic(trio_T *self,
2677 int output)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002678{
2679 struct dynamicBuffer *infop;
2680
2681 assert(VALID(self));
2682 assert(VALID(self->location));
2683
2684 infop = (struct dynamicBuffer *)self->location;
2685
2686 if (infop->buffer == NULL)
2687 {
2688 /* Start with a reasonable size */
2689 infop->buffer = (char *)malloc(DYNAMIC_START_SIZE);
2690 if (infop->buffer == NULL)
2691 return; /* fail */
2692
2693 infop->allocated = DYNAMIC_START_SIZE;
2694 self->processed = 0;
2695 self->committed = 0;
2696 }
2697 else if (self->committed + sizeof(NIL) >= infop->allocated)
2698 {
2699 char *newptr;
2700
2701 /* Allocate increasing chunks */
2702 newptr = (char *)realloc(infop->buffer, infop->allocated * 2);
2703
2704 if (newptr == NULL)
2705 return;
2706
2707 infop->buffer = newptr;
2708 infop->allocated *= 2;
2709 }
2710
2711 infop->buffer[self->committed] = output;
2712 self->committed++;
2713 self->processed++;
2714
2715 infop->length = self->committed;
2716}
2717
Daniel Veillard92ad2102001-03-27 12:47:33 +00002718/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002719 * printf
Daniel Veillard92ad2102001-03-27 12:47:33 +00002720 */
2721int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002722trio_printf(const char *format,
2723 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002724{
2725 int status;
2726 va_list args;
2727
2728 assert(VALID(format));
2729
2730 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002731 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002732 va_end(args);
2733 return status;
2734}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002735
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736int
2737trio_vprintf(const char *format,
2738 va_list args)
2739{
2740 assert(VALID(format));
2741 assert(VALID(args));
2742
2743 return TrioFormat(stdout, 0, TrioOutStreamFile, format, args, NULL);
2744}
2745
2746int
2747trio_printfv(const char *format,
2748 void ** args)
2749{
2750 assert(VALID(format));
2751 assert(VALID(args));
2752
2753 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
2754}
2755
Daniel Veillard92ad2102001-03-27 12:47:33 +00002756/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002757 * fprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00002758 */
2759int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002760trio_fprintf(FILE *file,
2761 const char *format,
2762 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002763{
2764 int status;
2765 va_list args;
2766
2767 assert(VALID(file));
2768 assert(VALID(format));
2769
2770 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002771 status = TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002772 va_end(args);
2773 return status;
2774}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002775
Daniel Veillard92ad2102001-03-27 12:47:33 +00002776int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002777trio_vfprintf(FILE *file,
2778 const char *format,
2779 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002780{
2781 assert(VALID(file));
2782 assert(VALID(format));
2783 assert(VALID(args));
2784
Bjorn Reese70a9da52001-04-21 16:57:29 +00002785 return TrioFormat(file, 0, TrioOutStreamFile, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002786}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002787
Bjorn Reese70a9da52001-04-21 16:57:29 +00002788int
2789trio_fprintfv(FILE *file,
2790 const char *format,
2791 void ** args)
2792{
2793 assert(VALID(file));
2794 assert(VALID(format));
2795 assert(VALID(args));
2796
2797 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
2798}
2799
Daniel Veillard92ad2102001-03-27 12:47:33 +00002800/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002801 * dprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00002802 */
2803int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002804trio_dprintf(int fd,
2805 const char *format,
2806 ...)
2807{
2808 int status;
2809 va_list args;
2810
2811 assert(VALID(format));
2812
2813 va_start(args, format);
2814 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
2815 va_end(args);
2816 return status;
2817}
2818
2819int
2820trio_vdprintf(int fd,
2821 const char *format,
2822 va_list args)
2823{
2824 assert(VALID(format));
2825 assert(VALID(args));
2826
2827 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, args, NULL);
2828}
2829
2830int
2831trio_dprintfv(int fd,
2832 const char *format,
2833 void **args)
2834{
2835 assert(VALID(format));
2836 assert(VALID(args));
2837
2838 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
2839}
2840
2841/*************************************************************************
2842 * sprintf
2843 */
2844int
2845trio_sprintf(char *buffer,
2846 const char *format,
2847 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002848{
2849 int status;
2850 va_list args;
2851
2852 assert(VALID(buffer));
2853 assert(VALID(format));
2854
2855 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002856 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002857 *buffer = NIL; /* Terminate with NIL character */
2858 va_end(args);
2859 return status;
2860}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002861
Daniel Veillard92ad2102001-03-27 12:47:33 +00002862int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002863trio_vsprintf(char *buffer,
2864 const char *format,
2865 va_list args)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002866{
2867 int status;
2868
2869 assert(VALID(buffer));
2870 assert(VALID(format));
2871 assert(VALID(args));
2872
Bjorn Reese70a9da52001-04-21 16:57:29 +00002873 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002874 *buffer = NIL;
2875 return status;
2876}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002877
Bjorn Reese70a9da52001-04-21 16:57:29 +00002878int
2879trio_sprintfv(char *buffer,
2880 const char *format,
2881 void **args)
2882{
2883 int status;
2884
2885 assert(VALID(buffer));
2886 assert(VALID(format));
2887 assert(VALID(args));
2888
2889 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
2890 *buffer = NIL;
2891 return status;
2892}
2893
Daniel Veillard92ad2102001-03-27 12:47:33 +00002894/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00002895 * snprintf
Daniel Veillard92ad2102001-03-27 12:47:33 +00002896 */
2897int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002898trio_snprintf(char *buffer,
2899 size_t bufferSize,
2900 const char *format,
2901 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00002902{
2903 int status;
2904 va_list args;
2905
2906 assert(VALID(buffer));
2907 assert(VALID(format));
2908
2909 va_start(args, format);
2910 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002911 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002912 if (bufferSize > 0)
2913 *buffer = NIL;
2914 va_end(args);
2915 return status;
2916}
Daniel Veillard92ad2102001-03-27 12:47:33 +00002917
Daniel Veillard92ad2102001-03-27 12:47:33 +00002918int
Bjorn Reese70a9da52001-04-21 16:57:29 +00002919trio_vsnprintf(char *buffer,
2920 size_t bufferSize,
2921 const char *format,
Daniel Veillard92ad2102001-03-27 12:47:33 +00002922 va_list args)
2923{
2924 int status;
2925
2926 assert(VALID(buffer));
2927 assert(VALID(format));
2928 assert(VALID(args));
2929
2930 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
Bjorn Reese70a9da52001-04-21 16:57:29 +00002931 TrioOutStreamStringMax, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00002932 if (bufferSize > 0)
2933 *buffer = NIL;
2934 return status;
2935}
Bjorn Reese70a9da52001-04-21 16:57:29 +00002936
2937int
2938trio_snprintfv(char *buffer,
2939 size_t bufferSize,
2940 const char *format,
2941 void **args)
2942{
2943 int status;
2944
2945 assert(VALID(buffer));
2946 assert(VALID(format));
2947 assert(VALID(args));
2948
2949 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
2950 TrioOutStreamStringMax, format, NULL, args);
2951 if (bufferSize > 0)
2952 *buffer = NIL;
2953 return status;
2954}
2955
2956/*************************************************************************
2957 * snprintfcat
2958 * Appends the new string to the buffer string overwriting the '\0'
2959 * character at the end of buffer.
2960 */
2961int
2962trio_snprintfcat(char *buffer,
2963 size_t bufferSize,
2964 const char *format,
2965 ...)
2966{
2967 int status;
2968 va_list args;
2969 size_t buf_len;
2970
2971 va_start(args, format);
2972
2973 assert(VALID(buffer));
2974 assert(VALID(format));
2975
2976 buf_len = strlen(buffer);
2977 buffer = &buffer[buf_len];
2978
2979 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
2980 TrioOutStreamStringMax, format, args, NULL);
2981 va_end(args);
2982 *buffer = NIL;
2983 return status;
2984}
2985
2986int
2987trio_vsnprintfcat(char *buffer,
2988 size_t bufferSize,
2989 const char *format,
2990 va_list args)
2991{
2992 int status;
2993 size_t buf_len;
2994 assert(VALID(buffer));
2995 assert(VALID(format));
2996 assert(VALID(args));
2997
2998 buf_len = strlen(buffer);
2999 buffer = &buffer[buf_len];
3000 status = TrioFormat(&buffer, bufferSize - 1 - buf_len,
3001 TrioOutStreamStringMax, format, args, NULL);
3002 *buffer = NIL;
3003 return status;
3004}
3005
3006/*************************************************************************
3007 * trio_aprintf
3008 */
3009
3010/* Deprecated */
3011char *
3012trio_aprintf(const char *format,
3013 ...)
3014{
3015 va_list args;
3016 struct dynamicBuffer info;
3017
3018 assert(VALID(format));
3019
3020 info.buffer = NULL;
3021 info.length = 0;
3022 info.allocated = 0;
3023
3024 va_start(args, format);
3025 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3026 va_end(args);
3027 if (info.length) {
3028 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3029 return info.buffer;
3030 }
3031 else
3032 return NULL;
3033}
3034
3035/* Deprecated */
3036char *
3037trio_vaprintf(const char *format,
3038 va_list args)
3039{
3040 struct dynamicBuffer info;
3041
3042 assert(VALID(format));
3043 assert(VALID(args));
3044
3045 info.buffer = NULL;
3046 info.length = 0;
3047 info.allocated = 0;
3048
3049 (void)TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3050 if (info.length) {
3051 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3052 return info.buffer;
3053 }
3054 else
3055 return NULL;
3056}
3057
3058int
3059trio_asprintf(char **result,
3060 const char *format,
3061 ...)
3062{
3063 va_list args;
3064 int status;
3065 struct dynamicBuffer info;
3066
3067 assert(VALID(format));
3068
3069 info.buffer = NULL;
3070 info.length = 0;
3071 info.allocated = 0;
3072
3073 va_start(args, format);
3074 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3075 va_end(args);
3076 if (status < 0) {
3077 *result = NULL;
3078 return status;
3079 }
3080 if (info.length == 0) {
3081 /*
3082 * If the length is zero, no characters have been written and therefore
3083 * no memory has been allocated, but we must to allocate and return an
3084 * empty string.
3085 */
3086 info.buffer = (char *)malloc(sizeof(char));
3087 if (info.buffer == NULL) {
3088 *result = NULL;
3089 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3090 }
3091 }
3092 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3093 *result = info.buffer;
3094
3095 return status;
3096}
3097
3098int
3099trio_vasprintf(char **result,
3100 const char *format,
3101 va_list args)
3102{
3103 int status;
3104 struct dynamicBuffer info;
3105
3106 assert(VALID(format));
3107 assert(VALID(args));
3108
3109 info.buffer = NULL;
3110 info.length = 0;
3111 info.allocated = 0;
3112
3113 status = TrioFormat(&info, 0, TrioOutStreamStringDynamic, format, args, NULL);
3114 if (status < 0) {
3115 *result = NULL;
3116 return status;
3117 }
3118 if (info.length == 0) {
3119 info.buffer = (char *)malloc(sizeof(char));
3120 if (info.buffer == NULL) {
3121 *result = NULL;
3122 return TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3123 }
3124 }
3125 info.buffer[info.length] = NIL; /* we terminate this with a zero byte */
3126 *result = info.buffer;
3127
3128 return status;
3129}
3130
Daniel Veillard92ad2102001-03-27 12:47:33 +00003131
3132/*************************************************************************
3133 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00003134 * @CALLBACK
Daniel Veillard92ad2102001-03-27 12:47:33 +00003135 *
3136 ************************************************************************/
3137
Bjorn Reese70a9da52001-04-21 16:57:29 +00003138
3139/*************************************************************************
3140 * trio_register [public]
3141 */
3142void *
3143trio_register(trio_callback_t callback,
3144 const char *name)
3145{
3146 userdef_T *def;
3147 userdef_T *prev = NULL;
3148
3149 if (callback == NULL)
3150 return NULL;
3151
3152 if (name)
3153 {
3154 /* Bail out if namespace is too long */
3155 if (StrLength(name) >= MAX_USER_NAME)
3156 return NULL;
3157
3158 /* Bail out if namespace already is registered */
3159 def = TrioFindNamespace(name, &prev);
3160 if (def)
3161 return NULL;
3162 }
3163
3164 def = (userdef_T *)malloc(sizeof(userdef_T));
3165 if (def)
3166 {
3167 if (name)
3168 {
3169 /* Link into internal list */
3170 if (prev == NULL)
3171 internalUserDef = def;
3172 else
3173 prev->next = def;
3174 }
3175 /* Initialize */
3176 def->callback = callback;
3177 def->name = (name == NULL)
3178 ? NULL
3179 : StrDuplicate(name);
3180 def->next = NULL;
3181 }
3182 return def;
3183}
3184
3185/*************************************************************************
3186 * trio_unregister [public]
3187 */
3188void
3189trio_unregister(void *handle)
3190{
3191 userdef_T *self = (userdef_T *)handle;
3192 userdef_T *def;
3193 userdef_T *prev = NULL;
3194
3195 assert(VALID(self));
3196
3197 if (self->name)
3198 {
3199 def = TrioFindNamespace(self->name, &prev);
3200 if (def)
3201 {
3202 if (prev == NULL)
3203 internalUserDef = NULL;
3204 else
3205 prev->next = def->next;
3206 }
3207 StrFree(self->name);
3208 }
3209 free(self);
3210}
3211
3212/*************************************************************************
3213 * trio_get_format [public]
3214 */
3215const char *
3216trio_get_format(void *ref)
3217{
3218 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3219
3220 return (((reference_T *)ref)->parameter->user_data);
3221}
3222
3223/*************************************************************************
3224 * trio_get_argument [public]
3225 */
3226void *
3227trio_get_argument(void *ref)
3228{
3229 assert(((reference_T *)ref)->parameter->type == FORMAT_USER_DEFINED);
3230
3231 return ((reference_T *)ref)->parameter->data.pointer;
3232}
3233
3234/*************************************************************************
3235 * trio_get_width / trio_set_width [public]
3236 */
3237int
3238trio_get_width(void *ref)
3239{
3240 return ((reference_T *)ref)->parameter->width;
3241}
3242
3243void
3244trio_set_width(void *ref,
3245 int width)
3246{
3247 ((reference_T *)ref)->parameter->width = width;
3248}
3249
3250/*************************************************************************
3251 * trio_get_precision / trio_set_precision [public]
3252 */
3253int
3254trio_get_precision(void *ref)
3255{
3256 return (((reference_T *)ref)->parameter->precision);
3257}
3258
3259void
3260trio_set_precision(void *ref,
3261 int precision)
3262{
3263 ((reference_T *)ref)->parameter->precision = precision;
3264}
3265
3266/*************************************************************************
3267 * trio_get_base / trio_set_base [public]
3268 */
3269int
3270trio_get_base(void *ref)
3271{
3272 return (((reference_T *)ref)->parameter->base);
3273}
3274
3275void
3276trio_set_base(void *ref,
3277 int base)
3278{
3279 ((reference_T *)ref)->parameter->base = base;
3280}
3281
3282/*************************************************************************
3283 * trio_get_long / trio_set_long [public]
3284 */
3285int
3286trio_get_long(void *ref)
3287{
3288 return (((reference_T *)ref)->parameter->flags & FLAGS_LONG);
3289}
3290
3291void
3292trio_set_long(void *ref,
3293 int is_long)
3294{
3295 if (is_long)
3296 ((reference_T *)ref)->parameter->flags |= FLAGS_LONG;
3297 else
3298 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONG;
3299}
3300
3301/*************************************************************************
3302 * trio_get_longlong / trio_set_longlong [public]
3303 */
3304int
3305trio_get_longlong(void *ref)
3306{
3307 return (((reference_T *)ref)->parameter->flags & FLAGS_QUAD);
3308}
3309
3310void
3311trio_set_longlong(void *ref,
3312 int is_longlong)
3313{
3314 if (is_longlong)
3315 ((reference_T *)ref)->parameter->flags |= FLAGS_QUAD;
3316 else
3317 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUAD;
3318}
3319
3320/*************************************************************************
3321 * trio_get_longdouble / trio_set_longdouble [public]
3322 */
3323int
3324trio_get_longdouble(void *ref)
3325{
3326 return (((reference_T *)ref)->parameter->flags & FLAGS_LONGDOUBLE);
3327}
3328
3329void
3330trio_set_longdouble(void *ref,
3331 int is_longdouble)
3332{
3333 if (is_longdouble)
3334 ((reference_T *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
3335 else
3336 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
3337}
3338
3339/*************************************************************************
3340 * trio_get_short / trio_set_short [public]
3341 */
3342int
3343trio_get_short(void *ref)
3344{
3345 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORT);
3346}
3347
3348void
3349trio_set_short(void *ref,
3350 int is_short)
3351{
3352 if (is_short)
3353 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORT;
3354 else
3355 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORT;
3356}
3357
3358/*************************************************************************
3359 * trio_get_shortshort / trio_set_shortshort [public]
3360 */
3361int
3362trio_get_shortshort(void *ref)
3363{
3364 return (((reference_T *)ref)->parameter->flags & FLAGS_SHORTSHORT);
3365}
3366
3367void
3368trio_set_shortshort(void *ref,
3369 int is_shortshort)
3370{
3371 if (is_shortshort)
3372 ((reference_T *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
3373 else
3374 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
3375}
3376
3377/*************************************************************************
3378 * trio_get_alternative / trio_set_alternative [public]
3379 */
3380int
3381trio_get_alternative(void *ref)
3382{
3383 return (((reference_T *)ref)->parameter->flags & FLAGS_ALTERNATIVE);
3384}
3385
3386void
3387trio_set_alternative(void *ref,
3388 int is_alternative)
3389{
3390 if (is_alternative)
3391 ((reference_T *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
3392 else
3393 ((reference_T *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
3394}
3395
3396/*************************************************************************
3397 * trio_get_alignment / trio_set_alignment [public]
3398 */
3399int
3400trio_get_alignment(void *ref)
3401{
3402 return (((reference_T *)ref)->parameter->flags & FLAGS_LEFTADJUST);
3403}
3404
3405void
3406trio_set_alignment(void *ref,
3407 int is_leftaligned)
3408{
3409 if (is_leftaligned)
3410 ((reference_T *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
3411 else
3412 ((reference_T *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
3413}
3414
3415/*************************************************************************
3416 * trio_get_spacing /trio_set_spacing [public]
3417 */
3418int
3419trio_get_spacing(void *ref)
3420{
3421 return (((reference_T *)ref)->parameter->flags & FLAGS_SPACE);
3422}
3423
3424void
3425trio_set_spacing(void *ref,
3426 int is_space)
3427{
3428 if (is_space)
3429 ((reference_T *)ref)->parameter->flags |= FLAGS_SPACE;
3430 else
3431 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SPACE;
3432}
3433
3434/*************************************************************************
3435 * trio_get_sign / trio_set_sign [public]
3436 */
3437int
3438trio_get_sign(void *ref)
3439{
3440 return (((reference_T *)ref)->parameter->flags & FLAGS_SHOWSIGN);
3441}
3442
3443void
3444trio_set_sign(void *ref,
3445 int is_sign)
3446{
3447 if (is_sign)
3448 ((reference_T *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
3449 else
3450 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
3451}
3452
3453/*************************************************************************
3454 * trio_get_padding / trio_set_padding [public]
3455 */
3456int
3457trio_get_padding(void *ref)
3458{
3459 return (((reference_T *)ref)->parameter->flags & FLAGS_NILPADDING);
3460}
3461
3462void
3463trio_set_padding(void *ref,
3464 int is_padding)
3465{
3466 if (is_padding)
3467 ((reference_T *)ref)->parameter->flags |= FLAGS_NILPADDING;
3468 else
3469 ((reference_T *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
3470}
3471
3472/*************************************************************************
3473 * trio_get_quote / trio_set_quote [public]
3474 */
3475int
3476trio_get_quote(void *ref)
3477{
3478 return (((reference_T *)ref)->parameter->flags & FLAGS_QUOTE);
3479}
3480
3481void
3482trio_set_quote(void *ref,
3483 int is_quote)
3484{
3485 if (is_quote)
3486 ((reference_T *)ref)->parameter->flags |= FLAGS_QUOTE;
3487 else
3488 ((reference_T *)ref)->parameter->flags &= ~FLAGS_QUOTE;
3489}
3490
3491/*************************************************************************
3492 * trio_get_upper / trio_set_upper [public]
3493 */
3494int
3495trio_get_upper(void *ref)
3496{
3497 return (((reference_T *)ref)->parameter->flags & FLAGS_UPPER);
3498}
3499
3500void
3501trio_set_upper(void *ref,
3502 int is_upper)
3503{
3504 if (is_upper)
3505 ((reference_T *)ref)->parameter->flags |= FLAGS_UPPER;
3506 else
3507 ((reference_T *)ref)->parameter->flags &= ~FLAGS_UPPER;
3508}
3509
3510/*************************************************************************
3511 * trio_get_largest / trio_set_largest [public]
3512 */
3513#if defined(TRIO_C99)
3514int
3515trio_get_largest(void *ref)
3516{
3517 return (((reference_T *)ref)->parameter->flags & FLAGS_INTMAX_T);
3518}
3519
3520void
3521trio_set_largest(void *ref,
3522 int is_largest)
3523{
3524 if (is_largest)
3525 ((reference_T *)ref)->parameter->flags |= FLAGS_INTMAX_T;
3526 else
3527 ((reference_T *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
3528}
3529#endif
3530
3531/*************************************************************************
3532 * trio_get_ptrdiff / trio_set_ptrdiff [public]
3533 */
3534#if defined(TRIO_C99)
3535int
3536trio_get_ptrdiff(void *ref)
3537{
3538 return (((reference_T *)ref)->parameter->flags & FLAGS_PTRDIFF_T);
3539}
3540
3541void
3542trio_set_ptrdiff(void *ref,
3543 int is_ptrdiff)
3544{
3545 if (is_ptrdiff)
3546 ((reference_T *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
3547 else
3548 ((reference_T *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
3549}
3550#endif
3551
3552/*************************************************************************
3553 * trio_get_size / trio_set_size [public]
3554 */
3555#if defined(TRIO_C99)
3556int
3557trio_get_size(void *ref)
3558{
3559 return (((reference_T *)ref)->parameter->flags & FLAGS_SIZE_T);
3560}
3561
3562void
3563trio_set_size(void *ref,
3564 int is_size)
3565{
3566 if (is_size)
3567 ((reference_T *)ref)->parameter->flags |= FLAGS_SIZE_T;
3568 else
3569 ((reference_T *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
3570}
3571#endif
3572
3573/*************************************************************************
3574 * trio_print_int [public]
3575 */
3576void
3577trio_print_int(void *ref,
3578 int number)
3579{
3580 reference_T *self = (reference_T *)ref;
3581
3582 TrioWriteNumber(self->data,
3583 (SLONGEST)number,
3584 self->parameter->flags,
3585 self->parameter->width,
3586 self->parameter->precision,
3587 self->parameter->base);
3588}
3589
3590/*************************************************************************
3591 * trio_print_uint [public]
3592 */
3593void
3594trio_print_uint(void *ref,
3595 unsigned int number)
3596{
3597 reference_T *self = (reference_T *)ref;
3598
3599 TrioWriteNumber(self->data,
3600 (SLONGEST)number,
3601 self->parameter->flags | FLAGS_UNSIGNED,
3602 self->parameter->width,
3603 self->parameter->precision,
3604 self->parameter->base);
3605}
3606
3607/*************************************************************************
3608 * trio_print_double [public]
3609 */
3610void
3611trio_print_double(void *ref,
3612 double number)
3613{
3614 reference_T *self = (reference_T *)ref;
3615
3616 TrioWriteDouble(self->data,
3617 number,
3618 self->parameter->flags,
3619 self->parameter->width,
3620 self->parameter->precision,
3621 self->parameter->base);
3622}
3623
3624/*************************************************************************
3625 * trio_print_string [public]
3626 */
3627void
3628trio_print_string(void *ref,
3629 char *string)
3630{
3631 reference_T *self = (reference_T *)ref;
3632
3633 TrioWriteString(self->data,
3634 string,
3635 self->parameter->flags,
3636 self->parameter->width,
3637 self->parameter->precision);
3638}
3639
3640/*************************************************************************
3641 * trio_print_pointer [public]
3642 */
3643void
3644trio_print_pointer(void *ref,
3645 void *pointer)
3646{
3647 reference_T *self = (reference_T *)ref;
3648 unsigned long flags;
3649 LONGLONG number;
3650
3651 if (NULL == pointer)
3652 {
3653 const char *string = null;
3654 while (*string)
3655 self->data->OutStream(self->data, *string++);
3656 }
3657 else
3658 {
3659 /*
3660 * The subtraction of the null pointer is a workaround
3661 * to avoid a compiler warning. The performance overhead
3662 * is negligible (and likely to be removed by an
3663 * optimising compiler). The (char *) casting is done
3664 * to please ANSI C++.
3665 */
3666 number = (ULONGLONG)((char *)pointer - (char *)0);
3667 /* Shrink to size of pointer */
3668 number &= (ULONGLONG)-1;
3669 flags = self->parameter->flags;
3670 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
3671 FLAGS_NILPADDING);
3672 TrioWriteNumber(self->data,
3673 number,
3674 flags,
3675 POINTER_WIDTH,
3676 NO_PRECISION,
3677 BASE_HEX);
3678 }
3679}
3680
3681/*************************************************************************
3682 * trio_print_ref [public]
3683 */
3684int
3685trio_print_ref(void *ref,
3686 const char *format,
3687 ...)
3688{
3689 int status;
3690 va_list arglist;
3691
3692 assert(VALID(format));
3693
3694 va_start(arglist, format);
3695 status = TrioFormatRef((reference_T *)ref, format, arglist, NULL);
3696 va_end(arglist);
3697 return status;
3698}
3699
3700/*************************************************************************
3701 * trio_vprint_ref [public]
3702 */
3703int
3704trio_vprint_ref(void *ref,
3705 const char *format,
3706 va_list arglist)
3707{
3708 assert(VALID(format));
3709
3710 return TrioFormatRef((reference_T *)ref, format, arglist, NULL);
3711}
3712
3713/*************************************************************************
3714 * trio_printv_ref [public]
3715 */
3716int
3717trio_printv_ref(void *ref,
3718 const char *format,
3719 void **argarray)
3720{
3721 assert(VALID(format));
3722
3723 return TrioFormatRef((reference_T *)ref, format, NULL, argarray);
3724}
3725
3726
3727/*************************************************************************
3728 *
3729 * @SCANNING
3730 *
3731 ************************************************************************/
3732
Daniel Veillard92ad2102001-03-27 12:47:33 +00003733
3734/*************************************************************************
3735 * TrioSkipWhitespaces [private]
3736 */
3737static int
3738TrioSkipWhitespaces(trio_T *self)
3739{
3740 int ch;
3741
3742 ch = self->current;
3743 while (isspace(ch))
3744 {
3745 self->InStream(self, &ch);
3746 }
3747 return ch;
3748}
3749
3750/*************************************************************************
3751 * TrioGetCharacterClass [private]
3752 *
3753 * FIXME:
3754 * multibyte
3755 */
3756static int
3757TrioGetCharacterClass(const char *format,
3758 int *indexPointer,
3759 int *flagsPointer,
3760 int *characterclass)
3761{
3762 int index = *indexPointer;
3763 int i;
3764 char ch;
3765 char range_begin;
3766 char range_end;
3767
3768 *flagsPointer &= ~FLAGS_EXCLUDE;
3769
3770 if (format[index] == QUALIFIER_CIRCUMFLEX)
3771 {
3772 *flagsPointer |= FLAGS_EXCLUDE;
3773 index++;
3774 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003775 /*
3776 * If the ungroup character is at the beginning of the scanlist,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003777 * it will be part of the class, and a second ungroup character
3778 * must follow to end the group.
3779 */
3780 if (format[index] == SPECIFIER_UNGROUP)
3781 {
3782 characterclass[(int)SPECIFIER_UNGROUP]++;
3783 index++;
3784 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00003785 /*
3786 * Minus is used to specify ranges. To include minus in the class,
Daniel Veillard92ad2102001-03-27 12:47:33 +00003787 * it must be at the beginning of the list
3788 */
3789 if (format[index] == QUALIFIER_MINUS)
3790 {
3791 characterclass[(int)QUALIFIER_MINUS]++;
3792 index++;
3793 }
3794 /* Collect characters */
3795 for (ch = format[index];
3796 ch != SPECIFIER_UNGROUP && ch != NIL;
3797 ch = format[++index])
3798 {
3799 switch (ch)
3800 {
3801 case QUALIFIER_MINUS: /* Scanlist ranges */
3802
Bjorn Reese70a9da52001-04-21 16:57:29 +00003803 /*
3804 * Both C99 and UNIX98 describes ranges as implementation-
Daniel Veillard92ad2102001-03-27 12:47:33 +00003805 * defined.
3806 *
3807 * We support the following behaviour (although this may
3808 * change as we become wiser)
3809 * - only increasing ranges, ie. [a-b] but not [b-a]
3810 * - transitive ranges, ie. [a-b-c] == [a-c]
3811 * - trailing minus, ie. [a-] is interpreted as an 'a'
3812 * and a '-'
3813 * - duplicates (although we can easily convert these
3814 * into errors)
3815 */
3816 range_begin = format[index - 1];
3817 range_end = format[++index];
3818 if (range_end == SPECIFIER_UNGROUP)
3819 {
3820 /* Trailing minus is included */
3821 characterclass[(int)ch]++;
3822 ch = range_end;
3823 break; /* for */
3824 }
3825 if (range_end == NIL)
3826 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
3827 if (range_begin > range_end)
3828 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
3829
3830 for (i = (int)range_begin; i <= (int)range_end; i++)
3831 characterclass[i]++;
3832
3833 ch = range_end;
3834 break;
3835
3836 case QUALIFIER_COLON: /* Character class expressions */
3837
3838 if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
3839 &format[index]))
3840 {
3841 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3842 if (isalnum(i))
3843 characterclass[i]++;
3844 index += sizeof(CLASS_ALNUM) - 1;
3845 }
3846 else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
3847 &format[index]))
3848 {
3849 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3850 if (isalpha(i))
3851 characterclass[i]++;
3852 index += sizeof(CLASS_ALPHA) - 1;
3853 }
3854 else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
3855 &format[index]))
3856 {
3857 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3858 if (iscntrl(i))
3859 characterclass[i]++;
3860 index += sizeof(CLASS_CNTRL) - 1;
3861 }
3862 else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
3863 &format[index]))
3864 {
3865 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3866 if (isdigit(i))
3867 characterclass[i]++;
3868 index += sizeof(CLASS_DIGIT) - 1;
3869 }
3870 else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
3871 &format[index]))
3872 {
3873 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3874 if (isgraph(i))
3875 characterclass[i]++;
3876 index += sizeof(CLASS_GRAPH) - 1;
3877 }
3878 else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
3879 &format[index]))
3880 {
3881 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3882 if (islower(i))
3883 characterclass[i]++;
3884 index += sizeof(CLASS_LOWER) - 1;
3885 }
3886 else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
3887 &format[index]))
3888 {
3889 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3890 if (isprint(i))
3891 characterclass[i]++;
3892 index += sizeof(CLASS_PRINT) - 1;
3893 }
3894 else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
3895 &format[index]))
3896 {
3897 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3898 if (ispunct(i))
3899 characterclass[i]++;
3900 index += sizeof(CLASS_PUNCT) - 1;
3901 }
3902 else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
3903 &format[index]))
3904 {
3905 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3906 if (isspace(i))
3907 characterclass[i]++;
3908 index += sizeof(CLASS_SPACE) - 1;
3909 }
3910 else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
3911 &format[index]))
3912 {
3913 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3914 if (isupper(i))
3915 characterclass[i]++;
3916 index += sizeof(CLASS_UPPER) - 1;
3917 }
3918 else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
3919 &format[index]))
3920 {
3921 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
3922 if (isxdigit(i))
3923 characterclass[i]++;
3924 index += sizeof(CLASS_XDIGIT) - 1;
3925 }
3926 else
3927 {
3928 characterclass[(int)ch]++;
3929 }
3930 break;
3931
3932 default:
3933 characterclass[(int)ch]++;
3934 break;
3935 }
3936 }
3937 return 0;
3938}
3939
3940/*************************************************************************
3941 * TrioReadNumber [private]
3942 *
3943 * We implement our own number conversion in preference of strtol and
3944 * strtoul, because we must handle 'long long' and thousand separators.
3945 */
3946static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00003947TrioReadNumber(trio_T *self,
3948 LONGEST *target,
3949 int flags,
3950 int width,
3951 int base)
Daniel Veillard92ad2102001-03-27 12:47:33 +00003952{
3953 LONGEST number = 0;
3954 int digit;
3955 int count;
3956 BOOLEAN_T isNegative = FALSE;
3957 int j;
3958
3959 assert(VALID(self));
3960 assert(VALID(self->InStream));
3961 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
3962
3963 TrioSkipWhitespaces(self);
3964
3965 if (!(flags & FLAGS_UNSIGNED))
3966 {
3967 /* Leading sign */
3968 if (self->current == '+')
3969 {
3970 self->InStream(self, NULL);
3971 }
3972 else if (self->current == '-')
3973 {
3974 self->InStream(self, NULL);
3975 isNegative = TRUE;
3976 }
3977 }
3978
3979 count = self->processed;
3980
3981 if (flags & FLAGS_ALTERNATIVE)
3982 {
3983 switch (base)
3984 {
3985 case NO_BASE:
3986 case BASE_OCTAL:
3987 case BASE_HEX:
3988 case BASE_BINARY:
3989 if (self->current == '0')
3990 {
3991 self->InStream(self, NULL);
3992 if (self->current)
3993 {
3994 if ((base == BASE_HEX) &&
3995 (toupper(self->current) == 'X'))
3996 {
3997 self->InStream(self, NULL);
3998 }
3999 else if ((base == BASE_BINARY) &&
4000 (toupper(self->current) == 'B'))
4001 {
4002 self->InStream(self, NULL);
4003 }
4004 }
4005 }
4006 else
4007 return FALSE;
4008 break;
4009 default:
4010 break;
4011 }
4012 }
4013
4014 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
4015 (! ((self->current == EOF) || isspace(self->current))))
4016 {
4017 if (isascii(self->current))
4018 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004019 digit = internalDigitArray[self->current];
Daniel Veillard92ad2102001-03-27 12:47:33 +00004020 /* Abort if digit is not allowed in the specified base */
4021 if ((digit == -1) || (digit >= base))
4022 break;
4023 }
4024 else if (flags & FLAGS_QUOTE)
4025 {
4026 /* Compare with thousands separator */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004027 for (j = 0; internalThousandSeparator[j] && self->current; j++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004028 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004029 if (internalThousandSeparator[j] != self->current)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004030 break;
4031
4032 self->InStream(self, NULL);
4033 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004034 if (internalThousandSeparator[j])
Daniel Veillard92ad2102001-03-27 12:47:33 +00004035 break; /* Mismatch */
4036 else
4037 continue; /* Match */
4038 }
4039 else
4040 break;
4041
4042 number *= base;
4043 number += digit;
4044
4045 self->InStream(self, NULL);
4046 }
4047
4048 /* Was anything read at all? */
4049 if (self->processed == count)
4050 return FALSE;
4051
4052 if (target)
4053 *target = (isNegative) ? -number : number;
4054 return TRUE;
4055}
4056
4057/*************************************************************************
4058 * TrioReadChar [private]
4059 */
4060static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004061TrioReadChar(trio_T *self,
4062 char *target,
4063 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004064{
4065 int i;
4066
4067 assert(VALID(self));
4068 assert(VALID(self->InStream));
4069
4070 for (i = 0;
4071 (self->current != EOF) && (i < width);
4072 i++)
4073 {
4074 if (target)
4075 target[i] = self->current;
4076 self->InStream(self, NULL);
4077 }
4078 return TRUE;
4079}
4080
4081/*************************************************************************
4082 * TrioReadString [private]
4083 */
4084static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004085TrioReadString(trio_T *self,
4086 char *target,
4087 int flags,
4088 int width)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004089{
4090 int i;
4091 char ch;
4092 LONGEST number;
4093
4094 assert(VALID(self));
4095 assert(VALID(self->InStream));
4096
4097 TrioSkipWhitespaces(self);
4098
Bjorn Reese70a9da52001-04-21 16:57:29 +00004099 /*
4100 * Continue until end of string is reached, a whitespace is encountered,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004101 * or width is exceeded
4102 */
4103 for (i = 0;
4104 ((width == NO_WIDTH) || (i < width)) &&
4105 (! ((self->current == EOF) || isspace(self->current)));
4106 i++)
4107 {
4108 ch = self->current;
4109 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
4110 {
4111 self->InStream(self, NULL);
4112 switch (self->current)
4113 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004114 case '\\': ch = '\\'; break;
4115 case 'a': ch = '\a'; break;
4116 case 'b': ch = '\b'; break;
4117 case 'f': ch = '\f'; break;
4118 case 'n': ch = '\n'; break;
4119 case 'r': ch = '\r'; break;
4120 case 't': ch = '\t'; break;
4121 case 'v': ch = '\v'; break;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004122 default:
4123 if (isdigit(self->current))
4124 {
4125 /* Read octal number */
4126 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
4127 return FALSE;
4128 ch = (char)number;
4129 }
4130 else if (toupper(self->current) == 'X')
4131 {
4132 /* Read hexadecimal number */
4133 self->InStream(self, NULL);
4134 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
4135 return FALSE;
4136 ch = (char)number;
4137 }
4138 else
4139 {
4140 ch = self->current;
4141 }
4142 break;
4143 }
4144 }
4145 if (target)
4146 target[i] = ch;
4147 self->InStream(self, NULL);
4148 }
4149 if (target)
4150 target[i] = NIL;
4151 return TRUE;
4152}
4153
4154/*************************************************************************
4155 * TrioReadGroup [private]
4156 *
4157 * FIXME: characterclass does not work with multibyte characters
4158 */
4159static BOOLEAN_T
4160TrioReadGroup(trio_T *self,
4161 char *target,
4162 int *characterclass,
4163 int flags,
4164 int width)
4165{
Bjorn Reese70a9da52001-04-21 16:57:29 +00004166 int ch;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004167 int i;
4168
4169 assert(VALID(self));
4170 assert(VALID(self->InStream));
4171
4172 ch = self->current;
4173 for (i = 0;
4174 ((width == NO_WIDTH) || (i < width)) &&
4175 (! ((ch == EOF) ||
4176 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
4177 i++)
4178 {
4179 if (target)
4180 target[i] = (char)ch;
4181 self->InStream(self, &ch);
4182 }
4183
4184 if (target)
4185 target[i] = NIL;
4186 return TRUE;
4187}
4188
4189/*************************************************************************
4190 * TrioReadDouble [private]
4191 *
4192 * FIXME:
4193 * add hex-float format
4194 * add long double
4195 */
4196static BOOLEAN_T
4197TrioReadDouble(trio_T *self,
4198 double *target,
4199 int flags,
4200 int width)
4201{
4202 int ch;
4203 char doubleString[512] = "";
4204 int index = 0;
4205 int start;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004206 int j;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004207
Bjorn Reese70a9da52001-04-21 16:57:29 +00004208 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004209 width = sizeof(doubleString) - 1;
4210
4211 TrioSkipWhitespaces(self);
4212
Bjorn Reese70a9da52001-04-21 16:57:29 +00004213 /*
4214 * Read entire double number from stream. StrToDouble requires a
Daniel Veillard92ad2102001-03-27 12:47:33 +00004215 * string as input, but InStream can be anything, so we have to
4216 * collect all characters.
4217 */
4218 ch = self->current;
4219 if ((ch == '+') || (ch == '-'))
4220 {
4221 doubleString[index++] = ch;
4222 self->InStream(self, &ch);
4223 width--;
4224 }
4225
4226 start = index;
Bjorn Reese70a9da52001-04-21 16:57:29 +00004227#if defined(USE_NON_NUMBERS)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004228 switch (ch)
4229 {
Daniel Veillard92ad2102001-03-27 12:47:33 +00004230 case 'n':
4231 case 'N':
4232 /* Not-a-number */
4233 if (index != 0)
4234 break;
4235 /* FALLTHROUGH */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004236 case 'i':
4237 case 'I':
4238 /* Infinity */
4239 while (isalpha(ch) && (index - start < width))
4240 {
4241 doubleString[index++] = ch;
4242 self->InStream(self, &ch);
4243 }
4244 doubleString[index] = NIL;
4245
Daniel Veillard92ad2102001-03-27 12:47:33 +00004246 /* Case insensitive string comparison */
4247 if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
4248 StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
4249 {
4250 *target = ((start == 1 && doubleString[0] == '-'))
4251 ? -HUGE_VAL
4252 : HUGE_VAL;
4253 return TRUE;
4254 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004255 if (StrEqual(doubleString, NAN_LOWER))
4256 {
4257 /* NaN must not have a preceeding + nor - */
4258 *target = NAN;
4259 return TRUE;
4260 }
Daniel Veillard92ad2102001-03-27 12:47:33 +00004261 return FALSE;
4262
4263 default:
4264 break;
4265 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004266#endif /* defined(USE_NON_NUMBERS) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004267
Bjorn Reese70a9da52001-04-21 16:57:29 +00004268 while ((ch != EOF) && (index - start < width))
Daniel Veillard92ad2102001-03-27 12:47:33 +00004269 {
4270 /* Integer part */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004271 if (isdigit(ch))
4272 {
4273 doubleString[index++] = ch;
4274 self->InStream(self, &ch);
4275 }
4276 else if (flags & FLAGS_QUOTE)
4277 {
4278 /* Compare with thousands separator */
4279 for (j = 0; internalThousandSeparator[j] && self->current; j++)
4280 {
4281 if (internalThousandSeparator[j] != self->current)
4282 break;
4283
4284 self->InStream(self, &ch);
4285 }
4286 if (internalThousandSeparator[j])
4287 break; /* Mismatch */
4288 else
4289 continue; /* Match */
4290 }
4291 else
4292 break; /* while */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004293 }
4294 if (ch == '.')
4295 {
4296 /* Decimal part */
4297 doubleString[index++] = ch;
4298 self->InStream(self, &ch);
4299 while (isdigit(ch) && (index - start < width))
4300 {
4301 doubleString[index++] = ch;
4302 self->InStream(self, &ch);
4303 }
4304 if ((ch == 'e') || (ch == 'E'))
4305 {
4306 /* Exponent */
4307 doubleString[index++] = ch;
4308 self->InStream(self, &ch);
4309 if ((ch == '+') || (ch == '-'))
4310 {
4311 doubleString[index++] = ch;
4312 self->InStream(self, &ch);
4313 }
4314 while (isdigit(ch) && (index - start < width))
4315 {
4316 doubleString[index++] = ch;
4317 self->InStream(self, &ch);
4318 }
4319 }
4320 }
4321
4322 if ((index == start) || (*doubleString == NIL))
4323 return FALSE;
4324
4325 if (flags & FLAGS_LONGDOUBLE)
4326/* *longdoublePointer = StrToLongDouble()*/;
4327 else
4328 {
4329 *target = StrToDouble(doubleString, NULL);
4330 }
4331 return TRUE;
4332}
4333
4334/*************************************************************************
4335 * TrioReadPointer [private]
4336 */
4337static BOOLEAN_T
Bjorn Reese70a9da52001-04-21 16:57:29 +00004338TrioReadPointer(trio_T *self,
4339 void **target,
4340 int flags)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004341{
4342 LONGEST number;
4343 char buffer[sizeof(null)];
4344
4345 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
4346
4347 if (TrioReadNumber(self,
4348 &number,
4349 flags,
4350 POINTER_WIDTH,
4351 BASE_HEX))
4352 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004353 /*
4354 * The strange assignment of number is a workaround for a compiler
4355 * warning
4356 */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004357 if (target)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004358 *target = (char *)0 + number;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004359 return TRUE;
4360 }
4361 else if (TrioReadString(self,
4362 (flags & FLAGS_IGNORE)
4363 ? NULL
4364 : buffer,
4365 0,
4366 sizeof(null) - 1))
4367 {
4368 if (StrEqualCase(buffer, null))
4369 {
4370 if (target)
4371 *target = NULL;
4372 return TRUE;
4373 }
4374 }
4375 return FALSE;
4376}
4377
4378/*************************************************************************
4379 * TrioScan [private]
4380 */
4381static int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004382TrioScan(const void *source,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004383 size_t sourceSize,
4384 void (*InStream)(trio_T *, int *),
4385 const char *format,
Bjorn Reese70a9da52001-04-21 16:57:29 +00004386 va_list arglist,
4387 void **argarray)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004388{
4389#if defined(USE_MULTIBYTE)
4390 int charlen;
4391#endif
4392 int status;
4393 int assignment;
4394 parameter_T parameters[MAX_PARAMETERS];
4395 trio_T internalData;
4396 trio_T *data;
4397 int ch;
4398 int cnt;
4399 int index; /* Index of format string */
4400 int i; /* Index of current parameter */
4401 int flags;
4402 int width;
4403 int base;
4404 void *pointer;
4405
4406 assert(VALID(InStream));
4407 assert(VALID(format));
Bjorn Reese70a9da52001-04-21 16:57:29 +00004408 assert(VALID(arglist) || VALID(argarray));
Daniel Veillard92ad2102001-03-27 12:47:33 +00004409
4410 memset(&internalData, 0, sizeof(internalData));
4411 data = &internalData;
4412 data->InStream = InStream;
4413 data->location = source;
4414 data->max = sourceSize;
4415
4416#if defined(USE_LOCALE)
Bjorn Reese70a9da52001-04-21 16:57:29 +00004417 if (NULL == internalLocaleValues)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004418 {
4419 TrioSetLocale();
4420 }
4421#endif
Bjorn Reese70a9da52001-04-21 16:57:29 +00004422 if (internalDigitsUnconverted)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004423 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004424 memset(internalDigitArray, -1, sizeof(internalDigitArray));
4425 for (i = 0; i < (int)sizeof(internalDigitsLower) - 1; i++)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004426 {
Bjorn Reese70a9da52001-04-21 16:57:29 +00004427 internalDigitArray[(int)internalDigitsLower[i]] = i;
4428 internalDigitArray[(int)internalDigitsUpper[i]] = i;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004429 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004430 internalDigitsUnconverted = FALSE;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004431 }
4432
Bjorn Reese70a9da52001-04-21 16:57:29 +00004433 status = TrioPreprocess(TYPE_SCAN, format, parameters, arglist, argarray);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004434 if (status < 0)
4435 return status;
4436
4437 assignment = 0;
4438 i = 0;
4439 index = 0;
4440 data->InStream(data, &ch);
4441
4442#if defined(USE_MULTIBYTE)
4443 mblen(NULL, 0);
4444#endif
4445
4446 while (format[index])
4447 {
4448#if defined(USE_MULTIBYTE)
4449 if (! isascii(format[index]))
4450 {
4451 charlen = mblen(&format[index], MB_LEN_MAX);
4452 /* Compare multibyte characters in format string */
4453 for (cnt = 0; cnt < charlen - 1; cnt++)
4454 {
4455 if (ch != format[index + cnt])
4456 {
4457 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4458 }
4459 data->InStream(data, &ch);
4460 }
4461 continue; /* while */
4462 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00004463#endif /* defined(USE_MULTIBYTE) */
Daniel Veillard92ad2102001-03-27 12:47:33 +00004464 if (EOF == ch)
4465 return EOF;
4466
4467 if (CHAR_IDENTIFIER == format[index])
4468 {
4469 if (CHAR_IDENTIFIER == format[index + 1])
4470 {
4471 /* Two % in format matches one % in input stream */
4472 if (CHAR_IDENTIFIER == ch)
4473 {
4474 data->InStream(data, &ch);
4475 index += 2;
4476 continue; /* while format chars left */
4477 }
4478 else
4479 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4480 }
4481
4482 /* Skip the parameter entries */
4483 while (parameters[i].type == FORMAT_PARAMETER)
4484 i++;
4485
4486 flags = parameters[i].flags;
4487 /* Find width */
4488 width = parameters[i].width;
4489 if (flags & FLAGS_WIDTH_PARAMETER)
4490 {
4491 /* Get width from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004492 width = (int)parameters[width].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004493 }
4494 /* Find base */
4495 base = parameters[i].base;
4496 if (flags & FLAGS_BASE_PARAMETER)
4497 {
4498 /* Get base from parameter list */
Bjorn Reese70a9da52001-04-21 16:57:29 +00004499 base = (int)parameters[base].data.number.as_signed;
Daniel Veillard92ad2102001-03-27 12:47:33 +00004500 }
4501
4502 switch (parameters[i].type)
4503 {
4504 case FORMAT_INT:
4505 {
4506 LONGEST number;
4507
4508 if (0 == base)
4509 base = BASE_DECIMAL;
4510
4511 if (!TrioReadNumber(data,
4512 &number,
4513 flags,
4514 width,
4515 base))
4516 return assignment;
4517 assignment++;
4518
4519 if (!(flags & FLAGS_IGNORE))
4520 {
4521 pointer = parameters[i].data.pointer;
4522#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
4523 if (flags & FLAGS_SIZE_T)
4524 *(size_t *)pointer = (size_t)number;
4525 else
4526#endif
4527#if defined(QUALIFIER_PTRDIFF_T)
4528 if (flags & FLAGS_PTRDIFF_T)
4529 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
4530 else
4531#endif
4532#if defined(QUALIFIER_INTMAX_T)
4533 if (flags & FLAGS_INTMAX_T)
4534 *(intmax_t *)pointer = (intmax_t)number;
4535 else
4536#endif
4537 if (flags & FLAGS_QUAD)
4538 *(ULONGLONG int *)pointer = (ULONGLONG)number;
4539 else if (flags & FLAGS_LONG)
4540 *(long int *)pointer = (long int)number;
4541 else if (flags & FLAGS_SHORT)
4542 *(short int *)pointer = (short int)number;
4543 else
4544 *(int *)pointer = (int)number;
4545 }
4546 }
4547 break; /* FORMAT_INT */
4548
4549 case FORMAT_STRING:
4550 if (!TrioReadString(data,
4551 (flags & FLAGS_IGNORE)
4552 ? NULL
4553 : parameters[i].data.string,
4554 flags,
4555 width))
4556 return assignment;
4557 assignment++;
4558 break; /* FORMAT_STRING */
4559
4560 case FORMAT_DOUBLE:
4561 if (!TrioReadDouble(data,
4562 (flags & FLAGS_IGNORE)
4563 ? NULL
4564 : parameters[i].data.doublePointer,
4565 flags,
4566 width))
4567 return assignment;
4568 assignment++;
4569 break; /* FORMAT_DOUBLE */
4570
4571 case FORMAT_GROUP:
4572 {
4573 int characterclass[MAX_CHARACTER_CLASS + 1];
4574 int rc;
4575
4576 index += 2;
4577 memset(characterclass, 0, sizeof(characterclass));
4578 rc = TrioGetCharacterClass(format, &index, &flags,
4579 characterclass);
4580 if (rc < 0)
4581 return rc;
4582
4583 if (!TrioReadGroup(data,
4584 (flags & FLAGS_IGNORE)
4585 ? NULL
4586 : parameters[i].data.string,
4587 characterclass,
4588 flags,
4589 parameters[i].width))
4590 return assignment;
4591 assignment++;
4592 }
4593 break; /* FORMAT_GROUP */
4594
4595 case FORMAT_COUNT:
4596 pointer = parameters[i].data.pointer;
4597 if (NULL != pointer)
4598 {
4599#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
4600 if (flags & FLAGS_SIZE_T)
4601 *(size_t *)pointer = (size_t)data->committed;
4602 else
4603#endif
4604#if defined(QUALIFIER_PTRDIFF_T)
4605 if (flags & FLAGS_PTRDIFF_T)
4606 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
4607 else
4608#endif
4609#if defined(QUALIFIER_INTMAX_T)
4610 if (flags & FLAGS_INTMAX_T)
4611 *(intmax_t *)pointer = (intmax_t)data->committed;
4612 else
4613#endif
4614 if (flags & FLAGS_QUAD)
4615 {
4616 *(ULONGLONG int *)pointer = (ULONGLONG)data->committed;
4617 }
4618 else if (flags & FLAGS_LONG)
4619 {
4620 *(long int *)pointer = (long int)data->committed;
4621 }
4622 else if (flags & FLAGS_SHORT)
4623 {
4624 *(short int *)pointer = (short int)data->committed;
4625 }
4626 else
4627 {
4628 *(int *)pointer = (int)data->committed;
4629 }
4630 }
4631 break; /* FORMAT_COUNT */
4632
4633 case FORMAT_CHAR:
4634 if (!TrioReadChar(data,
4635 (flags & FLAGS_IGNORE)
4636 ? NULL
4637 : parameters[i].data.string,
4638 (width == NO_WIDTH) ? 1 : width))
4639 return assignment;
4640 assignment++;
4641 break; /* FORMAT_CHAR */
4642
4643 case FORMAT_POINTER:
4644 if (!TrioReadPointer(data,
4645 (flags & FLAGS_IGNORE)
4646 ? NULL
Bjorn Reese70a9da52001-04-21 16:57:29 +00004647 : (void **)parameters[i].data.pointer,
Daniel Veillard92ad2102001-03-27 12:47:33 +00004648 flags))
4649 return assignment;
4650 assignment++;
4651 break; /* FORMAT_POINTER */
4652
4653 case FORMAT_PARAMETER:
4654 break; /* FORMAT_PARAMETER */
4655
4656 default:
4657 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4658 }
4659 ch = data->current;
4660 index = parameters[i].indexAfterSpecifier;
4661 i++;
4662 }
4663 else /* Not an % identifier */
4664 {
4665 if (isspace((int)format[index]))
4666 {
4667 /* Whitespaces may match any amount of whitespaces */
4668 ch = TrioSkipWhitespaces(data);
4669 }
4670 else if (ch == format[index])
4671 {
4672 data->InStream(data, &ch);
4673 }
4674 else
4675 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
4676
4677 index++;
4678 }
4679 }
4680 return assignment;
4681}
4682
4683/*************************************************************************
4684 * TrioInStreamFile [private]
4685 */
4686static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00004687TrioInStreamFile(trio_T *self,
4688 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004689{
4690 FILE *file = (FILE *)self->location;
4691
4692 assert(VALID(self));
4693 assert(VALID(file));
4694
4695 self->current = fgetc(file);
4696 self->processed++;
4697 self->committed++;
4698
4699 if (VALID(intPointer))
4700 {
4701 *intPointer = self->current;
4702 }
4703}
4704
4705/*************************************************************************
4706 * TrioInStreamFileDescriptor [private]
4707 */
4708static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00004709TrioInStreamFileDescriptor(trio_T *self,
4710 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004711{
4712 int fd = *((int *)self->location);
4713 int size;
4714 unsigned char input;
4715
4716 assert(VALID(self));
4717
4718 size = read(fd, &input, sizeof(char));
4719 self->current = (size == 0) ? EOF : input;
4720 self->processed++;
4721 self->committed++;
4722
4723 if (VALID(intPointer))
4724 {
4725 *intPointer = self->current;
4726 }
4727}
4728
4729/*************************************************************************
4730 * TrioInStreamString [private]
4731 */
4732static void
Bjorn Reese70a9da52001-04-21 16:57:29 +00004733TrioInStreamString(trio_T *self,
4734 int *intPointer)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004735{
4736 unsigned char **buffer;
4737
4738 assert(VALID(self));
4739 assert(VALID(self->InStream));
4740 assert(VALID(self->location));
4741
4742 buffer = (unsigned char **)self->location;
4743 self->current = (*buffer)[0];
4744 if (self->current == NIL)
4745 self->current = EOF;
4746 (*buffer)++;
4747 self->processed++;
4748 self->committed++;
4749
4750 if (VALID(intPointer))
4751 {
4752 *intPointer = self->current;
4753 }
4754}
4755
4756/*************************************************************************
Bjorn Reese70a9da52001-04-21 16:57:29 +00004757 * scanf
Daniel Veillard92ad2102001-03-27 12:47:33 +00004758 */
4759int
Bjorn Reese70a9da52001-04-21 16:57:29 +00004760trio_scanf(const char *format,
4761 ...)
4762{
4763 int status;
4764 va_list args;
4765
4766 assert(VALID(format));
4767
4768 va_start(args, format);
4769 status = TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
4770 va_end(args);
4771 return status;
4772}
4773
4774int
4775trio_vscanf(const char *format,
4776 va_list args)
4777{
4778 assert(VALID(format));
4779 assert(VALID(args));
4780
4781 return TrioScan(stdin, 0, TrioInStreamFile, format, args, NULL);
4782}
4783
4784int
4785trio_scanfv(const char *format,
4786 void **args)
4787{
4788 assert(VALID(format));
4789 assert(VALID(args));
4790
4791 return TrioScan(stdin, 0, TrioInStreamFile, format, NULL, args);
4792}
4793
4794/*************************************************************************
4795 * fscanf
4796 */
4797int
4798trio_fscanf(FILE *file,
4799 const char *format,
4800 ...)
4801{
4802 int status;
4803 va_list args;
4804
4805 assert(VALID(file));
4806 assert(VALID(format));
4807
4808 va_start(args, format);
4809 status = TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
4810 va_end(args);
4811 return status;
4812}
4813
4814int
4815trio_vfscanf(FILE *file,
4816 const char *format,
4817 va_list args)
4818{
4819 assert(VALID(file));
4820 assert(VALID(format));
4821 assert(VALID(args));
4822
4823 return TrioScan(file, 0, TrioInStreamFile, format, args, NULL);
4824}
4825
4826int
4827trio_fscanfv(FILE *file,
4828 const char *format,
4829 void **args)
4830{
4831 assert(VALID(file));
4832 assert(VALID(format));
4833 assert(VALID(args));
4834
4835 return TrioScan(file, 0, TrioInStreamFile, format, NULL, args);
4836}
4837
4838/*************************************************************************
4839 * dscanf
4840 */
4841int
4842trio_dscanf(int fd,
4843 const char *format,
4844 ...)
4845{
4846 int status;
4847 va_list args;
4848
4849 assert(VALID(format));
4850
4851 va_start(args, format);
4852 status = TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
4853 va_end(args);
4854 return status;
4855}
4856
4857int
4858trio_vdscanf(int fd,
4859 const char *format,
4860 va_list args)
4861{
4862 assert(VALID(format));
4863 assert(VALID(args));
4864
4865 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, args, NULL);
4866}
4867
4868int
4869trio_dscanfv(int fd,
4870 const char *format,
4871 void **args)
4872{
4873 assert(VALID(format));
4874 assert(VALID(args));
4875
4876 return TrioScan(&fd, 0, TrioInStreamFileDescriptor, format, NULL, args);
4877}
4878
4879/*************************************************************************
4880 * sscanf
4881 */
4882int
4883trio_sscanf(const char *buffer,
4884 const char *format,
4885 ...)
Daniel Veillard92ad2102001-03-27 12:47:33 +00004886{
4887 int status;
4888 va_list args;
4889
4890 assert(VALID(buffer));
4891 assert(VALID(format));
4892
4893 va_start(args, format);
Bjorn Reese70a9da52001-04-21 16:57:29 +00004894 status = TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
Daniel Veillard92ad2102001-03-27 12:47:33 +00004895 va_end(args);
4896 return status;
4897}
4898
Bjorn Reese70a9da52001-04-21 16:57:29 +00004899int
4900trio_vsscanf(const char *buffer,
4901 const char *format,
4902 va_list args)
4903{
4904 assert(VALID(buffer));
4905 assert(VALID(format));
4906 assert(VALID(args));
4907
4908 return TrioScan(&buffer, 0, TrioInStreamString, format, args, NULL);
4909}
4910
4911int
4912trio_sscanfv(const char *buffer,
4913 const char *format,
4914 void **args)
4915{
4916 assert(VALID(buffer));
4917 assert(VALID(format));
4918 assert(VALID(args));
4919
4920 return TrioScan(&buffer, 0, TrioInStreamString, format, NULL, args);
4921}