1 /*************************************************************************
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 *
18 * A note to trio contributors:
19 *
20 * 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
27 /*
28 * TODO:
29 * - Scan is probably too permissive about its modifiers.
30 * - C escapes in %#[] ?
31 * - Multibyte characters (done for format parsing, except scan groups)
32 * - Complex numbers? (C99 _Complex)
33 * - Boolean values? (C99 _Bool)
34 * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
35 * to print the mantissa, e.g. NaN(0xc000000000000000)
36 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
37 * for %a, because C99 used %a for other purposes. If specified as
38 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
39 * the C99 hex-float. This means that you cannot scan %as as a hex-float
40 * immediately followed by an 's'.
41 * - Scanning of collating symbols.
42 */
43
44 /*************************************************************************
45 * Trio include files
46 */
47 #include "triodef.h"
48 #include "trio.h"
49 #include "triop.h"
50 #include "trionan.h"
51 #if !defined(TRIO_MINIMAL)
52 # include "triostr.h"
53 #endif
54
55 /**************************************************************************
56 *
57 * Definitions
58 *
59 *************************************************************************/
60
61 #include <math.h>
62 #include <limits.h>
63 #include <float.h>
64
65 #if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
66 # define TRIO_COMPILER_SUPPORTS_MULTIBYTE
67 # if !defined(MB_LEN_MAX)
68 # define MB_LEN_MAX 6
69 # endif
70 #endif
71
72 #if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
73 # define TRIO_COMPILER_SUPPORTS_MSVC_INT
74 #endif
75
76 /*************************************************************************
77 * Generic definitions
78 */
79
80 #if !(defined(DEBUG) || defined(NDEBUG))
81 # define NDEBUG
82 #endif
83
84 #include <assert.h>
85 #include <ctype.h>
86 #if !defined(TRIO_COMPILER_SUPPORTS_C99)
87 # define isblank(x) (((x)==32) || ((x)==9))
88 #endif
89 #if defined(TRIO_COMPILER_ANCIENT)
90 # include <varargs.h>
91 #else
92 # include <stdarg.h>
93 #endif
94 #include <stddef.h>
95 #include <errno.h>
96
97 #ifndef NULL
98 # define NULL 0
99 #endif
100 #define NIL ((char)0)
101 #ifndef FALSE
102 # define FALSE (1 == 0)
103 # define TRUE (! FALSE)
104 #endif
105 #define BOOLEAN_T int
106
107 /* mincore() can be used for debugging purposes */
108 #define VALID(x) (NULL != (x))
109
110 #if TRIO_ERRORS
111 /*
112 * Encode the error code and the position. This is decoded
113 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
114 */
115 # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
116 #else
117 # define TRIO_ERROR_RETURN(x,y) (-1)
118 #endif
119
120 typedef unsigned long trio_flags_t;
121
122
123 /*************************************************************************
124 * Platform specific definitions
125 */
126 #if defined(TRIO_PLATFORM_UNIX)
127 # include <unistd.h>
128 # include <signal.h>
129 # include <locale.h>
130 # define USE_LOCALE
131 #endif /* TRIO_PLATFORM_UNIX */
132 #if defined(TRIO_PLATFORM_VMS)
133 # include <unistd.h>
134 #endif
135 #if defined(TRIO_PLATFORM_WIN32)
136 # include <io.h>
137 # define read _read
138 # define write _write
139 #endif /* TRIO_PLATFORM_WIN32 */
140
141 #if TRIO_WIDECHAR
142 # if defined(TRIO_COMPILER_SUPPORTS_ISO94)
143 # include <wchar.h>
144 # include <wctype.h>
145 typedef wchar_t trio_wchar_t;
146 typedef wint_t trio_wint_t;
147 # else
148 typedef char trio_wchar_t;
149 typedef int trio_wint_t;
150 # define WCONST(x) L ## x
151 # define WEOF EOF
152 # define iswalnum(x) isalnum(x)
153 # define iswalpha(x) isalpha(x)
154 # define iswblank(x) isblank(x)
155 # define iswcntrl(x) iscntrl(x)
156 # define iswdigit(x) isdigit(x)
157 # define iswgraph(x) isgraph(x)
158 # define iswlower(x) islower(x)
159 # define iswprint(x) isprint(x)
160 # define iswpunct(x) ispunct(x)
161 # define iswspace(x) isspace(x)
162 # define iswupper(x) isupper(x)
163 # define iswxdigit(x) isxdigit(x)
164 # endif
165 #endif
166
167
168 /*************************************************************************
169 * Compiler dependent definitions
170 */
171
172 /* Support for long long */
173 #ifndef __cplusplus
174 # if !defined(USE_LONGLONG)
175 # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
176 # define USE_LONGLONG
177 # elif defined(TRIO_COMPILER_SUNPRO)
178 # define USE_LONGLONG
179 # elif defined(_LONG_LONG) || defined(_LONGLONG)
180 # define USE_LONGLONG
181 # endif
182 # endif
183 #endif
184
185 /* The extra long numbers */
186 #if defined(USE_LONGLONG)
187 typedef signed long long int trio_longlong_t;
188 typedef unsigned long long int trio_ulonglong_t;
189 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
190 typedef signed __int64 trio_longlong_t;
191 typedef unsigned __int64 trio_ulonglong_t;
192 #else
193 typedef TRIO_SIGNED long int trio_longlong_t;
194 typedef unsigned long int trio_ulonglong_t;
195 #endif
196
197 /* Maximal and fixed integer types */
198 #if defined(TRIO_COMPILER_SUPPORTS_C99)
199 # include <stdint.h>
200 typedef intmax_t trio_intmax_t;
201 typedef uintmax_t trio_uintmax_t;
202 typedef int8_t trio_int8_t;
203 typedef int16_t trio_int16_t;
204 typedef int32_t trio_int32_t;
205 typedef int64_t trio_int64_t;
206 #elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
207 # include <inttypes.h>
208 typedef intmax_t trio_intmax_t;
209 typedef uintmax_t trio_uintmax_t;
210 typedef int8_t trio_int8_t;
211 typedef int16_t trio_int16_t;
212 typedef int32_t trio_int32_t;
213 typedef int64_t trio_int64_t;
214 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
215 typedef trio_longlong_t trio_intmax_t;
216 typedef trio_ulonglong_t trio_uintmax_t;
217 typedef __int8 trio_int8_t;
218 typedef __int16 trio_int16_t;
219 typedef __int32 trio_int32_t;
220 typedef __int64 trio_int64_t;
221 #else
222 typedef trio_longlong_t trio_intmax_t;
223 typedef trio_ulonglong_t trio_uintmax_t;
224 # if defined(TRIO_INT8_T)
225 typedef TRIO_INT8_T trio_int8_t;
226 # else
227 typedef TRIO_SIGNED char trio_int8_t;
228 # endif
229 # if defined(TRIO_INT16_T)
230 typedef TRIO_INT16_T trio_int16_t;
231 # else
232 typedef TRIO_SIGNED short trio_int16_t;
233 # endif
234 # if defined(TRIO_INT32_T)
235 typedef TRIO_INT32_T trio_int32_t;
236 # else
237 typedef TRIO_SIGNED int trio_int32_t;
238 # endif
239 # if defined(TRIO_INT64_T)
240 typedef TRIO_INT64_T trio_int64_t;
241 # else
242 typedef trio_longlong_t trio_int64_t;
243 # endif
244 #endif
245
246 #if !(defined(TRIO_COMPILER_SUPPORTS_C99) \
247 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))
248 # define floorl(x) floor((double)(x))
249 # define fmodl(x,y) fmod((double)(x),(double)(y))
250 # define powl(x,y) pow((double)(x),(double)(y))
251 #endif
252
253 #define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
254
255 /*************************************************************************
256 * Internal Definitions
257 */
258
259 #ifndef DECIMAL_DIG
260 # define DECIMAL_DIG DBL_DIG
261 #endif
262
263 /* Long double sizes */
264 #ifdef LDBL_DIG
265 # define MAX_MANTISSA_DIGITS LDBL_DIG
266 # define MAX_EXPONENT_DIGITS 4
267 # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
268 #else
269 # define MAX_MANTISSA_DIGITS DECIMAL_DIG
270 # define MAX_EXPONENT_DIGITS 3
271 # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
272 #endif
273
274 #if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
275 # undef LDBL_DIG
276 # undef LDBL_MANT_DIG
277 # undef LDBL_EPSILON
278 # define LDBL_DIG DBL_DIG
279 # define LDBL_MANT_DIG DBL_MANT_DIG
280 # define LDBL_EPSILON DBL_EPSILON
281 #endif
282
283 /* The maximal number of digits is for base 2 */
284 #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
285 /* The width of a pointer. The number of bits in a hex digit is 4 */
286 #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
287
288 /* Infinite and Not-A-Number for floating-point */
289 #define INFINITE_LOWER "inf"
290 #define INFINITE_UPPER "INF"
291 #define LONG_INFINITE_LOWER "infinite"
292 #define LONG_INFINITE_UPPER "INFINITE"
293 #define NAN_LOWER "nan"
294 #define NAN_UPPER "NAN"
295
296 /* Various constants */
297 enum {
298 TYPE_PRINT = 1,
299 TYPE_SCAN = 2,
300
301 /* Flags. FLAGS_LAST must be less than ULONG_MAX */
302 FLAGS_NEW = 0,
303 FLAGS_STICKY = 1,
304 FLAGS_SPACE = 2 * FLAGS_STICKY,
305 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
306 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
307 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
308 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
309 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
310 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
311 FLAGS_QUAD = 2 * FLAGS_LONG,
312 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
313 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
314 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
315 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
316 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
317 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
318 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
319 FLAGS_WIDTH = 2 * FLAGS_UPPER,
320 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
321 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
322 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
323 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
324 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
325 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
326 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
327 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
328 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
329 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
330 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
331 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
332 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
333 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
334 FLAGS_LAST = FLAGS_FIXED_SIZE,
335 /* Reused flags */
336 FLAGS_EXCLUDE = FLAGS_SHORT,
337 FLAGS_USER_DEFINED = FLAGS_IGNORE,
338 FLAGS_ROUNDING = FLAGS_INTMAX_T,
339 /* Compounded flags */
340 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
341 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
342
343 NO_POSITION = -1,
344 NO_WIDTH = 0,
345 NO_PRECISION = -1,
346 NO_SIZE = -1,
347
348 /* Do not change these */
349 NO_BASE = -1,
350 MIN_BASE = 2,
351 MAX_BASE = 36,
352 BASE_BINARY = 2,
353 BASE_OCTAL = 8,
354 BASE_DECIMAL = 10,
355 BASE_HEX = 16,
356
357 /* Maximal number of allowed parameters */
358 MAX_PARAMETERS = 64,
359 /* Maximal number of characters in class */
360 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
361
362 /* Maximal string lengths for user-defined specifiers */
363 MAX_USER_NAME = 64,
364 MAX_USER_DATA = 256,
365
366 /* Maximal length of locale separator strings */
367 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
368 /* Maximal number of integers in grouping */
369 MAX_LOCALE_GROUPS = 64,
370
371 /* Initial size of asprintf buffer */
372 DYNAMIC_START_SIZE = 32
373 };
374
375 #define NO_GROUPING ((int)CHAR_MAX)
376
377 /* Fundamental formatting parameter types */
378 #define FORMAT_UNKNOWN 0
379 #define FORMAT_INT 1
380 #define FORMAT_DOUBLE 2
381 #define FORMAT_CHAR 3
382 #define FORMAT_STRING 4
383 #define FORMAT_POINTER 5
384 #define FORMAT_COUNT 6
385 #define FORMAT_PARAMETER 7
386 #define FORMAT_GROUP 8
387 #if TRIO_GNU
388 # define FORMAT_ERRNO 9
389 #endif
390 #if TRIO_EXTENSION
391 # define FORMAT_USER_DEFINED 10
392 #endif
393
394 /* Character constants */
395 #define CHAR_IDENTIFIER '%'
396 #define CHAR_BACKSLASH '\\'
397 #define CHAR_QUOTE '\"'
398 #define CHAR_ADJUST ' '
399
400 /* Character class expressions */
401 #define CLASS_ALNUM "[:alnum:]"
402 #define CLASS_ALPHA "[:alpha:]"
403 #define CLASS_BLANK "[:blank:]"
404 #define CLASS_CNTRL "[:cntrl:]"
405 #define CLASS_DIGIT "[:digit:]"
406 #define CLASS_GRAPH "[:graph:]"
407 #define CLASS_LOWER "[:lower:]"
408 #define CLASS_PRINT "[:print:]"
409 #define CLASS_PUNCT "[:punct:]"
410 #define CLASS_SPACE "[:space:]"
411 #define CLASS_UPPER "[:upper:]"
412 #define CLASS_XDIGIT "[:xdigit:]"
413
414 /*
415 * SPECIFIERS:
416 *
417 *
418 * a Hex-float
419 * A Hex-float
420 * c Character
421 * C Widechar character (wint_t)
422 * d Decimal
423 * e Float
424 * E Float
425 * F Float
426 * F Float
427 * g Float
428 * G Float
429 * i Integer
430 * m Error message
431 * n Count
432 * o Octal
433 * p Pointer
434 * s String
435 * S Widechar string (wchar_t *)
436 * u Unsigned
437 * x Hex
438 * X Hex
439 * [] Group
440 * <> User-defined
441 *
442 * Reserved:
443 *
444 * D Binary Coded Decimal %D(length,precision) (OS/390)
445 */
446 #define SPECIFIER_CHAR 'c'
447 #define SPECIFIER_STRING 's'
448 #define SPECIFIER_DECIMAL 'd'
449 #define SPECIFIER_INTEGER 'i'
450 #define SPECIFIER_UNSIGNED 'u'
451 #define SPECIFIER_OCTAL 'o'
452 #define SPECIFIER_HEX 'x'
453 #define SPECIFIER_HEX_UPPER 'X'
454 #define SPECIFIER_FLOAT_E 'e'
455 #define SPECIFIER_FLOAT_E_UPPER 'E'
456 #define SPECIFIER_FLOAT_F 'f'
457 #define SPECIFIER_FLOAT_F_UPPER 'F'
458 #define SPECIFIER_FLOAT_G 'g'
459 #define SPECIFIER_FLOAT_G_UPPER 'G'
460 #define SPECIFIER_POINTER 'p'
461 #define SPECIFIER_GROUP '['
462 #define SPECIFIER_UNGROUP ']'
463 #define SPECIFIER_COUNT 'n'
464 #if TRIO_UNIX98
465 # define SPECIFIER_CHAR_UPPER 'C'
466 # define SPECIFIER_STRING_UPPER 'S'
467 #endif
468 #if TRIO_C99
469 # define SPECIFIER_HEXFLOAT 'a'
470 # define SPECIFIER_HEXFLOAT_UPPER 'A'
471 #endif
472 #if TRIO_GNU
473 # define SPECIFIER_ERRNO 'm'
474 #endif
475 #if TRIO_EXTENSION
476 # define SPECIFIER_BINARY 'b'
477 # define SPECIFIER_BINARY_UPPER 'B'
478 # define SPECIFIER_USER_DEFINED_BEGIN '<'
479 # define SPECIFIER_USER_DEFINED_END '>'
480 # define SPECIFIER_USER_DEFINED_SEPARATOR ':'
481 #endif
482
483 /*
484 * QUALIFIERS:
485 *
486 *
487 * Numbers = d,i,o,u,x,X
488 * Float = a,A,e,E,f,F,g,G
489 * String = s
490 * Char = c
491 *
492 *
493 * 9$ Position
494 * Use the 9th parameter. 9 can be any number between 1 and
495 * the maximal argument
496 *
497 * 9 Width
498 * Set width to 9. 9 can be any number, but must not be postfixed
499 * by '$'
500 *
501 * h Short
502 * Numbers:
503 * (unsigned) short int
504 *
505 * hh Short short
506 * Numbers:
507 * (unsigned) char
508 *
509 * l Long
510 * Numbers:
511 * (unsigned) long int
512 * String:
513 * as the S specifier
514 * Char:
515 * as the C specifier
516 *
517 * ll Long Long
518 * Numbers:
519 * (unsigned) long long int
520 *
521 * L Long Double
522 * Float
523 * long double
524 *
525 * # Alternative
526 * Float:
527 * Decimal-point is always present
528 * String:
529 * non-printable characters are handled as \number
530 *
531 * Spacing
532 *
533 * + Sign
534 *
535 * - Alignment
536 *
537 * . Precision
538 *
539 * * Parameter
540 * print: use parameter
541 * scan: no parameter (ignore)
542 *
543 * q Quad
544 *
545 * Z size_t
546 *
547 * w Widechar
548 *
549 * ' Thousands/quote
550 * Numbers:
551 * Integer part grouped in thousands
552 * Binary numbers:
553 * Number grouped in nibbles (4 bits)
554 * String:
555 * Quoted string
556 *
557 * j intmax_t
558 * t prtdiff_t
559 * z size_t
560 *
561 * ! Sticky
562 * @ Parameter (for both print and scan)
563 *
564 * I n-bit Integer
565 * Numbers:
566 * The following options exists
567 * I8 = 8-bit integer
568 * I16 = 16-bit integer
569 * I32 = 32-bit integer
570 * I64 = 64-bit integer
571 */
572 #define QUALIFIER_POSITION '$'
573 #define QUALIFIER_SHORT 'h'
574 #define QUALIFIER_LONG 'l'
575 #define QUALIFIER_LONG_UPPER 'L'
576 #define QUALIFIER_ALTERNATIVE '#'
577 #define QUALIFIER_SPACE ' '
578 #define QUALIFIER_PLUS '+'
579 #define QUALIFIER_MINUS '-'
580 #define QUALIFIER_DOT '.'
581 #define QUALIFIER_STAR '*'
582 #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
583 #if TRIO_C99
584 # define QUALIFIER_SIZE_T 'z'
585 # define QUALIFIER_PTRDIFF_T 't'
586 # define QUALIFIER_INTMAX_T 'j'
587 #endif
588 #if TRIO_BSD || TRIO_GNU
589 # define QUALIFIER_QUAD 'q'
590 #endif
591 #if TRIO_GNU
592 # define QUALIFIER_SIZE_T_UPPER 'Z'
593 #endif
594 #if TRIO_MISC
595 # define QUALIFIER_WIDECHAR 'w'
596 #endif
597 #if TRIO_MICROSOFT
598 # define QUALIFIER_FIXED_SIZE 'I'
599 #endif
600 #if TRIO_EXTENSION
601 # define QUALIFIER_QUOTE '\''
602 # define QUALIFIER_STICKY '!'
603 # define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
604 # define QUALIFIER_PARAM '@' /* Experimental */
605 # define QUALIFIER_COLON ':' /* For scanlists */
606 # define QUALIFIER_EQUAL '=' /* For scanlists */
607 # define QUALIFIER_ROUNDING_UPPER 'R'
608 #endif
609
610
611 /*************************************************************************
612 *
613 * Internal Structures
614 *
615 *************************************************************************/
616
617 /* Parameters */
618 typedef struct {
619 /* An indication of which entry in the data union is used */
620 int type;
621 /* The flags */
622 trio_flags_t flags;
623 /* The width qualifier */
624 int width;
625 /* The precision qualifier */
626 int precision;
627 /* The base qualifier */
628 int base;
629 /* The size for the variable size qualifier */
630 int varsize;
631 /* The marker of the end of the specifier */
632 int indexAfterSpecifier;
633 /* The data from the argument list */
634 union {
635 char *string;
636 #if TRIO_WIDECHAR
637 trio_wchar_t *wstring;
638 #endif
639 trio_pointer_t pointer;
640 union {
641 trio_intmax_t as_signed;
642 trio_uintmax_t as_unsigned;
643 } number;
644 double doubleNumber;
645 double *doublePointer;
646 trio_long_double_t longdoubleNumber;
647 trio_long_double_t *longdoublePointer;
648 int errorNumber;
649 } data;
650 /* For the user-defined specifier */
651 char user_name[MAX_USER_NAME];
652 char user_data[MAX_USER_DATA];
653 } trio_parameter_t;
654
655 /* Container for customized functions */
656 typedef struct {
657 union {
658 trio_outstream_t out;
659 trio_instream_t in;
660 } stream;
661 trio_pointer_t closure;
662 } trio_custom_t;
663
664 /* General trio "class" */
665 typedef struct _trio_class_t {
666 /*
667 * The function to write characters to a stream.
668 */
669 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
670 /*
671 * The function to read characters from a stream.
672 */
673 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
674 /*
675 * The current location in the stream.
676 */
677 trio_pointer_t location;
678 /*
679 * The character currently being processed.
680 */
681 int current;
682 /*
683 * The number of characters that would have been written/read
684 * if there had been sufficient space.
685 */
686 int processed;
687 /*
688 * The number of characters that are actually written/read.
689 * Processed and committed will only differ for the *nprintf
690 * and *nscanf functions.
691 */
692 int committed;
693 /*
694 * The upper limit of characters that may be written/read.
695 */
696 int max;
697 /*
698 * The last output error that was detected.
699 */
700 int error;
701 } trio_class_t;
702
703 /* References (for user-defined callbacks) */
704 typedef struct _trio_reference_t {
705 trio_class_t *data;
706 trio_parameter_t *parameter;
707 } trio_reference_t;
708
709 /* Registered entries (for user-defined callbacks) */
710 typedef struct _trio_userdef_t {
711 struct _trio_userdef_t *next;
712 trio_callback_t callback;
713 char *name;
714 } trio_userdef_t;
715
716 /*************************************************************************
717 *
718 * Internal Variables
719 *
720 *************************************************************************/
721
722 static TRIO_CONST char rcsid[] = "@(#)Id";
723
724 /*
725 * Need this to workaround a parser bug in HP C/iX compiler that fails
726 * to resolves macro definitions that includes type 'long double',
727 * e.g: va_arg(arg_ptr, long double)
728 */
729 #if defined(TRIO_PLATFORM_MPEIX)
730 static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
731 #endif
732
733 static TRIO_CONST char internalNullString[] = "(nil)";
734
735 #if defined(USE_LOCALE)
736 static struct lconv *internalLocaleValues = NULL;
737 #endif
738
739 /*
740 * UNIX98 says "in a locale where the radix character is not defined,
741 * the radix character defaults to a period (.)"
742 */
743 static int internalDecimalPointLength = 1;
744 static int internalThousandSeparatorLength = 1;
745 static char internalDecimalPoint = '.';
746 static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
747 static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
748 static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
749
750 static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
751 static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
752 static BOOLEAN_T internalDigitsUnconverted = TRUE;
753 static int internalDigitArray[128];
754 #if TRIO_EXTENSION
755 static BOOLEAN_T internalCollationUnconverted = TRUE;
756 static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
757 #endif
758
759 #if TRIO_EXTENSION
760 static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
761 static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
762 static trio_userdef_t *internalUserDef = NULL;
763 #endif
764
765
766 /*************************************************************************
767 *
768 * Internal Functions
769 *
770 ************************************************************************/
771
772 #if defined(TRIO_MINIMAL)
773 # define TRIO_STRING_PUBLIC static
774 # include "triostr.c"
775 #endif /* defined(TRIO_MINIMAL) */
776
777 /*************************************************************************
778 * TrioIsQualifier
779 *
780 * Description:
781 * Remember to add all new qualifiers to this function.
782 * QUALIFIER_POSITION must not be added.
783 */
784 TRIO_PRIVATE BOOLEAN_T
785 TrioIsQualifier
786 TRIO_ARGS1((character),
787 TRIO_CONST char character)
788 {
789 /* QUALIFIER_POSITION is not included */
790 switch (character)
791 {
792 case '0': case '1': case '2': case '3': case '4':
793 case '5': case '6': case '7': case '8': case '9':
794 case QUALIFIER_PLUS:
795 case QUALIFIER_MINUS:
796 case QUALIFIER_SPACE:
797 case QUALIFIER_DOT:
798 case QUALIFIER_STAR:
799 case QUALIFIER_ALTERNATIVE:
800 case QUALIFIER_SHORT:
801 case QUALIFIER_LONG:
802 case QUALIFIER_LONG_UPPER:
803 case QUALIFIER_CIRCUMFLEX:
804 #if defined(QUALIFIER_SIZE_T)
805 case QUALIFIER_SIZE_T:
806 #endif
807 #if defined(QUALIFIER_PTRDIFF_T)
808 case QUALIFIER_PTRDIFF_T:
809 #endif
810 #if defined(QUALIFIER_INTMAX_T)
811 case QUALIFIER_INTMAX_T:
812 #endif
813 #if defined(QUALIFIER_QUAD)
814 case QUALIFIER_QUAD:
815 #endif
816 #if defined(QUALIFIER_SIZE_T_UPPER)
817 case QUALIFIER_SIZE_T_UPPER:
818 #endif
819 #if defined(QUALIFIER_WIDECHAR)
820 case QUALIFIER_WIDECHAR:
821 #endif
822 #if defined(QUALIFIER_QUOTE)
823 case QUALIFIER_QUOTE:
824 #endif
825 #if defined(QUALIFIER_STICKY)
826 case QUALIFIER_STICKY:
827 #endif
828 #if defined(QUALIFIER_VARSIZE)
829 case QUALIFIER_VARSIZE:
830 #endif
831 #if defined(QUALIFIER_PARAM)
832 case QUALIFIER_PARAM:
833 #endif
834 #if defined(QUALIFIER_FIXED_SIZE)
835 case QUALIFIER_FIXED_SIZE:
836 #endif
837 #if defined(QUALIFIER_ROUNDING_UPPER)
838 case QUALIFIER_ROUNDING_UPPER:
839 #endif
840 return TRUE;
841 default:
842 return FALSE;
843 }
844 }
845
846 /*************************************************************************
847 * TrioSetLocale
848 */
849 #if defined(USE_LOCALE)
850 TRIO_PRIVATE void
TrioSetLocale(TRIO_NOARGS)851 TrioSetLocale(TRIO_NOARGS)
852 {
853 internalLocaleValues = (struct lconv *)localeconv();
854 if (internalLocaleValues)
855 {
856 if ((internalLocaleValues->decimal_point) &&
857 (internalLocaleValues->decimal_point[0] != NIL))
858 {
859 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
860 if (internalDecimalPointLength == 1)
861 {
862 internalDecimalPoint = internalLocaleValues->decimal_point[0];
863 }
864 else
865 {
866 internalDecimalPoint = NIL;
867 trio_copy_max(internalDecimalPointString,
868 sizeof(internalDecimalPointString),
869 internalLocaleValues->decimal_point);
870 }
871 }
872 if ((internalLocaleValues->thousands_sep) &&
873 (internalLocaleValues->thousands_sep[0] != NIL))
874 {
875 trio_copy_max(internalThousandSeparator,
876 sizeof(internalThousandSeparator),
877 internalLocaleValues->thousands_sep);
878 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
879 }
880 if ((internalLocaleValues->grouping) &&
881 (internalLocaleValues->grouping[0] != NIL))
882 {
883 trio_copy_max(internalGrouping,
884 sizeof(internalGrouping),
885 internalLocaleValues->grouping);
886 }
887 }
888 }
889 #endif /* defined(USE_LOCALE) */
890
891 TRIO_PRIVATE int
892 TrioCalcThousandSeparatorLength
893 TRIO_ARGS1((digits),
894 int digits)
895 {
896 #if TRIO_EXTENSION
897 int count = 0;
898 int step = NO_GROUPING;
899 char *groupingPointer = internalGrouping;
900
901 while (digits > 0)
902 {
903 if (*groupingPointer == CHAR_MAX)
904 {
905 /* Disable grouping */
906 break; /* while */
907 }
908 else if (*groupingPointer == 0)
909 {
910 /* Repeat last group */
911 if (step == NO_GROUPING)
912 {
913 /* Error in locale */
914 break; /* while */
915 }
916 }
917 else
918 {
919 step = *groupingPointer++;
920 }
921 if (digits > step)
922 count += internalThousandSeparatorLength;
923 digits -= step;
924 }
925 return count;
926 #else
927 return 0;
928 #endif
929 }
930
931 TRIO_PRIVATE BOOLEAN_T
932 TrioFollowedBySeparator
933 TRIO_ARGS1((position),
934 int position)
935 {
936 #if TRIO_EXTENSION
937 int step = 0;
938 char *groupingPointer = internalGrouping;
939
940 position--;
941 if (position == 0)
942 return FALSE;
943 while (position > 0)
944 {
945 if (*groupingPointer == CHAR_MAX)
946 {
947 /* Disable grouping */
948 break; /* while */
949 }
950 else if (*groupingPointer != 0)
951 {
952 step = *groupingPointer++;
953 }
954 if (step == 0)
955 break;
956 position -= step;
957 }
958 return (position == 0);
959 #else
960 return FALSE;
961 #endif
962 }
963
964 /*************************************************************************
965 * TrioGetPosition
966 *
967 * Get the %n$ position.
968 */
969 TRIO_PRIVATE int
970 TrioGetPosition
971 TRIO_ARGS2((format, indexPointer),
972 TRIO_CONST char *format,
973 int *indexPointer)
974 {
975 #if TRIO_UNIX98
976 char *tmpformat;
977 int number = 0;
978 int index = *indexPointer;
979
980 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
981 index = (int)(tmpformat - format);
982 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
983 {
984 *indexPointer = index;
985 /*
986 * number is decreased by 1, because n$ starts from 1, whereas
987 * the array it is indexing starts from 0.
988 */
989 return number - 1;
990 }
991 #endif
992 return NO_POSITION;
993 }
994
995 #if TRIO_EXTENSION
996 /*************************************************************************
997 * TrioFindNamespace
998 *
999 * Find registered user-defined specifier.
1000 * The prev argument is used for optimization only.
1001 */
1002 TRIO_PRIVATE trio_userdef_t *
1003 TrioFindNamespace
1004 TRIO_ARGS2((name, prev),
1005 TRIO_CONST char *name,
1006 trio_userdef_t **prev)
1007 {
1008 trio_userdef_t *def;
1009
1010 if (internalEnterCriticalRegion)
1011 (void)internalEnterCriticalRegion(NULL);
1012
1013 for (def = internalUserDef; def; def = def->next)
1014 {
1015 /* Case-sensitive string comparison */
1016 if (trio_equal_case(def->name, name))
1017 break;
1018
1019 if (prev)
1020 *prev = def;
1021 }
1022
1023 if (internalLeaveCriticalRegion)
1024 (void)internalLeaveCriticalRegion(NULL);
1025
1026 return def;
1027 }
1028 #endif
1029
1030 /*************************************************************************
1031 * TrioPower
1032 *
1033 * Description:
1034 * Calculate pow(base, exponent), where number and exponent are integers.
1035 */
1036 TRIO_PRIVATE trio_long_double_t
1037 TrioPower
1038 TRIO_ARGS2((number, exponent),
1039 int number,
1040 int exponent)
1041 {
1042 trio_long_double_t result;
1043
1044 if (number == 10)
1045 {
1046 switch (exponent)
1047 {
1048 /* Speed up calculation of common cases */
1049 case 0:
1050 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1051 break;
1052 case 1:
1053 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1054 break;
1055 case 2:
1056 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1057 break;
1058 case 3:
1059 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1060 break;
1061 case 4:
1062 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1063 break;
1064 case 5:
1065 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1066 break;
1067 case 6:
1068 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1069 break;
1070 case 7:
1071 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1072 break;
1073 case 8:
1074 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1075 break;
1076 case 9:
1077 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1078 break;
1079 default:
1080 result = powl((trio_long_double_t)number,
1081 (trio_long_double_t)exponent);
1082 break;
1083 }
1084 }
1085 else
1086 {
1087 return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1088 }
1089 return result;
1090 }
1091
1092 /*************************************************************************
1093 * TrioLogarithm
1094 */
1095 TRIO_PRIVATE double
1096 TrioLogarithm
1097 TRIO_ARGS2((number, base),
1098 double number,
1099 int base)
1100 {
1101 double result;
1102
1103 if (number <= 0.0)
1104 {
1105 /* xlC crashes on log(0) */
1106 result = (number == 0.0) ? trio_ninf() : trio_nan();
1107 }
1108 else
1109 {
1110 if (base == 10)
1111 {
1112 result = log10(number);
1113 }
1114 else
1115 {
1116 result = log10(number) / log10((double)base);
1117 }
1118 }
1119 return result;
1120 }
1121
1122 /*************************************************************************
1123 * TrioLogarithmBase
1124 */
1125 TRIO_PRIVATE double
1126 TrioLogarithmBase
1127 TRIO_ARGS1((base),
1128 int base)
1129 {
1130 switch (base)
1131 {
1132 case BASE_BINARY : return 1.0;
1133 case BASE_OCTAL : return 3.0;
1134 case BASE_DECIMAL: return 3.321928094887362345;
1135 case BASE_HEX : return 4.0;
1136 default : return TrioLogarithm((double)base, 2);
1137 }
1138 }
1139
1140 /*************************************************************************
1141 * TrioParse
1142 *
1143 * Description:
1144 * Parse the format string
1145 */
1146 TRIO_PRIVATE int
1147 TrioParse
1148 TRIO_ARGS5((type, format, parameters, arglist, argarray),
1149 int type,
1150 TRIO_CONST char *format,
1151 trio_parameter_t *parameters,
1152 va_list *arglist,
1153 trio_pointer_t *argarray)
1154 {
1155 /* Count the number of times a parameter is referenced */
1156 unsigned short usedEntries[MAX_PARAMETERS];
1157 /* Parameter counters */
1158 int parameterPosition;
1159 int currentParam;
1160 int maxParam = -1;
1161 /* Utility variables */
1162 trio_flags_t flags;
1163 int width;
1164 int precision;
1165 int varsize;
1166 int base;
1167 int index; /* Index into formatting string */
1168 int dots; /* Count number of dots in modifier part */
1169 BOOLEAN_T positional; /* Does the specifier have a positional? */
1170 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
1171 /*
1172 * indices specifies the order in which the parameters must be
1173 * read from the va_args (this is necessary to handle positionals)
1174 */
1175 int indices[MAX_PARAMETERS];
1176 int pos = 0;
1177 /* Various variables */
1178 char ch;
1179 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1180 int charlen;
1181 #endif
1182 int save_errno;
1183 int i = -1;
1184 int num;
1185 char *tmpformat;
1186
1187 /* One and only one of arglist and argarray must be used */
1188 assert((arglist != NULL) ^ (argarray != NULL));
1189
1190 /*
1191 * The 'parameters' array is not initialized, but we need to
1192 * know which entries we have used.
1193 */
1194 memset(usedEntries, 0, sizeof(usedEntries));
1195
1196 save_errno = errno;
1197 index = 0;
1198 parameterPosition = 0;
1199 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1200 (void)mblen(NULL, 0);
1201 #endif
1202
1203 while (format[index])
1204 {
1205 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1206 if (! isascii(format[index]))
1207 {
1208 /*
1209 * Multibyte characters cannot be legal specifiers or
1210 * modifiers, so we skip over them.
1211 */
1212 charlen = mblen(&format[index], MB_LEN_MAX);
1213 index += (charlen > 0) ? charlen : 1;
1214 continue; /* while */
1215 }
1216 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
1217 if (CHAR_IDENTIFIER == format[index++])
1218 {
1219 if (CHAR_IDENTIFIER == format[index])
1220 {
1221 index++;
1222 continue; /* while */
1223 }
1224
1225 flags = FLAGS_NEW;
1226 dots = 0;
1227 currentParam = TrioGetPosition(format, &index);
1228 positional = (NO_POSITION != currentParam);
1229 if (!positional)
1230 {
1231 /* We have no positional, get the next counter */
1232 currentParam = parameterPosition;
1233 }
1234 if(currentParam >= MAX_PARAMETERS)
1235 {
1236 /* Bail out completely to make the error more obvious */
1237 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1238 }
1239
1240 if (currentParam > maxParam)
1241 maxParam = currentParam;
1242
1243 /* Default values */
1244 width = NO_WIDTH;
1245 precision = NO_PRECISION;
1246 base = NO_BASE;
1247 varsize = NO_SIZE;
1248
1249 while (TrioIsQualifier(format[index]))
1250 {
1251 ch = format[index++];
1252
1253 switch (ch)
1254 {
1255 case QUALIFIER_SPACE:
1256 flags |= FLAGS_SPACE;
1257 break;
1258
1259 case QUALIFIER_PLUS:
1260 flags |= FLAGS_SHOWSIGN;
1261 break;
1262
1263 case QUALIFIER_MINUS:
1264 flags |= FLAGS_LEFTADJUST;
1265 flags &= ~FLAGS_NILPADDING;
1266 break;
1267
1268 case QUALIFIER_ALTERNATIVE:
1269 flags |= FLAGS_ALTERNATIVE;
1270 break;
1271
1272 case QUALIFIER_DOT:
1273 if (dots == 0) /* Precision */
1274 {
1275 dots++;
1276
1277 /* Skip if no precision */
1278 if (QUALIFIER_DOT == format[index])
1279 break;
1280
1281 /* After the first dot we have the precision */
1282 flags |= FLAGS_PRECISION;
1283 if ((QUALIFIER_STAR == format[index])
1284 #if defined(QUALIFIER_PARAM)
1285 || (QUALIFIER_PARAM == format[index])
1286 #endif
1287 )
1288 {
1289 index++;
1290 flags |= FLAGS_PRECISION_PARAMETER;
1291
1292 precision = TrioGetPosition(format, &index);
1293 if (precision == NO_POSITION)
1294 {
1295 parameterPosition++;
1296 if (positional)
1297 precision = parameterPosition;
1298 else
1299 {
1300 precision = currentParam;
1301 currentParam = precision + 1;
1302 }
1303 }
1304 else
1305 {
1306 if (! positional)
1307 currentParam = precision + 1;
1308 if (width > maxParam)
1309 maxParam = precision;
1310 }
1311 if (currentParam > maxParam)
1312 maxParam = currentParam;
1313 }
1314 else
1315 {
1316 precision = trio_to_long(&format[index],
1317 &tmpformat,
1318 BASE_DECIMAL);
1319 index = (int)(tmpformat - format);
1320 }
1321 }
1322 else if (dots == 1) /* Base */
1323 {
1324 dots++;
1325
1326 /* After the second dot we have the base */
1327 flags |= FLAGS_BASE;
1328 if ((QUALIFIER_STAR == format[index])
1329 #if defined(QUALIFIER_PARAM)
1330 || (QUALIFIER_PARAM == format[index])
1331 #endif
1332 )
1333 {
1334 index++;
1335 flags |= FLAGS_BASE_PARAMETER;
1336 base = TrioGetPosition(format, &index);
1337 if (base == NO_POSITION)
1338 {
1339 parameterPosition++;
1340 if (positional)
1341 base = parameterPosition;
1342 else
1343 {
1344 base = currentParam;
1345 currentParam = base + 1;
1346 }
1347 }
1348 else
1349 {
1350 if (! positional)
1351 currentParam = base + 1;
1352 if (base > maxParam)
1353 maxParam = base;
1354 }
1355 if (currentParam > maxParam)
1356 maxParam = currentParam;
1357 }
1358 else
1359 {
1360 base = trio_to_long(&format[index],
1361 &tmpformat,
1362 BASE_DECIMAL);
1363 if (base > MAX_BASE)
1364 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1365 index = (int)(tmpformat - format);
1366 }
1367 }
1368 else
1369 {
1370 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1371 }
1372 break; /* QUALIFIER_DOT */
1373
1374 #if defined(QUALIFIER_PARAM)
1375 case QUALIFIER_PARAM:
1376 type = TYPE_PRINT;
1377 /* FALLTHROUGH */
1378 #endif
1379 case QUALIFIER_STAR:
1380 /* This has different meanings for print and scan */
1381 if (TYPE_PRINT == type)
1382 {
1383 /* Read with from parameter */
1384 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1385 width = TrioGetPosition(format, &index);
1386 if (width == NO_POSITION)
1387 {
1388 parameterPosition++;
1389 if (positional)
1390 width = parameterPosition;
1391 else
1392 {
1393 width = currentParam;
1394 currentParam = width + 1;
1395 }
1396 }
1397 else
1398 {
1399 if (! positional)
1400 currentParam = width + 1;
1401 if (width > maxParam)
1402 maxParam = width;
1403 }
1404 if (currentParam > maxParam)
1405 maxParam = currentParam;
1406 }
1407 else
1408 {
1409 /* Scan, but do not store result */
1410 flags |= FLAGS_IGNORE;
1411 }
1412
1413 break; /* QUALIFIER_STAR */
1414
1415 case '0':
1416 if (! (flags & FLAGS_LEFTADJUST))
1417 flags |= FLAGS_NILPADDING;
1418 /* FALLTHROUGH */
1419 case '1': case '2': case '3': case '4':
1420 case '5': case '6': case '7': case '8': case '9':
1421 flags |= FLAGS_WIDTH;
1422 /* &format[index - 1] is used to "rewind" the read
1423 * character from format
1424 */
1425 width = trio_to_long(&format[index - 1],
1426 &tmpformat,
1427 BASE_DECIMAL);
1428 index = (int)(tmpformat - format);
1429 break;
1430
1431 case QUALIFIER_SHORT:
1432 if (flags & FLAGS_SHORTSHORT)
1433 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1434 else if (flags & FLAGS_SHORT)
1435 flags |= FLAGS_SHORTSHORT;
1436 else
1437 flags |= FLAGS_SHORT;
1438 break;
1439
1440 case QUALIFIER_LONG:
1441 if (flags & FLAGS_QUAD)
1442 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1443 else if (flags & FLAGS_LONG)
1444 flags |= FLAGS_QUAD;
1445 else
1446 flags |= FLAGS_LONG;
1447 break;
1448
1449 case QUALIFIER_LONG_UPPER:
1450 flags |= FLAGS_LONGDOUBLE;
1451 break;
1452
1453 #if defined(QUALIFIER_SIZE_T)
1454 case QUALIFIER_SIZE_T:
1455 flags |= FLAGS_SIZE_T;
1456 /* Modify flags for later truncation of number */
1457 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
1458 flags |= FLAGS_QUAD;
1459 else if (sizeof(size_t) == sizeof(long))
1460 flags |= FLAGS_LONG;
1461 break;
1462 #endif
1463
1464 #if defined(QUALIFIER_PTRDIFF_T)
1465 case QUALIFIER_PTRDIFF_T:
1466 flags |= FLAGS_PTRDIFF_T;
1467 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
1468 flags |= FLAGS_QUAD;
1469 else if (sizeof(ptrdiff_t) == sizeof(long))
1470 flags |= FLAGS_LONG;
1471 break;
1472 #endif
1473
1474 #if defined(QUALIFIER_INTMAX_T)
1475 case QUALIFIER_INTMAX_T:
1476 flags |= FLAGS_INTMAX_T;
1477 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
1478 flags |= FLAGS_QUAD;
1479 else if (sizeof(trio_intmax_t) == sizeof(long))
1480 flags |= FLAGS_LONG;
1481 break;
1482 #endif
1483
1484 #if defined(QUALIFIER_QUAD)
1485 case QUALIFIER_QUAD:
1486 flags |= FLAGS_QUAD;
1487 break;
1488 #endif
1489
1490 #if defined(QUALIFIER_FIXED_SIZE)
1491 case QUALIFIER_FIXED_SIZE:
1492 if (flags & FLAGS_FIXED_SIZE)
1493 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1494
1495 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1496 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
1497 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1498
1499 if ((format[index] == '6') &&
1500 (format[index + 1] == '4'))
1501 {
1502 varsize = sizeof(trio_int64_t);
1503 index += 2;
1504 }
1505 else if ((format[index] == '3') &&
1506 (format[index + 1] == '2'))
1507 {
1508 varsize = sizeof(trio_int32_t);
1509 index += 2;
1510 }
1511 else if ((format[index] == '1') &&
1512 (format[index + 1] == '6'))
1513 {
1514 varsize = sizeof(trio_int16_t);
1515 index += 2;
1516 }
1517 else if (format[index] == '8')
1518 {
1519 varsize = sizeof(trio_int8_t);
1520 index++;
1521 }
1522 else
1523 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1524
1525 flags |= FLAGS_FIXED_SIZE;
1526 break;
1527 #endif
1528
1529 #if defined(QUALIFIER_WIDECHAR)
1530 case QUALIFIER_WIDECHAR:
1531 flags |= FLAGS_WIDECHAR;
1532 break;
1533 #endif
1534
1535 #if defined(QUALIFIER_SIZE_T_UPPER)
1536 case QUALIFIER_SIZE_T_UPPER:
1537 break;
1538 #endif
1539
1540 #if defined(QUALIFIER_QUOTE)
1541 case QUALIFIER_QUOTE:
1542 flags |= FLAGS_QUOTE;
1543 break;
1544 #endif
1545
1546 #if defined(QUALIFIER_STICKY)
1547 case QUALIFIER_STICKY:
1548 flags |= FLAGS_STICKY;
1549 gotSticky = TRUE;
1550 break;
1551 #endif
1552
1553 #if defined(QUALIFIER_VARSIZE)
1554 case QUALIFIER_VARSIZE:
1555 flags |= FLAGS_VARSIZE_PARAMETER;
1556 parameterPosition++;
1557 if (positional)
1558 varsize = parameterPosition;
1559 else
1560 {
1561 varsize = currentParam;
1562 currentParam = varsize + 1;
1563 }
1564 if (currentParam > maxParam)
1565 maxParam = currentParam;
1566 break;
1567 #endif
1568
1569 #if defined(QUALIFIER_ROUNDING_UPPER)
1570 case QUALIFIER_ROUNDING_UPPER:
1571 flags |= FLAGS_ROUNDING;
1572 break;
1573 #endif
1574
1575 default:
1576 /* Bail out completely to make the error more obvious */
1577 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1578 }
1579 } /* while qualifier */
1580
1581 /*
1582 * Parameters only need the type and value. The value is
1583 * read later.
1584 */
1585 if (flags & FLAGS_WIDTH_PARAMETER)
1586 {
1587 usedEntries[width] += 1;
1588 parameters[pos].type = FORMAT_PARAMETER;
1589 parameters[pos].flags = 0;
1590 indices[width] = pos;
1591 width = pos++;
1592 }
1593 if (flags & FLAGS_PRECISION_PARAMETER)
1594 {
1595 usedEntries[precision] += 1;
1596 parameters[pos].type = FORMAT_PARAMETER;
1597 parameters[pos].flags = 0;
1598 indices[precision] = pos;
1599 precision = pos++;
1600 }
1601 if (flags & FLAGS_BASE_PARAMETER)
1602 {
1603 usedEntries[base] += 1;
1604 parameters[pos].type = FORMAT_PARAMETER;
1605 parameters[pos].flags = 0;
1606 indices[base] = pos;
1607 base = pos++;
1608 }
1609 if (flags & FLAGS_VARSIZE_PARAMETER)
1610 {
1611 usedEntries[varsize] += 1;
1612 parameters[pos].type = FORMAT_PARAMETER;
1613 parameters[pos].flags = 0;
1614 indices[varsize] = pos;
1615 varsize = pos++;
1616 }
1617
1618 indices[currentParam] = pos;
1619
1620 switch (format[index++])
1621 {
1622 #if defined(SPECIFIER_CHAR_UPPER)
1623 case SPECIFIER_CHAR_UPPER:
1624 flags |= FLAGS_WIDECHAR;
1625 /* FALLTHROUGH */
1626 #endif
1627 case SPECIFIER_CHAR:
1628 if (flags & FLAGS_LONG)
1629 flags |= FLAGS_WIDECHAR;
1630 else if (flags & FLAGS_SHORT)
1631 flags &= ~FLAGS_WIDECHAR;
1632 parameters[pos].type = FORMAT_CHAR;
1633 break;
1634
1635 #if defined(SPECIFIER_STRING_UPPER)
1636 case SPECIFIER_STRING_UPPER:
1637 flags |= FLAGS_WIDECHAR;
1638 /* FALLTHROUGH */
1639 #endif
1640 case SPECIFIER_STRING:
1641 if (flags & FLAGS_LONG)
1642 flags |= FLAGS_WIDECHAR;
1643 else if (flags & FLAGS_SHORT)
1644 flags &= ~FLAGS_WIDECHAR;
1645 parameters[pos].type = FORMAT_STRING;
1646 break;
1647
1648 case SPECIFIER_GROUP:
1649 if (TYPE_SCAN == type)
1650 {
1651 int depth = 1;
1652 parameters[pos].type = FORMAT_GROUP;
1653 if (format[index] == QUALIFIER_CIRCUMFLEX)
1654 index++;
1655 if (format[index] == SPECIFIER_UNGROUP)
1656 index++;
1657 if (format[index] == QUALIFIER_MINUS)
1658 index++;
1659 /* Skip nested brackets */
1660 while (format[index] != NIL)
1661 {
1662 if (format[index] == SPECIFIER_GROUP)
1663 {
1664 depth++;
1665 }
1666 else if (format[index] == SPECIFIER_UNGROUP)
1667 {
1668 if (--depth <= 0)
1669 {
1670 index++;
1671 break;
1672 }
1673 }
1674 index++;
1675 }
1676 }
1677 break;
1678
1679 case SPECIFIER_INTEGER:
1680 parameters[pos].type = FORMAT_INT;
1681 break;
1682
1683 case SPECIFIER_UNSIGNED:
1684 flags |= FLAGS_UNSIGNED;
1685 parameters[pos].type = FORMAT_INT;
1686 break;
1687
1688 case SPECIFIER_DECIMAL:
1689 /* Disable base modifier */
1690 flags &= ~FLAGS_BASE_PARAMETER;
1691 base = BASE_DECIMAL;
1692 parameters[pos].type = FORMAT_INT;
1693 break;
1694
1695 case SPECIFIER_OCTAL:
1696 flags |= FLAGS_UNSIGNED;
1697 flags &= ~FLAGS_BASE_PARAMETER;
1698 base = BASE_OCTAL;
1699 parameters[pos].type = FORMAT_INT;
1700 break;
1701
1702 #if defined(SPECIFIER_BINARY)
1703 case SPECIFIER_BINARY_UPPER:
1704 flags |= FLAGS_UPPER;
1705 /* FALLTHROUGH */
1706 case SPECIFIER_BINARY:
1707 flags |= FLAGS_NILPADDING;
1708 flags &= ~FLAGS_BASE_PARAMETER;
1709 base = BASE_BINARY;
1710 parameters[pos].type = FORMAT_INT;
1711 break;
1712 #endif
1713
1714 case SPECIFIER_HEX_UPPER:
1715 flags |= FLAGS_UPPER;
1716 /* FALLTHROUGH */
1717 case SPECIFIER_HEX:
1718 flags |= FLAGS_UNSIGNED;
1719 flags &= ~FLAGS_BASE_PARAMETER;
1720 base = BASE_HEX;
1721 parameters[pos].type = FORMAT_INT;
1722 break;
1723
1724 case SPECIFIER_FLOAT_E_UPPER:
1725 flags |= FLAGS_UPPER;
1726 /* FALLTHROUGH */
1727 case SPECIFIER_FLOAT_E:
1728 flags |= FLAGS_FLOAT_E;
1729 parameters[pos].type = FORMAT_DOUBLE;
1730 break;
1731
1732 case SPECIFIER_FLOAT_G_UPPER:
1733 flags |= FLAGS_UPPER;
1734 /* FALLTHROUGH */
1735 case SPECIFIER_FLOAT_G:
1736 flags |= FLAGS_FLOAT_G;
1737 parameters[pos].type = FORMAT_DOUBLE;
1738 break;
1739
1740 case SPECIFIER_FLOAT_F_UPPER:
1741 flags |= FLAGS_UPPER;
1742 /* FALLTHROUGH */
1743 case SPECIFIER_FLOAT_F:
1744 parameters[pos].type = FORMAT_DOUBLE;
1745 break;
1746
1747 case SPECIFIER_POINTER:
1748 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1749 flags |= FLAGS_QUAD;
1750 else if (sizeof(trio_pointer_t) == sizeof(long))
1751 flags |= FLAGS_LONG;
1752 parameters[pos].type = FORMAT_POINTER;
1753 break;
1754
1755 case SPECIFIER_COUNT:
1756 parameters[pos].type = FORMAT_COUNT;
1757 break;
1758
1759 #if defined(SPECIFIER_HEXFLOAT)
1760 # if defined(SPECIFIER_HEXFLOAT_UPPER)
1761 case SPECIFIER_HEXFLOAT_UPPER:
1762 flags |= FLAGS_UPPER;
1763 /* FALLTHROUGH */
1764 # endif
1765 case SPECIFIER_HEXFLOAT:
1766 base = BASE_HEX;
1767 parameters[pos].type = FORMAT_DOUBLE;
1768 break;
1769 #endif
1770
1771 #if defined(FORMAT_ERRNO)
1772 case SPECIFIER_ERRNO:
1773 parameters[pos].type = FORMAT_ERRNO;
1774 break;
1775 #endif
1776
1777 #if defined(SPECIFIER_USER_DEFINED_BEGIN)
1778 case SPECIFIER_USER_DEFINED_BEGIN:
1779 {
1780 unsigned int max;
1781 int without_namespace = TRUE;
1782
1783 parameters[pos].type = FORMAT_USER_DEFINED;
1784 parameters[pos].user_name[0] = NIL;
1785 tmpformat = (char *)&format[index];
1786
1787 while ((ch = format[index]))
1788 {
1789 index++;
1790 if (ch == SPECIFIER_USER_DEFINED_END)
1791 {
1792 if (without_namespace)
1793 {
1794 /* We must get the handle first */
1795 parameters[pos].type = FORMAT_PARAMETER;
1796 parameters[pos].indexAfterSpecifier = index;
1797 parameters[pos].flags = FLAGS_USER_DEFINED;
1798 /* Adjust parameters for insertion of new one */
1799 pos++;
1800 usedEntries[currentParam] += 1;
1801 parameters[pos].type = FORMAT_USER_DEFINED;
1802 currentParam++;
1803 indices[currentParam] = pos;
1804 if (currentParam > maxParam)
1805 maxParam = currentParam;
1806 }
1807 /* Copy the user data */
1808 max = (unsigned int)(&format[index] - tmpformat);
1809 if (max > MAX_USER_DATA)
1810 max = MAX_USER_DATA;
1811 trio_copy_max(parameters[pos].user_data,
1812 max,
1813 tmpformat);
1814 break; /* while */
1815 }
1816 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
1817 {
1818 without_namespace = FALSE;
1819 /* Copy the namespace for later looking-up */
1820 max = (int)(&format[index] - tmpformat);
1821 if (max > MAX_USER_NAME)
1822 max = MAX_USER_NAME;
1823 trio_copy_max(parameters[pos].user_name,
1824 max,
1825 tmpformat);
1826 tmpformat = (char *)&format[index];
1827 }
1828 }
1829 if (ch != SPECIFIER_USER_DEFINED_END)
1830 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1831 }
1832 break;
1833 #endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1834
1835 default:
1836 /* Bail out completely to make the error more obvious */
1837 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1838 }
1839
1840 /* Count the number of times this entry has been used */
1841 usedEntries[currentParam] += 1;
1842
1843 /* Find last sticky parameters */
1844 if (gotSticky && !(flags & FLAGS_STICKY))
1845 {
1846 for (i = pos - 1; i >= 0; i--)
1847 {
1848 if (parameters[i].type == FORMAT_PARAMETER)
1849 continue;
1850 if ((parameters[i].flags & FLAGS_STICKY) &&
1851 (parameters[i].type == parameters[pos].type))
1852 {
1853 /* Do not overwrite current qualifiers */
1854 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
1855 if (width == NO_WIDTH)
1856 width = parameters[i].width;
1857 if (precision == NO_PRECISION)
1858 precision = parameters[i].precision;
1859 if (base == NO_BASE)
1860 base = parameters[i].base;
1861 break;
1862 }
1863 }
1864 }
1865
1866 parameters[pos].indexAfterSpecifier = index;
1867 parameters[pos].flags = flags;
1868 parameters[pos].width = width;
1869 parameters[pos].precision = precision;
1870 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1871 parameters[pos].varsize = varsize;
1872 pos++;
1873
1874 if (! positional)
1875 parameterPosition++;
1876
1877 } /* if identifier */
1878
1879 } /* while format characters left */
1880
1881 for (num = 0; num <= maxParam; num++)
1882 {
1883 if (usedEntries[num] != 1)
1884 {
1885 if (usedEntries[num] == 0) /* gap detected */
1886 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1887 else /* double references detected */
1888 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1889 }
1890
1891 i = indices[num];
1892
1893 /*
1894 * FORMAT_PARAMETERS are only present if they must be read,
1895 * so it makes no sense to check the ignore flag (besides,
1896 * the flags variable is not set for that particular type)
1897 */
1898 if ((parameters[i].type != FORMAT_PARAMETER) &&
1899 (parameters[i].flags & FLAGS_IGNORE))
1900 continue; /* for all arguments */
1901
1902 /*
1903 * The stack arguments are read according to ANSI C89
1904 * default argument promotions:
1905 *
1906 * char = int
1907 * short = int
1908 * unsigned char = unsigned int
1909 * unsigned short = unsigned int
1910 * float = double
1911 *
1912 * In addition to the ANSI C89 these types are read (the
1913 * default argument promotions of C99 has not been
1914 * considered yet)
1915 *
1916 * long long
1917 * long double
1918 * size_t
1919 * ptrdiff_t
1920 * intmax_t
1921 */
1922 switch (parameters[i].type)
1923 {
1924 case FORMAT_GROUP:
1925 case FORMAT_STRING:
1926 #if TRIO_WIDECHAR
1927 if (flags & FLAGS_WIDECHAR)
1928 {
1929 parameters[i].data.wstring = (argarray == NULL)
1930 ? va_arg(*arglist, trio_wchar_t *)
1931 : (trio_wchar_t *)(argarray[num]);
1932 }
1933 else
1934 #endif
1935 {
1936 parameters[i].data.string = (argarray == NULL)
1937 ? va_arg(*arglist, char *)
1938 : (char *)(argarray[num]);
1939 }
1940 break;
1941
1942 #if defined(FORMAT_USER_DEFINED)
1943 case FORMAT_USER_DEFINED:
1944 #endif
1945 case FORMAT_POINTER:
1946 case FORMAT_COUNT:
1947 case FORMAT_UNKNOWN:
1948 parameters[i].data.pointer = (argarray == NULL)
1949 ? va_arg(*arglist, trio_pointer_t )
1950 : argarray[num];
1951 break;
1952
1953 case FORMAT_CHAR:
1954 case FORMAT_INT:
1955 if (TYPE_SCAN == type)
1956 {
1957 if (argarray == NULL)
1958 parameters[i].data.pointer =
1959 (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
1960 else
1961 {
1962 if (parameters[i].type == FORMAT_CHAR)
1963 parameters[i].data.pointer =
1964 (trio_pointer_t)((char *)argarray[num]);
1965 else if (parameters[i].flags & FLAGS_SHORT)
1966 parameters[i].data.pointer =
1967 (trio_pointer_t)((short *)argarray[num]);
1968 else
1969 parameters[i].data.pointer =
1970 (trio_pointer_t)((int *)argarray[num]);
1971 }
1972 }
1973 else
1974 {
1975 #if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
1976 if (parameters[i].flags
1977 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
1978 {
1979 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1980 {
1981 /*
1982 * Variable sizes are mapped onto the fixed sizes, in
1983 * accordance with integer promotion.
1984 *
1985 * Please note that this may not be portable, as we
1986 * only guess the size, not the layout of the numbers.
1987 * For example, if int is little-endian, and long is
1988 * big-endian, then this will fail.
1989 */
1990 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1991 }
1992 else
1993 {
1994 /* Used for the I<bits> modifiers */
1995 varsize = parameters[i].varsize;
1996 }
1997 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
1998
1999 if (varsize <= (int)sizeof(int))
2000 ;
2001 else if (varsize <= (int)sizeof(long))
2002 parameters[i].flags |= FLAGS_LONG;
2003 #if defined(QUALIFIER_INTMAX_T)
2004 else if (varsize <= (int)sizeof(trio_longlong_t))
2005 parameters[i].flags |= FLAGS_QUAD;
2006 else
2007 parameters[i].flags |= FLAGS_INTMAX_T;
2008 #else
2009 else
2010 parameters[i].flags |= FLAGS_QUAD;
2011 #endif
2012 }
2013 #endif /* defined(QUALIFIER_VARSIZE) */
2014 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2015 if (parameters[i].flags & FLAGS_SIZE_T)
2016 parameters[i].data.number.as_unsigned = (argarray == NULL)
2017 ? (trio_uintmax_t)va_arg(*arglist, size_t)
2018 : (trio_uintmax_t)(*((size_t *)argarray[num]));
2019 else
2020 #endif
2021 #if defined(QUALIFIER_PTRDIFF_T)
2022 if (parameters[i].flags & FLAGS_PTRDIFF_T)
2023 parameters[i].data.number.as_unsigned = (argarray == NULL)
2024 ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
2025 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
2026 else
2027 #endif
2028 #if defined(QUALIFIER_INTMAX_T)
2029 if (parameters[i].flags & FLAGS_INTMAX_T)
2030 parameters[i].data.number.as_unsigned = (argarray == NULL)
2031 ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
2032 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
2033 else
2034 #endif
2035 if (parameters[i].flags & FLAGS_QUAD)
2036 parameters[i].data.number.as_unsigned = (argarray == NULL)
2037 ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
2038 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
2039 else if (parameters[i].flags & FLAGS_LONG)
2040 parameters[i].data.number.as_unsigned = (argarray == NULL)
2041 ? (trio_uintmax_t)va_arg(*arglist, long)
2042 : (trio_uintmax_t)(*((long *)argarray[num]));
2043 else
2044 {
2045 if (argarray == NULL)
2046 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
2047 else
2048 {
2049 if (parameters[i].type == FORMAT_CHAR)
2050 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
2051 else if (parameters[i].flags & FLAGS_SHORT)
2052 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
2053 else
2054 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
2055 }
2056 }
2057 }
2058 break;
2059
2060 case FORMAT_PARAMETER:
2061 /*
2062 * The parameter for the user-defined specifier is a pointer,
2063 * whereas the rest (width, precision, base) uses an integer.
2064 */
2065 if (parameters[i].flags & FLAGS_USER_DEFINED)
2066 parameters[i].data.pointer = (argarray == NULL)
2067 ? va_arg(*arglist, trio_pointer_t )
2068 : argarray[num];
2069 else
2070 parameters[i].data.number.as_unsigned = (argarray == NULL)
2071 ? (trio_uintmax_t)va_arg(*arglist, int)
2072 : (trio_uintmax_t)(*((int *)argarray[num]));
2073 break;
2074
2075 case FORMAT_DOUBLE:
2076 if (TYPE_SCAN == type)
2077 {
2078 if (parameters[i].flags & FLAGS_LONGDOUBLE)
2079 parameters[i].data.longdoublePointer = (argarray == NULL)
2080 ? va_arg(*arglist, trio_long_double_t *)
2081 : (trio_long_double_t *)argarray[num];
2082 else
2083 {
2084 if (parameters[i].flags & FLAGS_LONG)
2085 parameters[i].data.doublePointer = (argarray == NULL)
2086 ? va_arg(*arglist, double *)
2087 : (double *)argarray[num];
2088 else
2089 parameters[i].data.doublePointer = (argarray == NULL)
2090 ? (double *)va_arg(*arglist, float *)
2091 : (double *)((float *)argarray[num]);
2092 }
2093 }
2094 else
2095 {
2096 if (parameters[i].flags & FLAGS_LONGDOUBLE)
2097 parameters[i].data.longdoubleNumber = (argarray == NULL)
2098 ? va_arg(*arglist, trio_long_double_t)
2099 : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
2100 else
2101 {
2102 if (argarray == NULL)
2103 parameters[i].data.longdoubleNumber =
2104 (trio_long_double_t)va_arg(*arglist, double);
2105 else
2106 {
2107 if (parameters[i].flags & FLAGS_SHORT)
2108 parameters[i].data.longdoubleNumber =
2109 (trio_long_double_t)(*((float *)argarray[num]));
2110 else
2111 parameters[i].data.longdoubleNumber =
2112 (trio_long_double_t)(*((double *)argarray[num]));
2113 }
2114 }
2115 }
2116 break;
2117
2118 #if defined(FORMAT_ERRNO)
2119 case FORMAT_ERRNO:
2120 parameters[i].data.errorNumber = save_errno;
2121 break;
2122 #endif
2123
2124 default:
2125 break;
2126 }
2127 } /* for all specifiers */
2128 return num;
2129 }
2130
2131
2132 /*************************************************************************
2133 *
2134 * FORMATTING
2135 *
2136 ************************************************************************/
2137
2138
2139 /*************************************************************************
2140 * TrioWriteNumber
2141 *
2142 * Description:
2143 * Output a number.
2144 * The complexity of this function is a result of the complexity
2145 * of the dependencies of the flags.
2146 */
2147 TRIO_PRIVATE void
2148 TrioWriteNumber
2149 TRIO_ARGS6((self, number, flags, width, precision, base),
2150 trio_class_t *self,
2151 trio_uintmax_t number,
2152 trio_flags_t flags,
2153 int width,
2154 int precision,
2155 int base)
2156 {
2157 BOOLEAN_T isNegative;
2158 BOOLEAN_T isNumberZero;
2159 BOOLEAN_T isPrecisionZero;
2160 BOOLEAN_T ignoreNumber;
2161 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
2162 char *bufferend;
2163 char *pointer;
2164 TRIO_CONST char *digits;
2165 int i;
2166 int length;
2167 char *p;
2168 int count;
2169
2170 assert(VALID(self));
2171 assert(VALID(self->OutStream));
2172 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2173
2174 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2175 if (base == NO_BASE)
2176 base = BASE_DECIMAL;
2177
2178 isNumberZero = (number == 0);
2179 isPrecisionZero = (precision == 0);
2180 ignoreNumber = (isNumberZero
2181 && isPrecisionZero
2182 && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2183
2184 if (flags & FLAGS_UNSIGNED)
2185 {
2186 isNegative = FALSE;
2187 flags &= ~FLAGS_SHOWSIGN;
2188 }
2189 else
2190 {
2191 isNegative = ((trio_intmax_t)number < 0);
2192 if (isNegative)
2193 number = -((trio_intmax_t)number);
2194 }
2195
2196 if (flags & FLAGS_QUAD)
2197 number &= (trio_ulonglong_t)-1;
2198 else if (flags & FLAGS_LONG)
2199 number &= (unsigned long)-1;
2200 else
2201 number &= (unsigned int)-1;
2202
2203 /* Build number */
2204 pointer = bufferend = &buffer[sizeof(buffer) - 1];
2205 *pointer-- = NIL;
2206 for (i = 1; i < (int)sizeof(buffer); i++)
2207 {
2208 *pointer-- = digits[number % base];
2209 number /= base;
2210 if (number == 0)
2211 break;
2212
2213 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
2214 {
2215 /*
2216 * We are building the number from the least significant
2217 * to the most significant digit, so we have to copy the
2218 * thousand separator backwards
2219 */
2220 length = internalThousandSeparatorLength;
2221 if (((int)(pointer - buffer) - length) > 0)
2222 {
2223 p = &internalThousandSeparator[length - 1];
2224 while (length-- > 0)
2225 *pointer-- = *p--;
2226 }
2227 }
2228 }
2229
2230 if (! ignoreNumber)
2231 {
2232 /* Adjust width */
2233 width -= (bufferend - pointer) - 1;
2234 }
2235
2236 /* Adjust precision */
2237 if (NO_PRECISION != precision)
2238 {
2239 precision -= (bufferend - pointer) - 1;
2240 if (precision < 0)
2241 precision = 0;
2242 flags |= FLAGS_NILPADDING;
2243 }
2244
2245 /* Calculate padding */
2246 count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2247 ? precision
2248 : 0;
2249
2250 /* Adjust width further */
2251 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2252 width--;
2253 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2254 {
2255 switch (base)
2256 {
2257 case BASE_BINARY:
2258 case BASE_HEX:
2259 width -= 2;
2260 break;
2261 case BASE_OCTAL:
2262 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2263 width--;
2264 break;
2265 default:
2266 break;
2267 }
2268 }
2269
2270 /* Output prefixes spaces if needed */
2271 if (! ((flags & FLAGS_LEFTADJUST) ||
2272 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2273 {
2274 while (width-- > count)
2275 self->OutStream(self, CHAR_ADJUST);
2276 }
2277
2278 /* width has been adjusted for signs and alternatives */
2279 if (isNegative)
2280 self->OutStream(self, '-');
2281 else if (flags & FLAGS_SHOWSIGN)
2282 self->OutStream(self, '+');
2283 else if (flags & FLAGS_SPACE)
2284 self->OutStream(self, ' ');
2285
2286 /* Prefix is not written when the value is zero */
2287 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2288 {
2289 switch (base)
2290 {
2291 case BASE_BINARY:
2292 self->OutStream(self, '0');
2293 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2294 break;
2295
2296 case BASE_OCTAL:
2297 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2298 self->OutStream(self, '0');
2299 break;
2300
2301 case BASE_HEX:
2302 self->OutStream(self, '0');
2303 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2304 break;
2305
2306 default:
2307 break;
2308 } /* switch base */
2309 }
2310
2311 /* Output prefixed zero padding if needed */
2312 if (flags & FLAGS_NILPADDING)
2313 {
2314 if (precision == NO_PRECISION)
2315 precision = width;
2316 while (precision-- > 0)
2317 {
2318 self->OutStream(self, '0');
2319 width--;
2320 }
2321 }
2322
2323 if (! ignoreNumber)
2324 {
2325 /* Output the number itself */
2326 while (*(++pointer))
2327 {
2328 self->OutStream(self, *pointer);
2329 }
2330 }
2331
2332 /* Output trailing spaces if needed */
2333 if (flags & FLAGS_LEFTADJUST)
2334 {
2335 while (width-- > 0)
2336 self->OutStream(self, CHAR_ADJUST);
2337 }
2338 }
2339
2340 /*************************************************************************
2341 * TrioWriteStringCharacter
2342 *
2343 * Description:
2344 * Output a single character of a string
2345 */
2346 TRIO_PRIVATE void
2347 TrioWriteStringCharacter
2348 TRIO_ARGS3((self, ch, flags),
2349 trio_class_t *self,
2350 int ch,
2351 trio_flags_t flags)
2352 {
2353 if (flags & FLAGS_ALTERNATIVE)
2354 {
2355 if (! isprint(ch))
2356 {
2357 /*
2358 * Non-printable characters are converted to C escapes or
2359 * \number, if no C escape exists.
2360 */
2361 self->OutStream(self, CHAR_BACKSLASH);
2362 switch (ch)
2363 {
2364 case '\007': self->OutStream(self, 'a'); break;
2365 case '\b': self->OutStream(self, 'b'); break;
2366 case '\f': self->OutStream(self, 'f'); break;
2367 case '\n': self->OutStream(self, 'n'); break;
2368 case '\r': self->OutStream(self, 'r'); break;
2369 case '\t': self->OutStream(self, 't'); break;
2370 case '\v': self->OutStream(self, 'v'); break;
2371 case '\\': self->OutStream(self, '\\'); break;
2372 default:
2373 self->OutStream(self, 'x');
2374 TrioWriteNumber(self, (trio_uintmax_t)ch,
2375 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2376 2, 2, BASE_HEX);
2377 break;
2378 }
2379 }
2380 else if (ch == CHAR_BACKSLASH)
2381 {
2382 self->OutStream(self, CHAR_BACKSLASH);
2383 self->OutStream(self, CHAR_BACKSLASH);
2384 }
2385 else
2386 {
2387 self->OutStream(self, ch);
2388 }
2389 }
2390 else
2391 {
2392 self->OutStream(self, ch);
2393 }
2394 }
2395
2396 /*************************************************************************
2397 * TrioWriteString
2398 *
2399 * Description:
2400 * Output a string
2401 */
2402 TRIO_PRIVATE void
2403 TrioWriteString
2404 TRIO_ARGS5((self, string, flags, width, precision),
2405 trio_class_t *self,
2406 TRIO_CONST char *string,
2407 trio_flags_t flags,
2408 int width,
2409 int precision)
2410 {
2411 int length;
2412 int ch;
2413
2414 assert(VALID(self));
2415 assert(VALID(self->OutStream));
2416
2417 if (string == NULL)
2418 {
2419 string = internalNullString;
2420 length = sizeof(internalNullString) - 1;
2421 /* Disable quoting for the null pointer */
2422 flags &= (~FLAGS_QUOTE);
2423 width = 0;
2424 }
2425 else
2426 {
2427 length = trio_length(string);
2428 }
2429 if ((NO_PRECISION != precision) &&
2430 (precision < length))
2431 {
2432 length = precision;
2433 }
2434 width -= length;
2435
2436 if (flags & FLAGS_QUOTE)
2437 self->OutStream(self, CHAR_QUOTE);
2438
2439 if (! (flags & FLAGS_LEFTADJUST))
2440 {
2441 while (width-- > 0)
2442 self->OutStream(self, CHAR_ADJUST);
2443 }
2444
2445 while (length-- > 0)
2446 {
2447 /* The ctype parameters must be an unsigned char (or EOF) */
2448 ch = (int)((unsigned char)(*string++));
2449 TrioWriteStringCharacter(self, ch, flags);
2450 }
2451
2452 if (flags & FLAGS_LEFTADJUST)
2453 {
2454 while (width-- > 0)
2455 self->OutStream(self, CHAR_ADJUST);
2456 }
2457 if (flags & FLAGS_QUOTE)
2458 self->OutStream(self, CHAR_QUOTE);
2459 }
2460
2461 /*************************************************************************
2462 * TrioWriteWideStringCharacter
2463 *
2464 * Description:
2465 * Output a wide string as a multi-byte sequence
2466 */
2467 #if TRIO_WIDECHAR
2468 TRIO_PRIVATE int
2469 TrioWriteWideStringCharacter
2470 TRIO_ARGS4((self, wch, flags, width),
2471 trio_class_t *self,
2472 trio_wchar_t wch,
2473 trio_flags_t flags,
2474 int width)
2475 {
2476 int size;
2477 int i;
2478 int ch;
2479 char *string;
2480 char buffer[MB_LEN_MAX + 1];
2481
2482 if (width == NO_WIDTH)
2483 width = sizeof(buffer);
2484
2485 size = wctomb(buffer, wch);
2486 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2487 return 0;
2488
2489 string = buffer;
2490 i = size;
2491 while ((width >= i) && (width-- > 0) && (i-- > 0))
2492 {
2493 /* The ctype parameters must be an unsigned char (or EOF) */
2494 ch = (int)((unsigned char)(*string++));
2495 TrioWriteStringCharacter(self, ch, flags);
2496 }
2497 return size;
2498 }
2499 #endif /* TRIO_WIDECHAR */
2500
2501 /*************************************************************************
2502 * TrioWriteWideString
2503 *
2504 * Description:
2505 * Output a wide character string as a multi-byte string
2506 */
2507 #if TRIO_WIDECHAR
2508 TRIO_PRIVATE void
2509 TrioWriteWideString
2510 TRIO_ARGS5((self, wstring, flags, width, precision),
2511 trio_class_t *self,
2512 TRIO_CONST trio_wchar_t *wstring,
2513 trio_flags_t flags,
2514 int width,
2515 int precision)
2516 {
2517 int length;
2518 int size;
2519
2520 assert(VALID(self));
2521 assert(VALID(self->OutStream));
2522
2523 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2524 (void)mblen(NULL, 0);
2525 #endif
2526
2527 if (wstring == NULL)
2528 {
2529 TrioWriteString(self, NULL, flags, width, precision);
2530 return;
2531 }
2532
2533 if (NO_PRECISION == precision)
2534 {
2535 length = INT_MAX;
2536 }
2537 else
2538 {
2539 length = precision;
2540 width -= length;
2541 }
2542
2543 if (flags & FLAGS_QUOTE)
2544 self->OutStream(self, CHAR_QUOTE);
2545
2546 if (! (flags & FLAGS_LEFTADJUST))
2547 {
2548 while (width-- > 0)
2549 self->OutStream(self, CHAR_ADJUST);
2550 }
2551
2552 while (length > 0)
2553 {
2554 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2555 if (size == 0)
2556 break; /* while */
2557 length -= size;
2558 }
2559
2560 if (flags & FLAGS_LEFTADJUST)
2561 {
2562 while (width-- > 0)
2563 self->OutStream(self, CHAR_ADJUST);
2564 }
2565 if (flags & FLAGS_QUOTE)
2566 self->OutStream(self, CHAR_QUOTE);
2567 }
2568 #endif /* TRIO_WIDECHAR */
2569
2570 /*************************************************************************
2571 * TrioWriteDouble
2572 *
2573 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2574 *
2575 * "5.2.4.2.2 paragraph #4
2576 *
2577 * The accuracy [...] is implementation defined, as is the accuracy
2578 * of the conversion between floating-point internal representations
2579 * and string representations performed by the libray routine in
2580 * <stdio.h>"
2581 */
2582 /* FIXME: handle all instances of constant long-double number (L)
2583 * and *l() math functions.
2584 */
2585 TRIO_PRIVATE void
2586 TrioWriteDouble
2587 TRIO_ARGS6((self, number, flags, width, precision, base),
2588 trio_class_t *self,
2589 trio_long_double_t number,
2590 trio_flags_t flags,
2591 int width,
2592 int precision,
2593 int base)
2594 {
2595 trio_long_double_t integerNumber;
2596 trio_long_double_t fractionNumber;
2597 trio_long_double_t workNumber;
2598 int integerDigits;
2599 int fractionDigits;
2600 int exponentDigits;
2601 int baseDigits;
2602 int integerThreshold;
2603 int fractionThreshold;
2604 int expectedWidth;
2605 int exponent = 0;
2606 unsigned int uExponent = 0;
2607 int exponentBase;
2608 trio_long_double_t dblBase;
2609 trio_long_double_t dblIntegerBase;
2610 trio_long_double_t dblFractionBase;
2611 trio_long_double_t integerAdjust;
2612 trio_long_double_t fractionAdjust;
2613 BOOLEAN_T isNegative;
2614 BOOLEAN_T isExponentNegative = FALSE;
2615 BOOLEAN_T requireTwoDigitExponent;
2616 BOOLEAN_T isHex;
2617 TRIO_CONST char *digits;
2618 char *groupingPointer;
2619 int i;
2620 int index;
2621 BOOLEAN_T hasOnlyZeroes;
2622 int zeroes = 0;
2623 register int trailingZeroes;
2624 BOOLEAN_T keepTrailingZeroes;
2625 BOOLEAN_T keepDecimalPoint;
2626 trio_long_double_t epsilon;
2627
2628 assert(VALID(self));
2629 assert(VALID(self->OutStream));
2630 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2631
2632 /* Determine sign and look for special quantities */
2633 switch (trio_fpclassify_and_signbit(number, &isNegative))
2634 {
2635 case TRIO_FP_NAN:
2636 TrioWriteString(self,
2637 (flags & FLAGS_UPPER)
2638 ? NAN_UPPER
2639 : NAN_LOWER,
2640 flags, width, precision);
2641 return;
2642
2643 case TRIO_FP_INFINITE:
2644 if (isNegative)
2645 {
2646 /* Negative infinity */
2647 TrioWriteString(self,
2648 (flags & FLAGS_UPPER)
2649 ? "-" INFINITE_UPPER
2650 : "-" INFINITE_LOWER,
2651 flags, width, precision);
2652 return;
2653 }
2654 else
2655 {
2656 /* Positive infinity */
2657 TrioWriteString(self,
2658 (flags & FLAGS_UPPER)
2659 ? INFINITE_UPPER
2660 : INFINITE_LOWER,
2661 flags, width, precision);
2662 return;
2663 }
2664
2665 default:
2666 /* Finitude */
2667 break;
2668 }
2669
2670 /* Normal numbers */
2671 if (flags & FLAGS_LONGDOUBLE)
2672 {
2673 baseDigits = (base == 10)
2674 ? LDBL_DIG
2675 : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2676 epsilon = LDBL_EPSILON;
2677 }
2678 else if (flags & FLAGS_SHORT)
2679 {
2680 baseDigits = (base == BASE_DECIMAL)
2681 ? FLT_DIG
2682 : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2683 epsilon = FLT_EPSILON;
2684 }
2685 else
2686 {
2687 baseDigits = (base == BASE_DECIMAL)
2688 ? DBL_DIG
2689 : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2690 epsilon = DBL_EPSILON;
2691 }
2692
2693 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2694 isHex = (base == BASE_HEX);
2695 if (base == NO_BASE)
2696 base = BASE_DECIMAL;
2697 dblBase = (trio_long_double_t)base;
2698 keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2699 ( (flags & FLAGS_FLOAT_G) &&
2700 !(flags & FLAGS_ALTERNATIVE) ) );
2701
2702 if (flags & FLAGS_ROUNDING)
2703 precision = baseDigits;
2704
2705 if (precision == NO_PRECISION)
2706 {
2707 if (isHex)
2708 {
2709 keepTrailingZeroes = FALSE;
2710 precision = FLT_MANT_DIG;
2711 }
2712 else
2713 {
2714 precision = FLT_DIG;
2715 }
2716 }
2717
2718 if (isNegative)
2719 number = -number;
2720
2721 if (isHex)
2722 flags |= FLAGS_FLOAT_E;
2723
2724 if (flags & FLAGS_FLOAT_G)
2725 {
2726 if (precision == 0)
2727 precision = 1;
2728
2729 if ((number < 1.0E-4) || (number > powl(base,
2730 (trio_long_double_t)precision)))
2731 {
2732 /* Use scientific notation */
2733 flags |= FLAGS_FLOAT_E;
2734 }
2735 else if (number < 1.0)
2736 {
2737 /*
2738 * Use normal notation. If the integer part of the number is
2739 * zero, then adjust the precision to include leading fractional
2740 * zeros.
2741 */
2742 workNumber = TrioLogarithm(number, base);
2743 workNumber = TRIO_FABS(workNumber);
2744 if (workNumber - floorl(workNumber) < 0.001)
2745 workNumber--;
2746 zeroes = (int)floorl(workNumber);
2747 }
2748 }
2749
2750 if (flags & FLAGS_FLOAT_E)
2751 {
2752 /* Scale the number */
2753 workNumber = TrioLogarithm(number, base);
2754 if (trio_isinf(workNumber) == -1)
2755 {
2756 exponent = 0;
2757 /* Undo setting */
2758 if (flags & FLAGS_FLOAT_G)
2759 flags &= ~FLAGS_FLOAT_E;
2760 }
2761 else
2762 {
2763 exponent = (int)floorl(workNumber);
2764 number /= powl(dblBase, (trio_long_double_t)exponent);
2765 isExponentNegative = (exponent < 0);
2766 uExponent = (isExponentNegative) ? -exponent : exponent;
2767 if (isHex)
2768 uExponent *= 4; /* log16(2) */
2769 /* No thousand separators */
2770 flags &= ~FLAGS_QUOTE;
2771 }
2772 }
2773
2774 integerNumber = floorl(number);
2775 fractionNumber = number - integerNumber;
2776
2777 /*
2778 * Truncated number.
2779 *
2780 * Precision is number of significant digits for FLOAT_G
2781 * and number of fractional digits for others.
2782 */
2783 integerDigits = (integerNumber > epsilon)
2784 ? 1 + (int)TrioLogarithm(integerNumber, base)
2785 : 1;
2786 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
2787 ? precision - integerDigits
2788 : zeroes + precision;
2789
2790 dblFractionBase = TrioPower(base, fractionDigits);
2791
2792 workNumber = number + 0.5 / dblFractionBase;
2793 if (floorl(number) != floorl(workNumber))
2794 {
2795 if (flags & FLAGS_FLOAT_E)
2796 {
2797 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2798 exponent++;
2799 isExponentNegative = (exponent < 0);
2800 uExponent = (isExponentNegative) ? -exponent : exponent;
2801 if (isHex)
2802 uExponent *= 4; /* log16(2) */
2803 workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2804 integerNumber = floorl(workNumber);
2805 fractionNumber = workNumber - integerNumber;
2806 }
2807 else
2808 {
2809 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2810 integerNumber = floorl(number + 0.5);
2811 fractionNumber = 0.0;
2812 integerDigits = (integerNumber > epsilon)
2813 ? 1 + (int)TrioLogarithm(integerNumber, base)
2814 : 1;
2815 }
2816 }
2817
2818 /* Estimate accuracy */
2819 integerAdjust = fractionAdjust = 0.5;
2820 if (flags & FLAGS_ROUNDING)
2821 {
2822 if (integerDigits > baseDigits)
2823 {
2824 integerThreshold = baseDigits;
2825 fractionDigits = 0;
2826 dblFractionBase = 1.0;
2827 fractionThreshold = 0;
2828 precision = 0; /* Disable decimal-point */
2829 integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2830 fractionAdjust = 0.0;
2831 }
2832 else
2833 {
2834 integerThreshold = integerDigits;
2835 fractionThreshold = fractionDigits - integerThreshold;
2836 fractionAdjust = 1.0;
2837 }
2838 }
2839 else
2840 {
2841 integerThreshold = INT_MAX;
2842 fractionThreshold = INT_MAX;
2843 }
2844
2845 /*
2846 * Calculate expected width.
2847 * sign + integer part + thousands separators + decimal point
2848 * + fraction + exponent
2849 */
2850 fractionAdjust /= dblFractionBase;
2851 hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2852 keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2853 !((precision == 0) ||
2854 (!keepTrailingZeroes && hasOnlyZeroes)) );
2855 if (flags & FLAGS_FLOAT_E)
2856 {
2857 exponentDigits = (uExponent == 0)
2858 ? 1
2859 : (int)ceil(TrioLogarithm((double)(uExponent + 1),
2860 (isHex) ? 10.0 : base));
2861 }
2862 else
2863 exponentDigits = 0;
2864 requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2865
2866 expectedWidth = integerDigits + fractionDigits
2867 + (keepDecimalPoint
2868 ? internalDecimalPointLength
2869 : 0)
2870 + ((flags & FLAGS_QUOTE)
2871 ? TrioCalcThousandSeparatorLength(integerDigits)
2872 : 0);
2873 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2874 expectedWidth += sizeof("-") - 1;
2875 if (exponentDigits > 0)
2876 expectedWidth += exponentDigits +
2877 ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
2878 if (isHex)
2879 expectedWidth += sizeof("0X") - 1;
2880
2881 /* Output prefixing */
2882 if (flags & FLAGS_NILPADDING)
2883 {
2884 /* Leading zeros must be after sign */
2885 if (isNegative)
2886 self->OutStream(self, '-');
2887 else if (flags & FLAGS_SHOWSIGN)
2888 self->OutStream(self, '+');
2889 else if (flags & FLAGS_SPACE)
2890 self->OutStream(self, ' ');
2891 if (isHex)
2892 {
2893 self->OutStream(self, '0');
2894 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2895 }
2896 if (!(flags & FLAGS_LEFTADJUST))
2897 {
2898 for (i = expectedWidth; i < width; i++)
2899 {
2900 self->OutStream(self, '0');
2901 }
2902 }
2903 }
2904 else
2905 {
2906 /* Leading spaces must be before sign */
2907 if (!(flags & FLAGS_LEFTADJUST))
2908 {
2909 for (i = expectedWidth; i < width; i++)
2910 {
2911 self->OutStream(self, CHAR_ADJUST);
2912 }
2913 }
2914 if (isNegative)
2915 self->OutStream(self, '-');
2916 else if (flags & FLAGS_SHOWSIGN)
2917 self->OutStream(self, '+');
2918 else if (flags & FLAGS_SPACE)
2919 self->OutStream(self, ' ');
2920 if (isHex)
2921 {
2922 self->OutStream(self, '0');
2923 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2924 }
2925 }
2926
2927 /* Output the integer part and thousand separators */
2928 dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2929 for (i = 0; i < integerDigits; i++)
2930 {
2931 workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2932 if (i > integerThreshold)
2933 {
2934 /* Beyond accuracy */
2935 self->OutStream(self, digits[0]);
2936 }
2937 else
2938 {
2939 self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2940 }
2941 dblIntegerBase *= dblBase;
2942
2943 if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2944 && TrioFollowedBySeparator(integerDigits - i))
2945 {
2946 for (groupingPointer = internalThousandSeparator;
2947 *groupingPointer != NIL;
2948 groupingPointer++)
2949 {
2950 self->OutStream(self, *groupingPointer);
2951 }
2952 }
2953 }
2954
2955 /* Insert decimal point and build the fraction part */
2956 trailingZeroes = 0;
2957
2958 if (keepDecimalPoint)
2959 {
2960 if (internalDecimalPoint)
2961 {
2962 self->OutStream(self, internalDecimalPoint);
2963 }
2964 else
2965 {
2966 for (i = 0; i < internalDecimalPointLength; i++)
2967 {
2968 self->OutStream(self, internalDecimalPointString[i]);
2969 }
2970 }
2971 }
2972
2973 for (i = 0; i < fractionDigits; i++)
2974 {
2975 if ((integerDigits > integerThreshold) || (i > fractionThreshold))
2976 {
2977 /* Beyond accuracy */
2978 trailingZeroes++;
2979 }
2980 else
2981 {
2982 fractionNumber *= dblBase;
2983 fractionAdjust *= dblBase;
2984 workNumber = floorl(fractionNumber + fractionAdjust);
2985 fractionNumber -= workNumber;
2986 index = (int)fmodl(workNumber, dblBase);
2987 if (index == 0)
2988 {
2989 trailingZeroes++;
2990 }
2991 else
2992 {
2993 while (trailingZeroes > 0)
2994 {
2995 /* Not trailing zeroes after all */
2996 self->OutStream(self, digits[0]);
2997 trailingZeroes--;
2998 }
2999 self->OutStream(self, digits[index]);
3000 }
3001 }
3002 }
3003
3004 if (keepTrailingZeroes)
3005 {
3006 while (trailingZeroes > 0)
3007 {
3008 self->OutStream(self, digits[0]);
3009 trailingZeroes--;
3010 }
3011 }
3012
3013 /* Output exponent */
3014 if (exponentDigits > 0)
3015 {
3016 self->OutStream(self,
3017 isHex
3018 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3019 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3020 self->OutStream(self, (isExponentNegative) ? '-' : '+');
3021
3022 /* The exponent must contain at least two digits */
3023 if (requireTwoDigitExponent)
3024 self->OutStream(self, '0');
3025
3026 if (isHex)
3027 base = 10.0;
3028 exponentBase = (int)TrioPower(base, exponentDigits - 1);
3029 for (i = 0; i < exponentDigits; i++)
3030 {
3031 self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3032 exponentBase /= base;
3033 }
3034 }
3035 /* Output trailing spaces */
3036 if (flags & FLAGS_LEFTADJUST)
3037 {
3038 for (i = expectedWidth; i < width; i++)
3039 {
3040 self->OutStream(self, CHAR_ADJUST);
3041 }
3042 }
3043 }
3044
3045 /*************************************************************************
3046 * TrioFormatProcess
3047 *
3048 * Description:
3049 * This is the main engine for formatting output
3050 */
3051 TRIO_PRIVATE int
3052 TrioFormatProcess
3053 TRIO_ARGS3((data, format, parameters),
3054 trio_class_t *data,
3055 TRIO_CONST char *format,
3056 trio_parameter_t *parameters)
3057 {
3058 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3059 int charlen;
3060 #endif
3061 int i;
3062 TRIO_CONST char *string;
3063 trio_pointer_t pointer;
3064 trio_flags_t flags;
3065 int width;
3066 int precision;
3067 int base;
3068 int index;
3069
3070 index = 0;
3071 i = 0;
3072 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3073 (void)mblen(NULL, 0);
3074 #endif
3075
3076 while (format[index])
3077 {
3078 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3079 if (! isascii(format[index]))
3080 {
3081 charlen = mblen(&format[index], MB_LEN_MAX);
3082 /*
3083 * Only valid multibyte characters are handled here. Invalid
3084 * multibyte characters (charlen == -1) are handled as normal
3085 * characters.
3086 */
3087 if (charlen != -1)
3088 {
3089 while (charlen-- > 0)
3090 {
3091 data->OutStream(data, format[index++]);
3092 }
3093 continue; /* while characters left in formatting string */
3094 }
3095 }
3096 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
3097 if (CHAR_IDENTIFIER == format[index])
3098 {
3099 if (CHAR_IDENTIFIER == format[index + 1])
3100 {
3101 data->OutStream(data, CHAR_IDENTIFIER);
3102 index += 2;
3103 }
3104 else
3105 {
3106 /* Skip the parameter entries */
3107 while (parameters[i].type == FORMAT_PARAMETER)
3108 i++;
3109
3110 flags = parameters[i].flags;
3111
3112 /* Find width */
3113 width = parameters[i].width;
3114 if (flags & FLAGS_WIDTH_PARAMETER)
3115 {
3116 /* Get width from parameter list */
3117 width = (int)parameters[width].data.number.as_signed;
3118 if (width < 0)
3119 {
3120 /*
3121 * A negative width is the same as the - flag and
3122 * a positive width.
3123 */
3124 flags |= FLAGS_LEFTADJUST;
3125 flags &= ~FLAGS_NILPADDING;
3126 width = -width;
3127 }
3128 }
3129
3130 /* Find precision */
3131 if (flags & FLAGS_PRECISION)
3132 {
3133 precision = parameters[i].precision;
3134 if (flags & FLAGS_PRECISION_PARAMETER)
3135 {
3136 /* Get precision from parameter list */
3137 precision = (int)parameters[precision].data.number.as_signed;
3138 if (precision < 0)
3139 {
3140 /*
3141 * A negative precision is the same as no
3142 * precision
3143 */
3144 precision = NO_PRECISION;
3145 }
3146 }
3147 }
3148 else
3149 {
3150 precision = NO_PRECISION;
3151 }
3152
3153 /* Find base */
3154 base = parameters[i].base;
3155 if (flags & FLAGS_BASE_PARAMETER)
3156 {
3157 /* Get base from parameter list */
3158 base = (int)parameters[base].data.number.as_signed;
3159 }
3160
3161 switch (parameters[i].type)
3162 {
3163 case FORMAT_CHAR:
3164 if (flags & FLAGS_QUOTE)
3165 data->OutStream(data, CHAR_QUOTE);
3166 if (! (flags & FLAGS_LEFTADJUST))
3167 {
3168 while (--width > 0)
3169 data->OutStream(data, CHAR_ADJUST);
3170 }
3171 #if TRIO_WIDECHAR
3172 if (flags & FLAGS_WIDECHAR)
3173 {
3174 TrioWriteWideStringCharacter(data,
3175 (trio_wchar_t)parameters[i].data.number.as_signed,
3176 flags,
3177 NO_WIDTH);
3178 }
3179 else
3180 #endif
3181 {
3182 TrioWriteStringCharacter(data,
3183 (int)parameters[i].data.number.as_signed,
3184 flags);
3185 }
3186
3187 if (flags & FLAGS_LEFTADJUST)
3188 {
3189 while(--width > 0)
3190 data->OutStream(data, CHAR_ADJUST);
3191 }
3192 if (flags & FLAGS_QUOTE)
3193 data->OutStream(data, CHAR_QUOTE);
3194
3195 break; /* FORMAT_CHAR */
3196
3197 case FORMAT_INT:
3198 TrioWriteNumber(data,
3199 parameters[i].data.number.as_unsigned,
3200 flags,
3201 width,
3202 precision,
3203 base);
3204
3205 break; /* FORMAT_INT */
3206
3207 case FORMAT_DOUBLE:
3208 TrioWriteDouble(data,
3209 parameters[i].data.longdoubleNumber,
3210 flags,
3211 width,
3212 precision,
3213 base);
3214 break; /* FORMAT_DOUBLE */
3215
3216 case FORMAT_STRING:
3217 #if TRIO_WIDECHAR
3218 if (flags & FLAGS_WIDECHAR)
3219 {
3220 TrioWriteWideString(data,
3221 parameters[i].data.wstring,
3222 flags,
3223 width,
3224 precision);
3225 }
3226 else
3227 #endif
3228 {
3229 TrioWriteString(data,
3230 parameters[i].data.string,
3231 flags,
3232 width,
3233 precision);
3234 }
3235 break; /* FORMAT_STRING */
3236
3237 case FORMAT_POINTER:
3238 {
3239 trio_reference_t reference;
3240
3241 reference.data = data;
3242 reference.parameter = ¶meters[i];
3243 trio_print_pointer(&reference, parameters[i].data.pointer);
3244 }
3245 break; /* FORMAT_POINTER */
3246
3247 case FORMAT_COUNT:
3248 pointer = parameters[i].data.pointer;
3249 if (NULL != pointer)
3250 {
3251 /*
3252 * C99 paragraph 7.19.6.1.8 says "the number of
3253 * characters written to the output stream so far by
3254 * this call", which is data->committed
3255 */
3256 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3257 if (flags & FLAGS_SIZE_T)
3258 *(size_t *)pointer = (size_t)data->committed;
3259 else
3260 #endif
3261 #if defined(QUALIFIER_PTRDIFF_T)
3262 if (flags & FLAGS_PTRDIFF_T)
3263 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3264 else
3265 #endif
3266 #if defined(QUALIFIER_INTMAX_T)
3267 if (flags & FLAGS_INTMAX_T)
3268 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
3269 else
3270 #endif
3271 if (flags & FLAGS_QUAD)
3272 {
3273 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
3274 }
3275 else if (flags & FLAGS_LONG)
3276 {
3277 *(long int *)pointer = (long int)data->committed;
3278 }
3279 else if (flags & FLAGS_SHORT)
3280 {
3281 *(short int *)pointer = (short int)data->committed;
3282 }
3283 else
3284 {
3285 *(int *)pointer = (int)data->committed;
3286 }
3287 }
3288 break; /* FORMAT_COUNT */
3289
3290 case FORMAT_PARAMETER:
3291 break; /* FORMAT_PARAMETER */
3292
3293 #if defined(FORMAT_ERRNO)
3294 case FORMAT_ERRNO:
3295 string = trio_error(parameters[i].data.errorNumber);
3296 if (string)
3297 {
3298 TrioWriteString(data,
3299 string,
3300 flags,
3301 width,
3302 precision);
3303 }
3304 else
3305 {
3306 data->OutStream(data, '#');
3307 TrioWriteNumber(data,
3308 (trio_uintmax_t)parameters[i].data.errorNumber,
3309 flags,
3310 width,
3311 precision,
3312 BASE_DECIMAL);
3313 }
3314 break; /* FORMAT_ERRNO */
3315 #endif /* defined(FORMAT_ERRNO) */
3316
3317 #if defined(FORMAT_USER_DEFINED)
3318 case FORMAT_USER_DEFINED:
3319 {
3320 trio_reference_t reference;
3321 trio_userdef_t *def = NULL;
3322
3323 if (parameters[i].user_name[0] == NIL)
3324 {
3325 /* Use handle */
3326 if ((i > 0) ||
3327 (parameters[i - 1].type == FORMAT_PARAMETER))
3328 def = (trio_userdef_t *)parameters[i - 1].data.pointer;
3329 }
3330 else
3331 {
3332 /* Look up namespace */
3333 def = TrioFindNamespace(parameters[i].user_name, NULL);
3334 }
3335 if (def) {
3336 reference.data = data;
3337 reference.parameter = ¶meters[i];
3338 def->callback(&reference);
3339 }
3340 }
3341 break;
3342 #endif /* defined(FORMAT_USER_DEFINED) */
3343
3344 default:
3345 break;
3346 } /* switch parameter type */
3347
3348 /* Prepare for next */
3349 index = parameters[i].indexAfterSpecifier;
3350 i++;
3351 }
3352 }
3353 else /* not identifier */
3354 {
3355 data->OutStream(data, format[index++]);
3356 }
3357 }
3358 return data->processed;
3359 }
3360
3361 /*************************************************************************
3362 * TrioFormatRef
3363 */
3364 TRIO_PRIVATE int
3365 TrioFormatRef
3366 TRIO_ARGS4((reference, format, arglist, argarray),
3367 trio_reference_t *reference,
3368 TRIO_CONST char *format,
3369 va_list *arglist,
3370 trio_pointer_t *argarray)
3371 {
3372 int status;
3373 trio_parameter_t parameters[MAX_PARAMETERS];
3374
3375 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3376 if (status < 0)
3377 return status;
3378
3379 status = TrioFormatProcess(reference->data, format, parameters);
3380 if (reference->data->error != 0)
3381 {
3382 status = reference->data->error;
3383 }
3384 return status;
3385 }
3386
3387 /*************************************************************************
3388 * TrioFormat
3389 */
3390 TRIO_PRIVATE int
3391 TrioFormat
3392 TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3393 trio_pointer_t destination,
3394 size_t destinationSize,
3395 void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
3396 TRIO_CONST char *format,
3397 va_list *arglist,
3398 trio_pointer_t *argarray)
3399 {
3400 int status;
3401 trio_class_t data;
3402 trio_parameter_t parameters[MAX_PARAMETERS];
3403
3404 assert(VALID(OutStream));
3405 assert(VALID(format));
3406
3407 memset(&data, 0, sizeof(data));
3408 data.OutStream = OutStream;
3409 data.location = destination;
3410 data.max = destinationSize;
3411 data.error = 0;
3412
3413 #if defined(USE_LOCALE)
3414 if (NULL == internalLocaleValues)
3415 {
3416 TrioSetLocale();
3417 }
3418 #endif
3419
3420 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3421 if (status < 0)
3422 return status;
3423
3424 status = TrioFormatProcess(&data, format, parameters);
3425 if (data.error != 0)
3426 {
3427 status = data.error;
3428 }
3429 return status;
3430 }
3431
3432 /*************************************************************************
3433 * TrioOutStreamFile
3434 */
3435 TRIO_PRIVATE void
3436 TrioOutStreamFile
3437 TRIO_ARGS2((self, output),
3438 trio_class_t *self,
3439 int output)
3440 {
3441 FILE *file;
3442
3443 assert(VALID(self));
3444 assert(VALID(self->location));
3445
3446 file = (FILE *)self->location;
3447 self->processed++;
3448 if (fputc(output, file) == EOF)
3449 {
3450 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3451 }
3452 else
3453 {
3454 self->committed++;
3455 }
3456 }
3457
3458 /*************************************************************************
3459 * TrioOutStreamFileDescriptor
3460 */
3461 TRIO_PRIVATE void
3462 TrioOutStreamFileDescriptor
3463 TRIO_ARGS2((self, output),
3464 trio_class_t *self,
3465 int output)
3466 {
3467 int fd;
3468 char ch;
3469
3470 assert(VALID(self));
3471
3472 fd = *((int *)self->location);
3473 ch = (char)output;
3474 self->processed++;
3475 if (write(fd, &ch, sizeof(char)) == -1)
3476 {
3477 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3478 }
3479 else
3480 {
3481 self->committed++;
3482 }
3483 }
3484
3485 /*************************************************************************
3486 * TrioOutStreamCustom
3487 */
3488 TRIO_PRIVATE void
3489 TrioOutStreamCustom
3490 TRIO_ARGS2((self, output),
3491 trio_class_t *self,
3492 int output)
3493 {
3494 int status;
3495 trio_custom_t *data;
3496
3497 assert(VALID(self));
3498 assert(VALID(self->location));
3499
3500 data = (trio_custom_t *)self->location;
3501 if (data->stream.out)
3502 {
3503 status = (data->stream.out)(data->closure, output);
3504 if (status >= 0)
3505 {
3506 self->committed++;
3507 }
3508 else
3509 {
3510 if (self->error == 0)
3511 {
3512 self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3513 }
3514 }
3515 }
3516 self->processed++;
3517 }
3518
3519 /*************************************************************************
3520 * TrioOutStreamString
3521 */
3522 TRIO_PRIVATE void
3523 TrioOutStreamString
3524 TRIO_ARGS2((self, output),
3525 trio_class_t *self,
3526 int output)
3527 {
3528 char **buffer;
3529
3530 assert(VALID(self));
3531 assert(VALID(self->location));
3532
3533 buffer = (char **)self->location;
3534 **buffer = (char)output;
3535 (*buffer)++;
3536 self->processed++;
3537 self->committed++;
3538 }
3539
3540 /*************************************************************************
3541 * TrioOutStreamStringMax
3542 */
3543 TRIO_PRIVATE void
3544 TrioOutStreamStringMax
3545 TRIO_ARGS2((self, output),
3546 trio_class_t *self,
3547 int output)
3548 {
3549 char **buffer;
3550
3551 assert(VALID(self));
3552 assert(VALID(self->location));
3553
3554 buffer = (char **)self->location;
3555
3556 if (self->processed < self->max)
3557 {
3558 **buffer = (char)output;
3559 (*buffer)++;
3560 self->committed++;
3561 }
3562 self->processed++;
3563 }
3564
3565 /*************************************************************************
3566 * TrioOutStreamStringDynamic
3567 */
3568 TRIO_PRIVATE void
3569 TrioOutStreamStringDynamic
3570 TRIO_ARGS2((self, output),
3571 trio_class_t *self,
3572 int output)
3573 {
3574 assert(VALID(self));
3575 assert(VALID(self->location));
3576
3577 if (self->error == 0)
3578 {
3579 trio_xstring_append_char((trio_string_t *)self->location,
3580 (char)output);
3581 self->committed++;
3582 }
3583 /* The processed variable must always be increased */
3584 self->processed++;
3585 }
3586
3587 /*************************************************************************
3588 *
3589 * Formatted printing functions
3590 *
3591 ************************************************************************/
3592
3593 #if defined(TRIO_DOCUMENTATION)
3594 # include "doc/doc_printf.h"
3595 #endif
3596 /** @addtogroup Printf
3597 @{
3598 */
3599
3600 /*************************************************************************
3601 * printf
3602 */
3603
3604 /**
3605 Print to standard output stream.
3606
3607 @param format Formatting string.
3608 @param ... Arguments.
3609 @return Number of printed characters.
3610 */
3611 TRIO_PUBLIC int
3612 trio_printf
3613 TRIO_VARGS2((format, va_alist),
3614 TRIO_CONST char *format,
3615 TRIO_VA_DECL)
3616 {
3617 int status;
3618 va_list args;
3619
3620 assert(VALID(format));
3621
3622 TRIO_VA_START(args, format);
3623 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3624 TRIO_VA_END(args);
3625 return status;
3626 }
3627
3628 /**
3629 Print to standard output stream.
3630
3631 @param format Formatting string.
3632 @param args Arguments.
3633 @return Number of printed characters.
3634 */
3635 TRIO_PUBLIC int
3636 trio_vprintf
3637 TRIO_ARGS2((format, args),
3638 TRIO_CONST char *format,
3639 va_list args)
3640 {
3641 assert(VALID(format));
3642
3643 return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
3644 }
3645
3646 /**
3647 Print to standard output stream.
3648
3649 @param format Formatting string.
3650 @param args Arguments.
3651 @return Number of printed characters.
3652 */
3653 TRIO_PUBLIC int
3654 trio_printfv
3655 TRIO_ARGS2((format, args),
3656 TRIO_CONST char *format,
3657 trio_pointer_t * args)
3658 {
3659 assert(VALID(format));
3660
3661 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
3662 }
3663
3664 /*************************************************************************
3665 * fprintf
3666 */
3667
3668 /**
3669 Print to file.
3670
3671 @param file File pointer.
3672 @param format Formatting string.
3673 @param ... Arguments.
3674 @return Number of printed characters.
3675 */
3676 TRIO_PUBLIC int
3677 trio_fprintf
3678 TRIO_VARGS3((file, format, va_alist),
3679 FILE *file,
3680 TRIO_CONST char *format,
3681 TRIO_VA_DECL)
3682 {
3683 int status;
3684 va_list args;
3685
3686 assert(VALID(file));
3687 assert(VALID(format));
3688
3689 TRIO_VA_START(args, format);
3690 status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3691 TRIO_VA_END(args);
3692 return status;
3693 }
3694
3695 /**
3696 Print to file.
3697
3698 @param file File pointer.
3699 @param format Formatting string.
3700 @param args Arguments.
3701 @return Number of printed characters.
3702 */
3703 TRIO_PUBLIC int
3704 trio_vfprintf
3705 TRIO_ARGS3((file, format, args),
3706 FILE *file,
3707 TRIO_CONST char *format,
3708 va_list args)
3709 {
3710 assert(VALID(file));
3711 assert(VALID(format));
3712
3713 return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
3714 }
3715
3716 /**
3717 Print to file.
3718
3719 @param file File pointer.
3720 @param format Formatting string.
3721 @param args Arguments.
3722 @return Number of printed characters.
3723 */
3724 TRIO_PUBLIC int
3725 trio_fprintfv
3726 TRIO_ARGS3((file, format, args),
3727 FILE *file,
3728 TRIO_CONST char *format,
3729 trio_pointer_t * args)
3730 {
3731 assert(VALID(file));
3732 assert(VALID(format));
3733
3734 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
3735 }
3736
3737 /*************************************************************************
3738 * dprintf
3739 */
3740
3741 /**
3742 Print to file descriptor.
3743
3744 @param fd File descriptor.
3745 @param format Formatting string.
3746 @param ... Arguments.
3747 @return Number of printed characters.
3748 */
3749 TRIO_PUBLIC int
3750 trio_dprintf
3751 TRIO_VARGS3((fd, format, va_alist),
3752 int fd,
3753 TRIO_CONST char *format,
3754 TRIO_VA_DECL)
3755 {
3756 int status;
3757 va_list args;
3758
3759 assert(VALID(format));
3760
3761 TRIO_VA_START(args, format);
3762 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3763 TRIO_VA_END(args);
3764 return status;
3765 }
3766
3767 /**
3768 Print to file descriptor.
3769
3770 @param fd File descriptor.
3771 @param format Formatting string.
3772 @param args Arguments.
3773 @return Number of printed characters.
3774 */
3775 TRIO_PUBLIC int
3776 trio_vdprintf
3777 TRIO_ARGS3((fd, format, args),
3778 int fd,
3779 TRIO_CONST char *format,
3780 va_list args)
3781 {
3782 assert(VALID(format));
3783
3784 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
3785 }
3786
3787 /**
3788 Print to file descriptor.
3789
3790 @param fd File descriptor.
3791 @param format Formatting string.
3792 @param args Arguments.
3793 @return Number of printed characters.
3794 */
3795 TRIO_PUBLIC int
3796 trio_dprintfv
3797 TRIO_ARGS3((fd, format, args),
3798 int fd,
3799 TRIO_CONST char *format,
3800 trio_pointer_t *args)
3801 {
3802 assert(VALID(format));
3803
3804 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3805 }
3806
3807 /*************************************************************************
3808 * cprintf
3809 */
3810 TRIO_PUBLIC int
3811 trio_cprintf
3812 TRIO_VARGS4((stream, closure, format, va_alist),
3813 trio_outstream_t stream,
3814 trio_pointer_t closure,
3815 TRIO_CONST char *format,
3816 TRIO_VA_DECL)
3817 {
3818 int status;
3819 va_list args;
3820 trio_custom_t data;
3821
3822 assert(VALID(stream));
3823 assert(VALID(format));
3824
3825 TRIO_VA_START(args, format);
3826 data.stream.out = stream;
3827 data.closure = closure;
3828 status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3829 TRIO_VA_END(args);
3830 return status;
3831 }
3832
3833 TRIO_PUBLIC int
3834 trio_vcprintf
3835 TRIO_ARGS4((stream, closure, format, args),
3836 trio_outstream_t stream,
3837 trio_pointer_t closure,
3838 TRIO_CONST char *format,
3839 va_list args)
3840 {
3841 trio_custom_t data;
3842
3843 assert(VALID(stream));
3844 assert(VALID(format));
3845
3846 data.stream.out = stream;
3847 data.closure = closure;
3848 return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
3849 }
3850
3851 TRIO_PUBLIC int
3852 trio_cprintfv
3853 TRIO_ARGS4((stream, closure, format, args),
3854 trio_outstream_t stream,
3855 trio_pointer_t closure,
3856 TRIO_CONST char *format,
3857 void **args)
3858 {
3859 trio_custom_t data;
3860
3861 assert(VALID(stream));
3862 assert(VALID(format));
3863
3864 data.stream.out = stream;
3865 data.closure = closure;
3866 return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
3867 }
3868
3869 /*************************************************************************
3870 * sprintf
3871 */
3872
3873 /**
3874 Print to string.
3875
3876 @param buffer Output string.
3877 @param format Formatting string.
3878 @param ... Arguments.
3879 @return Number of printed characters.
3880 */
3881 TRIO_PUBLIC int
3882 trio_sprintf
3883 TRIO_VARGS3((buffer, format, va_alist),
3884 char *buffer,
3885 TRIO_CONST char *format,
3886 TRIO_VA_DECL)
3887 {
3888 int status;
3889 va_list args;
3890
3891 assert(VALID(buffer));
3892 assert(VALID(format));
3893
3894 TRIO_VA_START(args, format);
3895 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
3896 *buffer = NIL; /* Terminate with NIL character */
3897 TRIO_VA_END(args);
3898 return status;
3899 }
3900
3901 /**
3902 Print to string.
3903
3904 @param buffer Output string.
3905 @param format Formatting string.
3906 @param args Arguments.
3907 @return Number of printed characters.
3908 */
3909 TRIO_PUBLIC int
3910 trio_vsprintf
3911 TRIO_ARGS3((buffer, format, args),
3912 char *buffer,
3913 TRIO_CONST char *format,
3914 va_list args)
3915 {
3916 int status;
3917
3918 assert(VALID(buffer));
3919 assert(VALID(format));
3920
3921 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
3922 *buffer = NIL;
3923 return status;
3924 }
3925
3926 /**
3927 Print to string.
3928
3929 @param buffer Output string.
3930 @param format Formatting string.
3931 @param args Arguments.
3932 @return Number of printed characters.
3933 */
3934 TRIO_PUBLIC int
3935 trio_sprintfv
3936 TRIO_ARGS3((buffer, format, args),
3937 char *buffer,
3938 TRIO_CONST char *format,
3939 trio_pointer_t *args)
3940 {
3941 int status;
3942
3943 assert(VALID(buffer));
3944 assert(VALID(format));
3945
3946 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
3947 *buffer = NIL;
3948 return status;
3949 }
3950
3951 /*************************************************************************
3952 * snprintf
3953 */
3954
3955 /**
3956 Print at most @p max characters to string.
3957
3958 @param buffer Output string.
3959 @param max Maximum number of characters to print.
3960 @param format Formatting string.
3961 @param ... Arguments.
3962 @return Number of printed characters.
3963 */
3964 TRIO_PUBLIC int
3965 trio_snprintf
3966 TRIO_VARGS4((buffer, max, format, va_alist),
3967 char *buffer,
3968 size_t max,
3969 TRIO_CONST char *format,
3970 TRIO_VA_DECL)
3971 {
3972 int status;
3973 va_list args;
3974
3975 assert(VALID(buffer));
3976 assert(VALID(format));
3977
3978 TRIO_VA_START(args, format);
3979 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
3980 TrioOutStreamStringMax, format, &args, NULL);
3981 if (max > 0)
3982 *buffer = NIL;
3983 TRIO_VA_END(args);
3984 return status;
3985 }
3986
3987 /**
3988 Print at most @p max characters to string.
3989
3990 @param buffer Output string.
3991 @param max Maximum number of characters to print.
3992 @param format Formatting string.
3993 @param args Arguments.
3994 @return Number of printed characters.
3995 */
3996 TRIO_PUBLIC int
3997 trio_vsnprintf
3998 TRIO_ARGS4((buffer, max, format, args),
3999 char *buffer,
4000 size_t max,
4001 TRIO_CONST char *format,
4002 va_list args)
4003 {
4004 int status;
4005
4006 assert(VALID(buffer));
4007 assert(VALID(format));
4008
4009 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4010 TrioOutStreamStringMax, format, &args, NULL);
4011 if (max > 0)
4012 *buffer = NIL;
4013 return status;
4014 }
4015
4016 /**
4017 Print at most @p max characters to string.
4018
4019 @param buffer Output string.
4020 @param max Maximum number of characters to print.
4021 @param format Formatting string.
4022 @param args Arguments.
4023 @return Number of printed characters.
4024 */
4025 TRIO_PUBLIC int
4026 trio_snprintfv
4027 TRIO_ARGS4((buffer, max, format, args),
4028 char *buffer,
4029 size_t max,
4030 TRIO_CONST char *format,
4031 trio_pointer_t *args)
4032 {
4033 int status;
4034
4035 assert(VALID(buffer));
4036 assert(VALID(format));
4037
4038 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4039 TrioOutStreamStringMax, format, NULL, args);
4040 if (max > 0)
4041 *buffer = NIL;
4042 return status;
4043 }
4044
4045 /*************************************************************************
4046 * snprintfcat
4047 * Appends the new string to the buffer string overwriting the '\0'
4048 * character at the end of buffer.
4049 */
4050 TRIO_PUBLIC int
4051 trio_snprintfcat
4052 TRIO_VARGS4((buffer, max, format, va_alist),
4053 char *buffer,
4054 size_t max,
4055 TRIO_CONST char *format,
4056 TRIO_VA_DECL)
4057 {
4058 int status;
4059 va_list args;
4060 size_t buf_len;
4061
4062 TRIO_VA_START(args, format);
4063
4064 assert(VALID(buffer));
4065 assert(VALID(format));
4066
4067 buf_len = trio_length(buffer);
4068 buffer = &buffer[buf_len];
4069
4070 status = TrioFormat(&buffer, max - 1 - buf_len,
4071 TrioOutStreamStringMax, format, &args, NULL);
4072 TRIO_VA_END(args);
4073 *buffer = NIL;
4074 return status;
4075 }
4076
4077 TRIO_PUBLIC int
4078 trio_vsnprintfcat
4079 TRIO_ARGS4((buffer, max, format, args),
4080 char *buffer,
4081 size_t max,
4082 TRIO_CONST char *format,
4083 va_list args)
4084 {
4085 int status;
4086 size_t buf_len;
4087
4088 assert(VALID(buffer));
4089 assert(VALID(format));
4090
4091 buf_len = trio_length(buffer);
4092 buffer = &buffer[buf_len];
4093 status = TrioFormat(&buffer, max - 1 - buf_len,
4094 TrioOutStreamStringMax, format, &args, NULL);
4095 *buffer = NIL;
4096 return status;
4097 }
4098
4099 /*************************************************************************
4100 * trio_aprintf
4101 */
4102
4103 /* Deprecated */
4104 TRIO_PUBLIC char *
4105 trio_aprintf
4106 TRIO_VARGS2((format, va_alist),
4107 TRIO_CONST char *format,
4108 TRIO_VA_DECL)
4109 {
4110 va_list args;
4111 trio_string_t *info;
4112 char *result = NULL;
4113
4114 assert(VALID(format));
4115
4116 info = trio_xstring_duplicate("");
4117 if (info)
4118 {
4119 TRIO_VA_START(args, format);
4120 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4121 format, &args, NULL);
4122 TRIO_VA_END(args);
4123
4124 trio_string_terminate(info);
4125 result = trio_string_extract(info);
4126 trio_string_destroy(info);
4127 }
4128 return result;
4129 }
4130
4131 /* Deprecated */
4132 TRIO_PUBLIC char *
4133 trio_vaprintf
4134 TRIO_ARGS2((format, args),
4135 TRIO_CONST char *format,
4136 va_list args)
4137 {
4138 trio_string_t *info;
4139 char *result = NULL;
4140
4141 assert(VALID(format));
4142
4143 info = trio_xstring_duplicate("");
4144 if (info)
4145 {
4146 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4147 format, &args, NULL);
4148 trio_string_terminate(info);
4149 result = trio_string_extract(info);
4150 trio_string_destroy(info);
4151 }
4152 return result;
4153 }
4154
4155 TRIO_PUBLIC int
4156 trio_asprintf
4157 TRIO_VARGS3((result, format, va_alist),
4158 char **result,
4159 TRIO_CONST char *format,
4160 TRIO_VA_DECL)
4161 {
4162 va_list args;
4163 int status;
4164 trio_string_t *info;
4165
4166 assert(VALID(format));
4167
4168 *result = NULL;
4169
4170 info = trio_xstring_duplicate("");
4171 if (info == NULL)
4172 {
4173 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4174 }
4175 else
4176 {
4177 TRIO_VA_START(args, format);
4178 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4179 format, &args, NULL);
4180 TRIO_VA_END(args);
4181 if (status >= 0)
4182 {
4183 trio_string_terminate(info);
4184 *result = trio_string_extract(info);
4185 }
4186 trio_string_destroy(info);
4187 }
4188 return status;
4189 }
4190
4191 TRIO_PUBLIC int
4192 trio_vasprintf
4193 TRIO_ARGS3((result, format, args),
4194 char **result,
4195 TRIO_CONST char *format,
4196 va_list args)
4197 {
4198 int status;
4199 trio_string_t *info;
4200
4201 assert(VALID(format));
4202
4203 *result = NULL;
4204
4205 info = trio_xstring_duplicate("");
4206 if (info == NULL)
4207 {
4208 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4209 }
4210 else
4211 {
4212 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4213 format, &args, NULL);
4214 if (status >= 0)
4215 {
4216 trio_string_terminate(info);
4217 *result = trio_string_extract(info);
4218 }
4219 trio_string_destroy(info);
4220 }
4221 return status;
4222 }
4223
4224 /** @} End of Printf documentation module */
4225
4226 /*************************************************************************
4227 *
4228 * CALLBACK
4229 *
4230 ************************************************************************/
4231
4232 #if defined(TRIO_DOCUMENTATION)
4233 # include "doc/doc_register.h"
4234 #endif
4235 /**
4236 @addtogroup UserDefined
4237 @{
4238 */
4239
4240 #if TRIO_EXTENSION
4241
4242 /*************************************************************************
4243 * trio_register
4244 */
4245
4246 /**
4247 Register new user-defined specifier.
4248
4249 @param callback
4250 @param name
4251 @return Handle.
4252 */
4253 TRIO_PUBLIC trio_pointer_t
4254 trio_register
4255 TRIO_ARGS2((callback, name),
4256 trio_callback_t callback,
4257 TRIO_CONST char *name)
4258 {
4259 trio_userdef_t *def;
4260 trio_userdef_t *prev = NULL;
4261
4262 if (callback == NULL)
4263 return NULL;
4264
4265 if (name)
4266 {
4267 /* Handle built-in namespaces */
4268 if (name[0] == ':')
4269 {
4270 if (trio_equal(name, ":enter"))
4271 {
4272 internalEnterCriticalRegion = callback;
4273 }
4274 else if (trio_equal(name, ":leave"))
4275 {
4276 internalLeaveCriticalRegion = callback;
4277 }
4278 return NULL;
4279 }
4280
4281 /* Bail out if namespace is too long */
4282 if (trio_length(name) >= MAX_USER_NAME)
4283 return NULL;
4284
4285 /* Bail out if namespace already is registered */
4286 def = TrioFindNamespace(name, &prev);
4287 if (def)
4288 return NULL;
4289 }
4290
4291 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
4292 if (def)
4293 {
4294 if (internalEnterCriticalRegion)
4295 (void)internalEnterCriticalRegion(NULL);
4296
4297 if (name)
4298 {
4299 /* Link into internal list */
4300 if (prev == NULL)
4301 internalUserDef = def;
4302 else
4303 prev->next = def;
4304 }
4305 /* Initialize */
4306 def->callback = callback;
4307 def->name = (name == NULL)
4308 ? NULL
4309 : trio_duplicate(name);
4310 def->next = NULL;
4311
4312 if (internalLeaveCriticalRegion)
4313 (void)internalLeaveCriticalRegion(NULL);
4314 }
4315 return (trio_pointer_t)def;
4316 }
4317
4318 /**
4319 Unregister an existing user-defined specifier.
4320
4321 @param handle
4322 */
4323 void
4324 trio_unregister
4325 TRIO_ARGS1((handle),
4326 trio_pointer_t handle)
4327 {
4328 trio_userdef_t *self = (trio_userdef_t *)handle;
4329 trio_userdef_t *def;
4330 trio_userdef_t *prev = NULL;
4331
4332 assert(VALID(self));
4333
4334 if (self->name)
4335 {
4336 def = TrioFindNamespace(self->name, &prev);
4337 if (def)
4338 {
4339 if (internalEnterCriticalRegion)
4340 (void)internalEnterCriticalRegion(NULL);
4341
4342 if (prev == NULL)
4343 internalUserDef = NULL;
4344 else
4345 prev->next = def->next;
4346
4347 if (internalLeaveCriticalRegion)
4348 (void)internalLeaveCriticalRegion(NULL);
4349 }
4350 trio_destroy(self->name);
4351 }
4352 TRIO_FREE(self);
4353 }
4354
4355 /*************************************************************************
4356 * trio_get_format [public]
4357 */
4358 TRIO_CONST char *
4359 trio_get_format
4360 TRIO_ARGS1((ref),
4361 trio_pointer_t ref)
4362 {
4363 #if defined(FORMAT_USER_DEFINED)
4364 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4365 #endif
4366
4367 return (((trio_reference_t *)ref)->parameter->user_data);
4368 }
4369
4370 /*************************************************************************
4371 * trio_get_argument [public]
4372 */
4373 trio_pointer_t
4374 trio_get_argument
4375 TRIO_ARGS1((ref),
4376 trio_pointer_t ref)
4377 {
4378 #if defined(FORMAT_USER_DEFINED)
4379 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4380 #endif
4381
4382 return ((trio_reference_t *)ref)->parameter->data.pointer;
4383 }
4384
4385 /*************************************************************************
4386 * trio_get_width / trio_set_width [public]
4387 */
4388 int
4389 trio_get_width
4390 TRIO_ARGS1((ref),
4391 trio_pointer_t ref)
4392 {
4393 return ((trio_reference_t *)ref)->parameter->width;
4394 }
4395
4396 void
4397 trio_set_width
4398 TRIO_ARGS2((ref, width),
4399 trio_pointer_t ref,
4400 int width)
4401 {
4402 ((trio_reference_t *)ref)->parameter->width = width;
4403 }
4404
4405 /*************************************************************************
4406 * trio_get_precision / trio_set_precision [public]
4407 */
4408 int
4409 trio_get_precision
4410 TRIO_ARGS1((ref),
4411 trio_pointer_t ref)
4412 {
4413 return (((trio_reference_t *)ref)->parameter->precision);
4414 }
4415
4416 void
4417 trio_set_precision
4418 TRIO_ARGS2((ref, precision),
4419 trio_pointer_t ref,
4420 int precision)
4421 {
4422 ((trio_reference_t *)ref)->parameter->precision = precision;
4423 }
4424
4425 /*************************************************************************
4426 * trio_get_base / trio_set_base [public]
4427 */
4428 int
4429 trio_get_base
4430 TRIO_ARGS1((ref),
4431 trio_pointer_t ref)
4432 {
4433 return (((trio_reference_t *)ref)->parameter->base);
4434 }
4435
4436 void
4437 trio_set_base
4438 TRIO_ARGS2((ref, base),
4439 trio_pointer_t ref,
4440 int base)
4441 {
4442 ((trio_reference_t *)ref)->parameter->base = base;
4443 }
4444
4445 /*************************************************************************
4446 * trio_get_long / trio_set_long [public]
4447 */
4448 int
4449 trio_get_long
4450 TRIO_ARGS1((ref),
4451 trio_pointer_t ref)
4452 {
4453 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4454 ? TRUE
4455 : FALSE;
4456 }
4457
4458 void
4459 trio_set_long
4460 TRIO_ARGS2((ref, is_long),
4461 trio_pointer_t ref,
4462 int is_long)
4463 {
4464 if (is_long)
4465 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
4466 else
4467 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
4468 }
4469
4470 /*************************************************************************
4471 * trio_get_longlong / trio_set_longlong [public]
4472 */
4473 int
4474 trio_get_longlong
4475 TRIO_ARGS1((ref),
4476 trio_pointer_t ref)
4477 {
4478 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4479 ? TRUE
4480 : FALSE;
4481 }
4482
4483 void
4484 trio_set_longlong
4485 TRIO_ARGS2((ref, is_longlong),
4486 trio_pointer_t ref,
4487 int is_longlong)
4488 {
4489 if (is_longlong)
4490 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
4491 else
4492 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
4493 }
4494
4495 /*************************************************************************
4496 * trio_get_longdouble / trio_set_longdouble [public]
4497 */
4498 int
4499 trio_get_longdouble
4500 TRIO_ARGS1((ref),
4501 trio_pointer_t ref)
4502 {
4503 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4504 ? TRUE
4505 : FALSE;
4506 }
4507
4508 void
4509 trio_set_longdouble
4510 TRIO_ARGS2((ref, is_longdouble),
4511 trio_pointer_t ref,
4512 int is_longdouble)
4513 {
4514 if (is_longdouble)
4515 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
4516 else
4517 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
4518 }
4519
4520 /*************************************************************************
4521 * trio_get_short / trio_set_short [public]
4522 */
4523 int
4524 trio_get_short
4525 TRIO_ARGS1((ref),
4526 trio_pointer_t ref)
4527 {
4528 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4529 ? TRUE
4530 : FALSE;
4531 }
4532
4533 void
4534 trio_set_short
4535 TRIO_ARGS2((ref, is_short),
4536 trio_pointer_t ref,
4537 int is_short)
4538 {
4539 if (is_short)
4540 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
4541 else
4542 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
4543 }
4544
4545 /*************************************************************************
4546 * trio_get_shortshort / trio_set_shortshort [public]
4547 */
4548 int
4549 trio_get_shortshort
4550 TRIO_ARGS1((ref),
4551 trio_pointer_t ref)
4552 {
4553 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4554 ? TRUE
4555 : FALSE;
4556 }
4557
4558 void
4559 trio_set_shortshort
4560 TRIO_ARGS2((ref, is_shortshort),
4561 trio_pointer_t ref,
4562 int is_shortshort)
4563 {
4564 if (is_shortshort)
4565 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
4566 else
4567 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
4568 }
4569
4570 /*************************************************************************
4571 * trio_get_alternative / trio_set_alternative [public]
4572 */
4573 int
4574 trio_get_alternative
4575 TRIO_ARGS1((ref),
4576 trio_pointer_t ref)
4577 {
4578 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4579 ? TRUE
4580 : FALSE;
4581 }
4582
4583 void
4584 trio_set_alternative
4585 TRIO_ARGS2((ref, is_alternative),
4586 trio_pointer_t ref,
4587 int is_alternative)
4588 {
4589 if (is_alternative)
4590 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
4591 else
4592 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
4593 }
4594
4595 /*************************************************************************
4596 * trio_get_alignment / trio_set_alignment [public]
4597 */
4598 int
4599 trio_get_alignment
4600 TRIO_ARGS1((ref),
4601 trio_pointer_t ref)
4602 {
4603 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4604 ? TRUE
4605 : FALSE;
4606 }
4607
4608 void
4609 trio_set_alignment
4610 TRIO_ARGS2((ref, is_leftaligned),
4611 trio_pointer_t ref,
4612 int is_leftaligned)
4613 {
4614 if (is_leftaligned)
4615 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
4616 else
4617 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
4618 }
4619
4620 /*************************************************************************
4621 * trio_get_spacing /trio_set_spacing [public]
4622 */
4623 int
4624 trio_get_spacing
4625 TRIO_ARGS1((ref),
4626 trio_pointer_t ref)
4627 {
4628 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4629 ? TRUE
4630 : FALSE;
4631 }
4632
4633 void
4634 trio_set_spacing
4635 TRIO_ARGS2((ref, is_space),
4636 trio_pointer_t ref,
4637 int is_space)
4638 {
4639 if (is_space)
4640 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
4641 else
4642 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
4643 }
4644
4645 /*************************************************************************
4646 * trio_get_sign / trio_set_sign [public]
4647 */
4648 int
4649 trio_get_sign
4650 TRIO_ARGS1((ref),
4651 trio_pointer_t ref)
4652 {
4653 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4654 ? TRUE
4655 : FALSE;
4656 }
4657
4658 void
4659 trio_set_sign
4660 TRIO_ARGS2((ref, is_sign),
4661 trio_pointer_t ref,
4662 int is_sign)
4663 {
4664 if (is_sign)
4665 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
4666 else
4667 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
4668 }
4669
4670 /*************************************************************************
4671 * trio_get_padding / trio_set_padding [public]
4672 */
4673 int
4674 trio_get_padding
4675 TRIO_ARGS1((ref),
4676 trio_pointer_t ref)
4677 {
4678 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4679 ? TRUE
4680 : FALSE;
4681 }
4682
4683 void
4684 trio_set_padding
4685 TRIO_ARGS2((ref, is_padding),
4686 trio_pointer_t ref,
4687 int is_padding)
4688 {
4689 if (is_padding)
4690 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
4691 else
4692 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
4693 }
4694
4695 /*************************************************************************
4696 * trio_get_quote / trio_set_quote [public]
4697 */
4698 int
4699 trio_get_quote
4700 TRIO_ARGS1((ref),
4701 trio_pointer_t ref)
4702 {
4703 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4704 ? TRUE
4705 : FALSE;
4706 }
4707
4708 void
4709 trio_set_quote
4710 TRIO_ARGS2((ref, is_quote),
4711 trio_pointer_t ref,
4712 int is_quote)
4713 {
4714 if (is_quote)
4715 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
4716 else
4717 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
4718 }
4719
4720 /*************************************************************************
4721 * trio_get_upper / trio_set_upper [public]
4722 */
4723 int
4724 trio_get_upper
4725 TRIO_ARGS1((ref),
4726 trio_pointer_t ref)
4727 {
4728 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4729 ? TRUE
4730 : FALSE;
4731 }
4732
4733 void
4734 trio_set_upper
4735 TRIO_ARGS2((ref, is_upper),
4736 trio_pointer_t ref,
4737 int is_upper)
4738 {
4739 if (is_upper)
4740 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
4741 else
4742 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
4743 }
4744
4745 /*************************************************************************
4746 * trio_get_largest / trio_set_largest [public]
4747 */
4748 #if TRIO_C99
4749 int
4750 trio_get_largest
4751 TRIO_ARGS1((ref),
4752 trio_pointer_t ref)
4753 {
4754 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4755 ? TRUE
4756 : FALSE;
4757 }
4758
4759 void
4760 trio_set_largest
4761 TRIO_ARGS2((ref, is_largest),
4762 trio_pointer_t ref,
4763 int is_largest)
4764 {
4765 if (is_largest)
4766 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
4767 else
4768 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
4769 }
4770 #endif
4771
4772 /*************************************************************************
4773 * trio_get_ptrdiff / trio_set_ptrdiff [public]
4774 */
4775 int
4776 trio_get_ptrdiff
4777 TRIO_ARGS1((ref),
4778 trio_pointer_t ref)
4779 {
4780 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4781 ? TRUE
4782 : FALSE;
4783 }
4784
4785 void
4786 trio_set_ptrdiff
4787 TRIO_ARGS2((ref, is_ptrdiff),
4788 trio_pointer_t ref,
4789 int is_ptrdiff)
4790 {
4791 if (is_ptrdiff)
4792 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
4793 else
4794 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
4795 }
4796
4797 /*************************************************************************
4798 * trio_get_size / trio_set_size [public]
4799 */
4800 #if TRIO_C99
4801 int
4802 trio_get_size
4803 TRIO_ARGS1((ref),
4804 trio_pointer_t ref)
4805 {
4806 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4807 ? TRUE
4808 : FALSE;
4809 }
4810
4811 void
4812 trio_set_size
4813 TRIO_ARGS2((ref, is_size),
4814 trio_pointer_t ref,
4815 int is_size)
4816 {
4817 if (is_size)
4818 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
4819 else
4820 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4821 }
4822 #endif
4823
4824 /*************************************************************************
4825 * trio_print_int [public]
4826 */
4827 void
4828 trio_print_int
4829 TRIO_ARGS2((ref, number),
4830 trio_pointer_t ref,
4831 int number)
4832 {
4833 trio_reference_t *self = (trio_reference_t *)ref;
4834
4835 TrioWriteNumber(self->data,
4836 (trio_uintmax_t)number,
4837 self->parameter->flags,
4838 self->parameter->width,
4839 self->parameter->precision,
4840 self->parameter->base);
4841 }
4842
4843 /*************************************************************************
4844 * trio_print_uint [public]
4845 */
4846 void
4847 trio_print_uint
4848 TRIO_ARGS2((ref, number),
4849 trio_pointer_t ref,
4850 unsigned int number)
4851 {
4852 trio_reference_t *self = (trio_reference_t *)ref;
4853
4854 TrioWriteNumber(self->data,
4855 (trio_uintmax_t)number,
4856 self->parameter->flags | FLAGS_UNSIGNED,
4857 self->parameter->width,
4858 self->parameter->precision,
4859 self->parameter->base);
4860 }
4861
4862 /*************************************************************************
4863 * trio_print_double [public]
4864 */
4865 void
4866 trio_print_double
4867 TRIO_ARGS2((ref, number),
4868 trio_pointer_t ref,
4869 double number)
4870 {
4871 trio_reference_t *self = (trio_reference_t *)ref;
4872
4873 TrioWriteDouble(self->data,
4874 number,
4875 self->parameter->flags,
4876 self->parameter->width,
4877 self->parameter->precision,
4878 self->parameter->base);
4879 }
4880
4881 /*************************************************************************
4882 * trio_print_string [public]
4883 */
4884 void
4885 trio_print_string
4886 TRIO_ARGS2((ref, string),
4887 trio_pointer_t ref,
4888 char *string)
4889 {
4890 trio_reference_t *self = (trio_reference_t *)ref;
4891
4892 TrioWriteString(self->data,
4893 string,
4894 self->parameter->flags,
4895 self->parameter->width,
4896 self->parameter->precision);
4897 }
4898
4899 /*************************************************************************
4900 * trio_print_ref [public]
4901 */
4902 int
4903 trio_print_ref
4904 TRIO_VARGS3((ref, format, va_alist),
4905 trio_pointer_t ref,
4906 TRIO_CONST char *format,
4907 TRIO_VA_DECL)
4908 {
4909 int status;
4910 va_list arglist;
4911
4912 assert(VALID(format));
4913
4914 TRIO_VA_START(arglist, format);
4915 status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4916 TRIO_VA_END(arglist);
4917 return status;
4918 }
4919
4920 /*************************************************************************
4921 * trio_vprint_ref [public]
4922 */
4923 int
4924 trio_vprint_ref
4925 TRIO_ARGS3((ref, format, arglist),
4926 trio_pointer_t ref,
4927 TRIO_CONST char *format,
4928 va_list arglist)
4929 {
4930 assert(VALID(format));
4931
4932 return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
4933 }
4934
4935 /*************************************************************************
4936 * trio_printv_ref [public]
4937 */
4938 int
4939 trio_printv_ref
4940 TRIO_ARGS3((ref, format, argarray),
4941 trio_pointer_t ref,
4942 TRIO_CONST char *format,
4943 trio_pointer_t *argarray)
4944 {
4945 assert(VALID(format));
4946
4947 return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4948 }
4949
4950 #endif /* TRIO_EXTENSION */
4951
4952 /*************************************************************************
4953 * trio_print_pointer [public]
4954 */
4955 void
4956 trio_print_pointer
4957 TRIO_ARGS2((ref, pointer),
4958 trio_pointer_t ref,
4959 trio_pointer_t pointer)
4960 {
4961 trio_reference_t *self = (trio_reference_t *)ref;
4962 trio_flags_t flags;
4963 trio_uintmax_t number;
4964
4965 if (NULL == pointer)
4966 {
4967 TRIO_CONST char *string = internalNullString;
4968 while (*string)
4969 self->data->OutStream(self->data, *string++);
4970 }
4971 else
4972 {
4973 /*
4974 * The subtraction of the null pointer is a workaround
4975 * to avoid a compiler warning. The performance overhead
4976 * is negligible (and likely to be removed by an
4977 * optimizing compiler). The (char *) casting is done
4978 * to please ANSI C++.
4979 */
4980 number = (trio_uintmax_t)((char *)pointer - (char *)0);
4981 /* Shrink to size of pointer */
4982 number &= (trio_uintmax_t)-1;
4983 flags = self->parameter->flags;
4984 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
4985 FLAGS_NILPADDING);
4986 TrioWriteNumber(self->data,
4987 number,
4988 flags,
4989 POINTER_WIDTH,
4990 NO_PRECISION,
4991 BASE_HEX);
4992 }
4993 }
4994
4995 /** @} End of UserDefined documentation module */
4996
4997 /*************************************************************************
4998 *
4999 * LOCALES
5000 *
5001 ************************************************************************/
5002
5003 /*************************************************************************
5004 * trio_locale_set_decimal_point
5005 *
5006 * Decimal point can only be one character. The input argument is a
5007 * string to enable multibyte characters. At most MB_LEN_MAX characters
5008 * will be used.
5009 */
5010 TRIO_PUBLIC void
5011 trio_locale_set_decimal_point
5012 TRIO_ARGS1((decimalPoint),
5013 char *decimalPoint)
5014 {
5015 #if defined(USE_LOCALE)
5016 if (NULL == internalLocaleValues)
5017 {
5018 TrioSetLocale();
5019 }
5020 #endif
5021 internalDecimalPointLength = trio_length(decimalPoint);
5022 if (internalDecimalPointLength == 1)
5023 {
5024 internalDecimalPoint = *decimalPoint;
5025 }
5026 else
5027 {
5028 internalDecimalPoint = NIL;
5029 trio_copy_max(internalDecimalPointString,
5030 sizeof(internalDecimalPointString),
5031 decimalPoint);
5032 }
5033 }
5034
5035 /*************************************************************************
5036 * trio_locale_set_thousand_separator
5037 *
5038 * See trio_locale_set_decimal_point
5039 */
5040 TRIO_PUBLIC void
5041 trio_locale_set_thousand_separator
5042 TRIO_ARGS1((thousandSeparator),
5043 char *thousandSeparator)
5044 {
5045 #if defined(USE_LOCALE)
5046 if (NULL == internalLocaleValues)
5047 {
5048 TrioSetLocale();
5049 }
5050 #endif
5051 trio_copy_max(internalThousandSeparator,
5052 sizeof(internalThousandSeparator),
5053 thousandSeparator);
5054 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5055 }
5056
5057 /*************************************************************************
5058 * trio_locale_set_grouping
5059 *
5060 * Array of bytes. Reversed order.
5061 *
5062 * CHAR_MAX : No further grouping
5063 * 0 : Repeat last group for the remaining digits (not necessary
5064 * as C strings are zero-terminated)
5065 * n : Set current group to n
5066 *
5067 * Same order as the grouping attribute in LC_NUMERIC.
5068 */
5069 TRIO_PUBLIC void
5070 trio_locale_set_grouping
5071 TRIO_ARGS1((grouping),
5072 char *grouping)
5073 {
5074 #if defined(USE_LOCALE)
5075 if (NULL == internalLocaleValues)
5076 {
5077 TrioSetLocale();
5078 }
5079 #endif
5080 trio_copy_max(internalGrouping,
5081 sizeof(internalGrouping),
5082 grouping);
5083 }
5084
5085
5086 /*************************************************************************
5087 *
5088 * SCANNING
5089 *
5090 ************************************************************************/
5091
5092 /*************************************************************************
5093 * TrioSkipWhitespaces
5094 */
5095 TRIO_PRIVATE int
5096 TrioSkipWhitespaces
5097 TRIO_ARGS1((self),
5098 trio_class_t *self)
5099 {
5100 int ch;
5101
5102 ch = self->current;
5103 while (isspace(ch))
5104 {
5105 self->InStream(self, &ch);
5106 }
5107 return ch;
5108 }
5109
5110 /*************************************************************************
5111 * TrioGetCollation
5112 */
5113 #if TRIO_EXTENSION
5114 TRIO_PRIVATE void
TrioGetCollation(TRIO_NOARGS)5115 TrioGetCollation(TRIO_NOARGS)
5116 {
5117 int i;
5118 int j;
5119 int k;
5120 char first[2];
5121 char second[2];
5122
5123 /* This is computationally expensive */
5124 first[1] = NIL;
5125 second[1] = NIL;
5126 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5127 {
5128 k = 0;
5129 first[0] = (char)i;
5130 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5131 {
5132 second[0] = (char)j;
5133 if (trio_equal_locale(first, second))
5134 internalCollationArray[i][k++] = (char)j;
5135 }
5136 internalCollationArray[i][k] = NIL;
5137 }
5138 }
5139 #endif
5140
5141 /*************************************************************************
5142 * TrioGetCharacterClass
5143 *
5144 * FIXME:
5145 * multibyte
5146 */
5147 TRIO_PRIVATE int
5148 TrioGetCharacterClass
5149 TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5150 TRIO_CONST char *format,
5151 int *indexPointer,
5152 trio_flags_t *flagsPointer,
5153 int *characterclass)
5154 {
5155 int index = *indexPointer;
5156 int i;
5157 char ch;
5158 char range_begin;
5159 char range_end;
5160
5161 *flagsPointer &= ~FLAGS_EXCLUDE;
5162
5163 if (format[index] == QUALIFIER_CIRCUMFLEX)
5164 {
5165 *flagsPointer |= FLAGS_EXCLUDE;
5166 index++;
5167 }
5168 /*
5169 * If the ungroup character is at the beginning of the scanlist,
5170 * it will be part of the class, and a second ungroup character
5171 * must follow to end the group.
5172 */
5173 if (format[index] == SPECIFIER_UNGROUP)
5174 {
5175 characterclass[(int)SPECIFIER_UNGROUP]++;
5176 index++;
5177 }
5178 /*
5179 * Minus is used to specify ranges. To include minus in the class,
5180 * it must be at the beginning of the list
5181 */
5182 if (format[index] == QUALIFIER_MINUS)
5183 {
5184 characterclass[(int)QUALIFIER_MINUS]++;
5185 index++;
5186 }
5187 /* Collect characters */
5188 for (ch = format[index];
5189 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
5190 ch = format[++index])
5191 {
5192 switch (ch)
5193 {
5194 case QUALIFIER_MINUS: /* Scanlist ranges */
5195
5196 /*
5197 * Both C99 and UNIX98 describes ranges as implementation-
5198 * defined.
5199 *
5200 * We support the following behaviour (although this may
5201 * change as we become wiser)
5202 * - only increasing ranges, ie. [a-b] but not [b-a]
5203 * - transitive ranges, ie. [a-b-c] == [a-c]
5204 * - trailing minus, ie. [a-] is interpreted as an 'a'
5205 * and a '-'
5206 * - duplicates (although we can easily convert these
5207 * into errors)
5208 */
5209 range_begin = format[index - 1];
5210 range_end = format[++index];
5211 if (range_end == SPECIFIER_UNGROUP)
5212 {
5213 /* Trailing minus is included */
5214 characterclass[(int)ch]++;
5215 ch = range_end;
5216 break; /* for */
5217 }
5218 if (range_end == NIL)
5219 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5220 if (range_begin > range_end)
5221 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5222
5223 for (i = (int)range_begin; i <= (int)range_end; i++)
5224 characterclass[i]++;
5225
5226 ch = range_end;
5227 break;
5228
5229 #if TRIO_EXTENSION
5230
5231 case SPECIFIER_GROUP:
5232
5233 switch (format[index + 1])
5234 {
5235 case QUALIFIER_DOT: /* Collating symbol */
5236 /*
5237 * FIXME: This will be easier to implement when multibyte
5238 * characters have been implemented. Until now, we ignore
5239 * this feature.
5240 */
5241 for (i = index + 2; ; i++)
5242 {
5243 if (format[i] == NIL)
5244 /* Error in syntax */
5245 return -1;
5246 else if (format[i] == QUALIFIER_DOT)
5247 break; /* for */
5248 }
5249 if (format[++i] != SPECIFIER_UNGROUP)
5250 return -1;
5251
5252 index = i;
5253 break;
5254
5255 case QUALIFIER_EQUAL: /* Equivalence class expressions */
5256 {
5257 unsigned int j;
5258 unsigned int k;
5259
5260 if (internalCollationUnconverted)
5261 {
5262 /* Lazy evaluation of collation array */
5263 TrioGetCollation();
5264 internalCollationUnconverted = FALSE;
5265 }
5266 for (i = index + 2; ; i++)
5267 {
5268 if (format[i] == NIL)
5269 /* Error in syntax */
5270 return -1;
5271 else if (format[i] == QUALIFIER_EQUAL)
5272 break; /* for */
5273 else
5274 {
5275 /* Mark any equivalent character */
5276 k = (unsigned int)format[i];
5277 for (j = 0; internalCollationArray[k][j] != NIL; j++)
5278 characterclass[(int)internalCollationArray[k][j]]++;
5279 }
5280 }
5281 if (format[++i] != SPECIFIER_UNGROUP)
5282 return -1;
5283
5284 index = i;
5285 }
5286 break;
5287
5288 case QUALIFIER_COLON: /* Character class expressions */
5289
5290 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5291 &format[index]))
5292 {
5293 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5294 if (isalnum(i))
5295 characterclass[i]++;
5296 index += sizeof(CLASS_ALNUM) - 1;
5297 }
5298 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5299 &format[index]))
5300 {
5301 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5302 if (isalpha(i))
5303 characterclass[i]++;
5304 index += sizeof(CLASS_ALPHA) - 1;
5305 }
5306 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5307 &format[index]))
5308 {
5309 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5310 if (iscntrl(i))
5311 characterclass[i]++;
5312 index += sizeof(CLASS_CNTRL) - 1;
5313 }
5314 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5315 &format[index]))
5316 {
5317 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5318 if (isdigit(i))
5319 characterclass[i]++;
5320 index += sizeof(CLASS_DIGIT) - 1;
5321 }
5322 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5323 &format[index]))
5324 {
5325 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5326 if (isgraph(i))
5327 characterclass[i]++;
5328 index += sizeof(CLASS_GRAPH) - 1;
5329 }
5330 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5331 &format[index]))
5332 {
5333 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5334 if (islower(i))
5335 characterclass[i]++;
5336 index += sizeof(CLASS_LOWER) - 1;
5337 }
5338 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5339 &format[index]))
5340 {
5341 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5342 if (isprint(i))
5343 characterclass[i]++;
5344 index += sizeof(CLASS_PRINT) - 1;
5345 }
5346 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5347 &format[index]))
5348 {
5349 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5350 if (ispunct(i))
5351 characterclass[i]++;
5352 index += sizeof(CLASS_PUNCT) - 1;
5353 }
5354 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5355 &format[index]))
5356 {
5357 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5358 if (isspace(i))
5359 characterclass[i]++;
5360 index += sizeof(CLASS_SPACE) - 1;
5361 }
5362 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5363 &format[index]))
5364 {
5365 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5366 if (isupper(i))
5367 characterclass[i]++;
5368 index += sizeof(CLASS_UPPER) - 1;
5369 }
5370 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5371 &format[index]))
5372 {
5373 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5374 if (isxdigit(i))
5375 characterclass[i]++;
5376 index += sizeof(CLASS_XDIGIT) - 1;
5377 }
5378 else
5379 {
5380 characterclass[(int)ch]++;
5381 }
5382 break;
5383
5384 default:
5385 characterclass[(int)ch]++;
5386 break;
5387 }
5388 break;
5389
5390 #endif /* TRIO_EXTENSION */
5391
5392 default:
5393 characterclass[(int)ch]++;
5394 break;
5395 }
5396 }
5397 return 0;
5398 }
5399
5400 /*************************************************************************
5401 * TrioReadNumber
5402 *
5403 * We implement our own number conversion in preference of strtol and
5404 * strtoul, because we must handle 'long long' and thousand separators.
5405 */
5406 TRIO_PRIVATE BOOLEAN_T
5407 TrioReadNumber
5408 TRIO_ARGS5((self, target, flags, width, base),
5409 trio_class_t *self,
5410 trio_uintmax_t *target,
5411 trio_flags_t flags,
5412 int width,
5413 int base)
5414 {
5415 trio_uintmax_t number = 0;
5416 int digit;
5417 int count;
5418 BOOLEAN_T isNegative = FALSE;
5419 BOOLEAN_T gotNumber = FALSE;
5420 int j;
5421
5422 assert(VALID(self));
5423 assert(VALID(self->InStream));
5424 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5425
5426 if (internalDigitsUnconverted)
5427 {
5428 /* Lazy evaluation of digits array */
5429 memset(internalDigitArray, -1, sizeof(internalDigitArray));
5430 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5431 {
5432 internalDigitArray[(int)internalDigitsLower[j]] = j;
5433 internalDigitArray[(int)internalDigitsUpper[j]] = j;
5434 }
5435 internalDigitsUnconverted = FALSE;
5436 }
5437
5438 TrioSkipWhitespaces(self);
5439
5440 if (!(flags & FLAGS_UNSIGNED))
5441 {
5442 /* Leading sign */
5443 if (self->current == '+')
5444 {
5445 self->InStream(self, NULL);
5446 }
5447 else if (self->current == '-')
5448 {
5449 self->InStream(self, NULL);
5450 isNegative = TRUE;
5451 }
5452 }
5453
5454 count = self->processed;
5455
5456 if (flags & FLAGS_ALTERNATIVE)
5457 {
5458 switch (base)
5459 {
5460 case NO_BASE:
5461 case BASE_OCTAL:
5462 case BASE_HEX:
5463 case BASE_BINARY:
5464 if (self->current == '0')
5465 {
5466 self->InStream(self, NULL);
5467 if (self->current)
5468 {
5469 if ((base == BASE_HEX) &&
5470 (trio_to_upper(self->current) == 'X'))
5471 {
5472 self->InStream(self, NULL);
5473 }
5474 else if ((base == BASE_BINARY) &&
5475 (trio_to_upper(self->current) == 'B'))
5476 {
5477 self->InStream(self, NULL);
5478 }
5479 }
5480 }
5481 else
5482 return FALSE;
5483 break;
5484 default:
5485 break;
5486 }
5487 }
5488
5489 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5490 (! ((self->current == EOF) || isspace(self->current))))
5491 {
5492 if (isascii(self->current))
5493 {
5494 digit = internalDigitArray[self->current];
5495 /* Abort if digit is not allowed in the specified base */
5496 if ((digit == -1) || (digit >= base))
5497 break;
5498 }
5499 else if (flags & FLAGS_QUOTE)
5500 {
5501 /* Compare with thousands separator */
5502 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5503 {
5504 if (internalThousandSeparator[j] != self->current)
5505 break;
5506
5507 self->InStream(self, NULL);
5508 }
5509 if (internalThousandSeparator[j])
5510 break; /* Mismatch */
5511 else
5512 continue; /* Match */
5513 }
5514 else
5515 break;
5516
5517 number *= base;
5518 number += digit;
5519 gotNumber = TRUE; /* we need at least one digit */
5520
5521 self->InStream(self, NULL);
5522 }
5523
5524 /* Was anything read at all? */
5525 if (!gotNumber)
5526 return FALSE;
5527
5528 if (target)
5529 *target = (isNegative) ? -((trio_intmax_t)number) : number;
5530 return TRUE;
5531 }
5532
5533 /*************************************************************************
5534 * TrioReadChar
5535 */
5536 TRIO_PRIVATE int
5537 TrioReadChar
5538 TRIO_ARGS4((self, target, flags, width),
5539 trio_class_t *self,
5540 char *target,
5541 trio_flags_t flags,
5542 int width)
5543 {
5544 int i;
5545 char ch;
5546 trio_uintmax_t number;
5547
5548 assert(VALID(self));
5549 assert(VALID(self->InStream));
5550
5551 for (i = 0;
5552 (self->current != EOF) && (i < width);
5553 i++)
5554 {
5555 ch = (char)self->current;
5556 self->InStream(self, NULL);
5557 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5558 {
5559 switch (self->current)
5560 {
5561 case '\\': ch = '\\'; break;
5562 case 'a': ch = '\007'; break;
5563 case 'b': ch = '\b'; break;
5564 case 'f': ch = '\f'; break;
5565 case 'n': ch = '\n'; break;
5566 case 'r': ch = '\r'; break;
5567 case 't': ch = '\t'; break;
5568 case 'v': ch = '\v'; break;
5569 default:
5570 if (isdigit(self->current))
5571 {
5572 /* Read octal number */
5573 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5574 return 0;
5575 ch = (char)number;
5576 }
5577 else if (trio_to_upper(self->current) == 'X')
5578 {
5579 /* Read hexadecimal number */
5580 self->InStream(self, NULL);
5581 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5582 return 0;
5583 ch = (char)number;
5584 }
5585 else
5586 {
5587 ch = (char)self->current;
5588 }
5589 break;
5590 }
5591 }
5592
5593 if (target)
5594 target[i] = ch;
5595 }
5596 return i + 1;
5597 }
5598
5599 /*************************************************************************
5600 * TrioReadString
5601 */
5602 TRIO_PRIVATE BOOLEAN_T
5603 TrioReadString
5604 TRIO_ARGS4((self, target, flags, width),
5605 trio_class_t *self,
5606 char *target,
5607 trio_flags_t flags,
5608 int width)
5609 {
5610 int i;
5611
5612 assert(VALID(self));
5613 assert(VALID(self->InStream));
5614
5615 TrioSkipWhitespaces(self);
5616
5617 /*
5618 * Continue until end of string is reached, a whitespace is encountered,
5619 * or width is exceeded
5620 */
5621 for (i = 0;
5622 ((width == NO_WIDTH) || (i < width)) &&
5623 (! ((self->current == EOF) || isspace(self->current)));
5624 i++)
5625 {
5626 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
5627 break; /* for */
5628 }
5629 if (target)
5630 target[i] = NIL;
5631 return TRUE;
5632 }
5633
5634 /*************************************************************************
5635 * TrioReadWideChar
5636 */
5637 #if TRIO_WIDECHAR
5638 TRIO_PRIVATE int
5639 TrioReadWideChar
5640 TRIO_ARGS4((self, target, flags, width),
5641 trio_class_t *self,
5642 trio_wchar_t *target,
5643 trio_flags_t flags,
5644 int width)
5645 {
5646 int i;
5647 int j;
5648 int size;
5649 int amount = 0;
5650 trio_wchar_t wch;
5651 char buffer[MB_LEN_MAX + 1];
5652
5653 assert(VALID(self));
5654 assert(VALID(self->InStream));
5655
5656 for (i = 0;
5657 (self->current != EOF) && (i < width);
5658 i++)
5659 {
5660 if (isascii(self->current))
5661 {
5662 if (TrioReadChar(self, buffer, flags, 1) == 0)
5663 return 0;
5664 buffer[1] = NIL;
5665 }
5666 else
5667 {
5668 /*
5669 * Collect a multibyte character, by enlarging buffer until
5670 * it contains a fully legal multibyte character, or the
5671 * buffer is full.
5672 */
5673 j = 0;
5674 do
5675 {
5676 buffer[j++] = (char)self->current;
5677 buffer[j] = NIL;
5678 self->InStream(self, NULL);
5679 }
5680 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5681 }
5682 if (target)
5683 {
5684 size = mbtowc(&wch, buffer, sizeof(buffer));
5685 if (size > 0)
5686 target[i] = wch;
5687 }
5688 amount += size;
5689 self->InStream(self, NULL);
5690 }
5691 return amount;
5692 }
5693 #endif /* TRIO_WIDECHAR */
5694
5695 /*************************************************************************
5696 * TrioReadWideString
5697 */
5698 #if TRIO_WIDECHAR
5699 TRIO_PRIVATE BOOLEAN_T
5700 TrioReadWideString
5701 TRIO_ARGS4((self, target, flags, width),
5702 trio_class_t *self,
5703 trio_wchar_t *target,
5704 trio_flags_t flags,
5705 int width)
5706 {
5707 int i;
5708 int size;
5709
5710 assert(VALID(self));
5711 assert(VALID(self->InStream));
5712
5713 TrioSkipWhitespaces(self);
5714
5715 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
5716 (void)mblen(NULL, 0);
5717 #endif
5718
5719 /*
5720 * Continue until end of string is reached, a whitespace is encountered,
5721 * or width is exceeded
5722 */
5723 for (i = 0;
5724 ((width == NO_WIDTH) || (i < width)) &&
5725 (! ((self->current == EOF) || isspace(self->current)));
5726 )
5727 {
5728 size = TrioReadWideChar(self, &target[i], flags, 1);
5729 if (size == 0)
5730 break; /* for */
5731
5732 i += size;
5733 }
5734 if (target)
5735 target[i] = WCONST('\0');
5736 return TRUE;
5737 }
5738 #endif /* TRIO_WIDECHAR */
5739
5740 /*************************************************************************
5741 * TrioReadGroup
5742 *
5743 * FIXME: characterclass does not work with multibyte characters
5744 */
5745 TRIO_PRIVATE BOOLEAN_T
5746 TrioReadGroup
5747 TRIO_ARGS5((self, target, characterclass, flags, width),
5748 trio_class_t *self,
5749 char *target,
5750 int *characterclass,
5751 trio_flags_t flags,
5752 int width)
5753 {
5754 int ch;
5755 int i;
5756
5757 assert(VALID(self));
5758 assert(VALID(self->InStream));
5759
5760 ch = self->current;
5761 for (i = 0;
5762 ((width == NO_WIDTH) || (i < width)) &&
5763 (! ((ch == EOF) ||
5764 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
5765 i++)
5766 {
5767 if (target)
5768 target[i] = (char)ch;
5769 self->InStream(self, &ch);
5770 }
5771
5772 if (target)
5773 target[i] = NIL;
5774 return TRUE;
5775 }
5776
5777 /*************************************************************************
5778 * TrioReadDouble
5779 *
5780 * FIXME:
5781 * add long double
5782 * handle base
5783 */
5784 TRIO_PRIVATE BOOLEAN_T
5785 TrioReadDouble
5786 TRIO_ARGS4((self, target, flags, width),
5787 trio_class_t *self,
5788 trio_pointer_t target,
5789 trio_flags_t flags,
5790 int width)
5791 {
5792 int ch;
5793 char doubleString[512];
5794 int index = 0;
5795 int start;
5796 int j;
5797 BOOLEAN_T isHex = FALSE;
5798
5799 doubleString[0] = 0;
5800
5801 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
5802 width = sizeof(doubleString) - 1;
5803
5804 TrioSkipWhitespaces(self);
5805
5806 /*
5807 * Read entire double number from stream. trio_to_double requires
5808 * a string as input, but InStream can be anything, so we have to
5809 * collect all characters.
5810 */
5811 ch = self->current;
5812 if ((ch == '+') || (ch == '-'))
5813 {
5814 doubleString[index++] = (char)ch;
5815 self->InStream(self, &ch);
5816 width--;
5817 }
5818
5819 start = index;
5820 switch (ch)
5821 {
5822 case 'n':
5823 case 'N':
5824 /* Not-a-number */
5825 if (index != 0)
5826 break;
5827 /* FALLTHROUGH */
5828 case 'i':
5829 case 'I':
5830 /* Infinity */
5831 while (isalpha(ch) && (index - start < width))
5832 {
5833 doubleString[index++] = (char)ch;
5834 self->InStream(self, &ch);
5835 }
5836 doubleString[index] = NIL;
5837
5838 /* Case insensitive string comparison */
5839 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
5840 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
5841 {
5842 if (flags & FLAGS_LONGDOUBLE)
5843 {
5844 if ((start == 1) && (doubleString[0] == '-'))
5845 {
5846 *((trio_long_double_t *)target) = trio_ninf();
5847 }
5848 else
5849 {
5850 *((trio_long_double_t *)target) = trio_pinf();
5851 }
5852 }
5853 else
5854 {
5855 if ((start == 1) && (doubleString[0] == '-'))
5856 {
5857 *((double *)target) = trio_ninf();
5858 }
5859 else
5860 {
5861 *((double *)target) = trio_pinf();
5862 }
5863 }
5864 return TRUE;
5865 }
5866 if (trio_equal(doubleString, NAN_UPPER))
5867 {
5868 /* NaN must not have a preceeding + nor - */
5869 if (flags & FLAGS_LONGDOUBLE)
5870 {
5871 *((trio_long_double_t *)target) = trio_nan();
5872 }
5873 else
5874 {
5875 *((double *)target) = trio_nan();
5876 }
5877 return TRUE;
5878 }
5879 return FALSE;
5880
5881 case '0':
5882 doubleString[index++] = (char)ch;
5883 self->InStream(self, &ch);
5884 if (trio_to_upper(ch) == 'X')
5885 {
5886 isHex = TRUE;
5887 doubleString[index++] = (char)ch;
5888 self->InStream(self, &ch);
5889 }
5890 break;
5891
5892 default:
5893 break;
5894 }
5895
5896 while ((ch != EOF) && (index - start < width))
5897 {
5898 /* Integer part */
5899 if (isHex ? isxdigit(ch) : isdigit(ch))
5900 {
5901 doubleString[index++] = (char)ch;
5902 self->InStream(self, &ch);
5903 }
5904 else if (flags & FLAGS_QUOTE)
5905 {
5906 /* Compare with thousands separator */
5907 for (j = 0; internalThousandSeparator[j] && self->current; j++)
5908 {
5909 if (internalThousandSeparator[j] != self->current)
5910 break;
5911
5912 self->InStream(self, &ch);
5913 }
5914 if (internalThousandSeparator[j])
5915 break; /* Mismatch */
5916 else
5917 continue; /* Match */
5918 }
5919 else
5920 break; /* while */
5921 }
5922 if (ch == '.')
5923 {
5924 /* Decimal part */
5925 doubleString[index++] = (char)ch;
5926 self->InStream(self, &ch);
5927 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
5928 (index - start < width))
5929 {
5930 doubleString[index++] = (char)ch;
5931 self->InStream(self, &ch);
5932 }
5933 if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
5934 {
5935 /* Exponent */
5936 doubleString[index++] = (char)ch;
5937 self->InStream(self, &ch);
5938 if ((ch == '+') || (ch == '-'))
5939 {
5940 doubleString[index++] = (char)ch;
5941 self->InStream(self, &ch);
5942 }
5943 while (isdigit(ch) && (index - start < width))
5944 {
5945 doubleString[index++] = (char)ch;
5946 self->InStream(self, &ch);
5947 }
5948 }
5949 }
5950
5951 if ((index == start) || (*doubleString == NIL))
5952 return FALSE;
5953
5954 doubleString[index] = 0;
5955
5956 if (flags & FLAGS_LONGDOUBLE)
5957 {
5958 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
5959 }
5960 else
5961 {
5962 *((double *)target) = trio_to_double(doubleString, NULL);
5963 }
5964 return TRUE;
5965 }
5966
5967 /*************************************************************************
5968 * TrioReadPointer
5969 */
5970 TRIO_PRIVATE BOOLEAN_T
5971 TrioReadPointer
5972 TRIO_ARGS3((self, target, flags),
5973 trio_class_t *self,
5974 trio_pointer_t *target,
5975 trio_flags_t flags)
5976 {
5977 trio_uintmax_t number;
5978 char buffer[sizeof(internalNullString)];
5979
5980 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
5981
5982 if (TrioReadNumber(self,
5983 &number,
5984 flags,
5985 POINTER_WIDTH,
5986 BASE_HEX))
5987 {
5988 /*
5989 * The strange assignment of number is a workaround for a compiler
5990 * warning
5991 */
5992 if (target)
5993 *target = (char *)0 + number;
5994 return TRUE;
5995 }
5996 else if (TrioReadString(self,
5997 (flags & FLAGS_IGNORE)
5998 ? NULL
5999 : buffer,
6000 0,
6001 sizeof(internalNullString) - 1))
6002 {
6003 if (trio_equal_case(buffer, internalNullString))
6004 {
6005 if (target)
6006 *target = NULL;
6007 return TRUE;
6008 }
6009 }
6010 return FALSE;
6011 }
6012
6013 /*************************************************************************
6014 * TrioScanProcess
6015 */
6016 TRIO_PRIVATE int
6017 TrioScanProcess
6018 TRIO_ARGS3((data, format, parameters),
6019 trio_class_t *data,
6020 TRIO_CONST char *format,
6021 trio_parameter_t *parameters)
6022 {
6023 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6024 int charlen;
6025 int cnt;
6026 #endif
6027 int assignment;
6028 int ch;
6029 int index; /* Index of format string */
6030 int i; /* Index of current parameter */
6031 trio_flags_t flags;
6032 int width;
6033 int base;
6034 trio_pointer_t pointer;
6035
6036 assignment = 0;
6037 i = 0;
6038 index = 0;
6039 data->InStream(data, &ch);
6040
6041 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6042 (void)mblen(NULL, 0);
6043 #endif
6044
6045 while (format[index])
6046 {
6047 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6048 if (! isascii(format[index]))
6049 {
6050 charlen = mblen(&format[index], MB_LEN_MAX);
6051 if (charlen != -1)
6052 {
6053 /* Compare multibyte characters in format string */
6054 for (cnt = 0; cnt < charlen - 1; cnt++)
6055 {
6056 if (ch != format[index + cnt])
6057 {
6058 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6059 }
6060 data->InStream(data, &ch);
6061 }
6062 continue; /* while characters left in formatting string */
6063 }
6064 }
6065 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
6066
6067 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6068 {
6069 return (assignment > 0) ? assignment : EOF;
6070 }
6071
6072 if (CHAR_IDENTIFIER == format[index])
6073 {
6074 if (CHAR_IDENTIFIER == format[index + 1])
6075 {
6076 /* Two % in format matches one % in input stream */
6077 if (CHAR_IDENTIFIER == ch)
6078 {
6079 data->InStream(data, &ch);
6080 index += 2;
6081 continue; /* while format chars left */
6082 }
6083 else
6084 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6085 }
6086
6087 /* Skip the parameter entries */
6088 while (parameters[i].type == FORMAT_PARAMETER)
6089 i++;
6090
6091 flags = parameters[i].flags;
6092 /* Find width */
6093 width = parameters[i].width;
6094 if (flags & FLAGS_WIDTH_PARAMETER)
6095 {
6096 /* Get width from parameter list */
6097 width = (int)parameters[width].data.number.as_signed;
6098 }
6099 /* Find base */
6100 base = parameters[i].base;
6101 if (flags & FLAGS_BASE_PARAMETER)
6102 {
6103 /* Get base from parameter list */
6104 base = (int)parameters[base].data.number.as_signed;
6105 }
6106
6107 switch (parameters[i].type)
6108 {
6109 case FORMAT_INT:
6110 {
6111 trio_uintmax_t number;
6112
6113 if (0 == base)
6114 base = BASE_DECIMAL;
6115
6116 if (!TrioReadNumber(data,
6117 &number,
6118 flags,
6119 width,
6120 base))
6121 return assignment;
6122
6123 if (!(flags & FLAGS_IGNORE))
6124 {
6125 assignment++;
6126
6127 pointer = parameters[i].data.pointer;
6128 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6129 if (flags & FLAGS_SIZE_T)
6130 *(size_t *)pointer = (size_t)number;
6131 else
6132 #endif
6133 #if defined(QUALIFIER_PTRDIFF_T)
6134 if (flags & FLAGS_PTRDIFF_T)
6135 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6136 else
6137 #endif
6138 #if defined(QUALIFIER_INTMAX_T)
6139 if (flags & FLAGS_INTMAX_T)
6140 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
6141 else
6142 #endif
6143 if (flags & FLAGS_QUAD)
6144 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
6145 else if (flags & FLAGS_LONG)
6146 *(long int *)pointer = (long int)number;
6147 else if (flags & FLAGS_SHORT)
6148 *(short int *)pointer = (short int)number;
6149 else
6150 *(int *)pointer = (int)number;
6151 }
6152 }
6153 break; /* FORMAT_INT */
6154
6155 case FORMAT_STRING:
6156 #if TRIO_WIDECHAR
6157 if (flags & FLAGS_WIDECHAR)
6158 {
6159 if (!TrioReadWideString(data,
6160 (flags & FLAGS_IGNORE)
6161 ? NULL
6162 : parameters[i].data.wstring,
6163 flags,
6164 width))
6165 return assignment;
6166 }
6167 else
6168 #endif
6169 {
6170 if (!TrioReadString(data,
6171 (flags & FLAGS_IGNORE)
6172 ? NULL
6173 : parameters[i].data.string,
6174 flags,
6175 width))
6176 return assignment;
6177 }
6178 if (!(flags & FLAGS_IGNORE))
6179 assignment++;
6180 break; /* FORMAT_STRING */
6181
6182 case FORMAT_DOUBLE:
6183 {
6184 trio_pointer_t pointer;
6185
6186 if (flags & FLAGS_IGNORE)
6187 {
6188 pointer = NULL;
6189 }
6190 else
6191 {
6192 pointer = (flags & FLAGS_LONGDOUBLE)
6193 ? (trio_pointer_t)parameters[i].data.longdoublePointer
6194 : (trio_pointer_t)parameters[i].data.doublePointer;
6195 }
6196 if (!TrioReadDouble(data, pointer, flags, width))
6197 {
6198 return assignment;
6199 }
6200 if (!(flags & FLAGS_IGNORE))
6201 {
6202 assignment++;
6203 }
6204 break; /* FORMAT_DOUBLE */
6205 }
6206 case FORMAT_GROUP:
6207 {
6208 int characterclass[MAX_CHARACTER_CLASS + 1];
6209 int rc;
6210
6211 /* Skip over modifiers */
6212 while (format[index] != SPECIFIER_GROUP)
6213 {
6214 index++;
6215 }
6216 /* Skip over group specifier */
6217 index++;
6218
6219 memset(characterclass, 0, sizeof(characterclass));
6220 rc = TrioGetCharacterClass(format,
6221 &index,
6222 &flags,
6223 characterclass);
6224 if (rc < 0)
6225 return rc;
6226
6227 if (!TrioReadGroup(data,
6228 (flags & FLAGS_IGNORE)
6229 ? NULL
6230 : parameters[i].data.string,
6231 characterclass,
6232 flags,
6233 parameters[i].width))
6234 return assignment;
6235 if (!(flags & FLAGS_IGNORE))
6236 assignment++;
6237 }
6238 break; /* FORMAT_GROUP */
6239
6240 case FORMAT_COUNT:
6241 pointer = parameters[i].data.pointer;
6242 if (NULL != pointer)
6243 {
6244 int count = data->committed;
6245 if (ch != EOF)
6246 count--; /* a character is read, but is not consumed yet */
6247 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
6248 if (flags & FLAGS_SIZE_T)
6249 *(size_t *)pointer = (size_t)count;
6250 else
6251 #endif
6252 #if defined(QUALIFIER_PTRDIFF_T)
6253 if (flags & FLAGS_PTRDIFF_T)
6254 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
6255 else
6256 #endif
6257 #if defined(QUALIFIER_INTMAX_T)
6258 if (flags & FLAGS_INTMAX_T)
6259 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
6260 else
6261 #endif
6262 if (flags & FLAGS_QUAD)
6263 {
6264 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
6265 }
6266 else if (flags & FLAGS_LONG)
6267 {
6268 *(long int *)pointer = (long int)count;
6269 }
6270 else if (flags & FLAGS_SHORT)
6271 {
6272 *(short int *)pointer = (short int)count;
6273 }
6274 else
6275 {
6276 *(int *)pointer = (int)count;
6277 }
6278 }
6279 break; /* FORMAT_COUNT */
6280
6281 case FORMAT_CHAR:
6282 #if TRIO_WIDECHAR
6283 if (flags & FLAGS_WIDECHAR)
6284 {
6285 if (TrioReadWideChar(data,
6286 (flags & FLAGS_IGNORE)
6287 ? NULL
6288 : parameters[i].data.wstring,
6289 flags,
6290 (width == NO_WIDTH) ? 1 : width) == 0)
6291 return assignment;
6292 }
6293 else
6294 #endif
6295 {
6296 if (TrioReadChar(data,
6297 (flags & FLAGS_IGNORE)
6298 ? NULL
6299 : parameters[i].data.string,
6300 flags,
6301 (width == NO_WIDTH) ? 1 : width) == 0)
6302 return assignment;
6303 }
6304 if (!(flags & FLAGS_IGNORE))
6305 assignment++;
6306 break; /* FORMAT_CHAR */
6307
6308 case FORMAT_POINTER:
6309 if (!TrioReadPointer(data,
6310 (flags & FLAGS_IGNORE)
6311 ? NULL
6312 : (trio_pointer_t *)parameters[i].data.pointer,
6313 flags))
6314 return assignment;
6315 if (!(flags & FLAGS_IGNORE))
6316 assignment++;
6317 break; /* FORMAT_POINTER */
6318
6319 case FORMAT_PARAMETER:
6320 break; /* FORMAT_PARAMETER */
6321
6322 default:
6323 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
6324 }
6325 ch = data->current;
6326 index = parameters[i].indexAfterSpecifier;
6327 i++;
6328 }
6329 else /* Not an % identifier */
6330 {
6331 if (isspace((int)format[index]))
6332 {
6333 /* Whitespaces may match any amount of whitespaces */
6334 ch = TrioSkipWhitespaces(data);
6335 }
6336 else if (ch == format[index])
6337 {
6338 data->InStream(data, &ch);
6339 }
6340 else
6341 return assignment;
6342
6343 index++;
6344 }
6345 }
6346 return assignment;
6347 }
6348
6349 /*************************************************************************
6350 * TrioScan
6351 */
6352 TRIO_PRIVATE int
6353 TrioScan
6354 TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
6355 trio_pointer_t source,
6356 size_t sourceSize,
6357 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
6358 TRIO_CONST char *format,
6359 va_list *arglist,
6360 trio_pointer_t *argarray)
6361 {
6362 int status;
6363 trio_parameter_t parameters[MAX_PARAMETERS];
6364 trio_class_t data;
6365
6366 assert(VALID(InStream));
6367 assert(VALID(format));
6368
6369 memset(&data, 0, sizeof(data));
6370 data.InStream = InStream;
6371 data.location = (trio_pointer_t)source;
6372 data.max = sourceSize;
6373 data.error = 0;
6374
6375 #if defined(USE_LOCALE)
6376 if (NULL == internalLocaleValues)
6377 {
6378 TrioSetLocale();
6379 }
6380 #endif
6381
6382 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
6383 if (status < 0)
6384 return status;
6385
6386 status = TrioScanProcess(&data, format, parameters);
6387 if (data.error != 0)
6388 {
6389 status = data.error;
6390 }
6391 return status;
6392 }
6393
6394 /*************************************************************************
6395 * TrioInStreamFile
6396 */
6397 TRIO_PRIVATE void
6398 TrioInStreamFile
6399 TRIO_ARGS2((self, intPointer),
6400 trio_class_t *self,
6401 int *intPointer)
6402 {
6403 FILE *file = (FILE *)self->location;
6404
6405 assert(VALID(self));
6406 assert(VALID(file));
6407
6408 self->current = fgetc(file);
6409 if (self->current == EOF)
6410 {
6411 self->error = (ferror(file))
6412 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
6413 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
6414 }
6415 else
6416 {
6417 self->processed++;
6418 self->committed++;
6419 }
6420
6421 if (VALID(intPointer))
6422 {
6423 *intPointer = self->current;
6424 }
6425 }
6426
6427 /*************************************************************************
6428 * TrioInStreamFileDescriptor
6429 */
6430 TRIO_PRIVATE void
6431 TrioInStreamFileDescriptor
6432 TRIO_ARGS2((self, intPointer),
6433 trio_class_t *self,
6434 int *intPointer)
6435 {
6436 int fd = *((int *)self->location);
6437 int size;
6438 unsigned char input;
6439
6440 assert(VALID(self));
6441
6442 size = read(fd, &input, sizeof(char));
6443 if (size == -1)
6444 {
6445 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
6446 self->current = EOF;
6447 }
6448 else
6449 {
6450 self->current = (size == 0) ? EOF : input;
6451 }
6452 if (self->current != EOF)
6453 {
6454 self->committed++;
6455 self->processed++;
6456 }
6457
6458 if (VALID(intPointer))
6459 {
6460 *intPointer = self->current;
6461 }
6462 }
6463
6464 /*************************************************************************
6465 * TrioInStreamCustom
6466 */
6467 TRIO_PRIVATE void
6468 TrioInStreamCustom
6469 TRIO_ARGS2((self, intPointer),
6470 trio_class_t *self,
6471 int *intPointer)
6472 {
6473 trio_custom_t *data;
6474
6475 assert(VALID(self));
6476 assert(VALID(self->location));
6477
6478 data = (trio_custom_t *)self->location;
6479
6480 self->current = (data->stream.in == NULL)
6481 ? NIL
6482 : (data->stream.in)(data->closure);
6483
6484 if (self->current == NIL)
6485 {
6486 self->current = EOF;
6487 }
6488 else
6489 {
6490 self->processed++;
6491 self->committed++;
6492 }
6493
6494 if (VALID(intPointer))
6495 {
6496 *intPointer = self->current;
6497 }
6498 }
6499
6500 /*************************************************************************
6501 * TrioInStreamString
6502 */
6503 TRIO_PRIVATE void
6504 TrioInStreamString
6505 TRIO_ARGS2((self, intPointer),
6506 trio_class_t *self,
6507 int *intPointer)
6508 {
6509 unsigned char **buffer;
6510
6511 assert(VALID(self));
6512 assert(VALID(self->location));
6513
6514 buffer = (unsigned char **)self->location;
6515 self->current = (*buffer)[0];
6516 if (self->current == NIL)
6517 {
6518 self->current = EOF;
6519 }
6520 else
6521 {
6522 (*buffer)++;
6523 self->processed++;
6524 self->committed++;
6525 }
6526
6527 if (VALID(intPointer))
6528 {
6529 *intPointer = self->current;
6530 }
6531 }
6532
6533 /*************************************************************************
6534 *
6535 * Formatted scanning functions
6536 *
6537 ************************************************************************/
6538
6539 #if defined(TRIO_DOCUMENTATION)
6540 # include "doc/doc_scanf.h"
6541 #endif
6542 /** @addtogroup Scanf
6543 @{
6544 */
6545
6546 /*************************************************************************
6547 * scanf
6548 */
6549
6550 /**
6551 Scan characters from standard input stream.
6552
6553 @param format Formatting string.
6554 @param ... Arguments.
6555 @return Number of scanned characters.
6556 */
6557 TRIO_PUBLIC int
6558 trio_scanf
6559 TRIO_VARGS2((format, va_alist),
6560 TRIO_CONST char *format,
6561 TRIO_VA_DECL)
6562 {
6563 int status;
6564 va_list args;
6565
6566 assert(VALID(format));
6567
6568 TRIO_VA_START(args, format);
6569 status = TrioScan((trio_pointer_t)stdin, 0,
6570 TrioInStreamFile,
6571 format, &args, NULL);
6572 TRIO_VA_END(args);
6573 return status;
6574 }
6575
6576 TRIO_PUBLIC int
6577 trio_vscanf
6578 TRIO_ARGS2((format, args),
6579 TRIO_CONST char *format,
6580 va_list args)
6581 {
6582 assert(VALID(format));
6583
6584 return TrioScan((trio_pointer_t)stdin, 0,
6585 TrioInStreamFile,
6586 format, &args, NULL);
6587 }
6588
6589 TRIO_PUBLIC int
6590 trio_scanfv
6591 TRIO_ARGS2((format, args),
6592 TRIO_CONST char *format,
6593 trio_pointer_t *args)
6594 {
6595 assert(VALID(format));
6596
6597 return TrioScan((trio_pointer_t)stdin, 0,
6598 TrioInStreamFile,
6599 format, NULL, args);
6600 }
6601
6602 /*************************************************************************
6603 * fscanf
6604 */
6605 TRIO_PUBLIC int
6606 trio_fscanf
6607 TRIO_VARGS3((file, format, va_alist),
6608 FILE *file,
6609 TRIO_CONST char *format,
6610 TRIO_VA_DECL)
6611 {
6612 int status;
6613 va_list args;
6614
6615 assert(VALID(file));
6616 assert(VALID(format));
6617
6618 TRIO_VA_START(args, format);
6619 status = TrioScan((trio_pointer_t)file, 0,
6620 TrioInStreamFile,
6621 format, &args, NULL);
6622 TRIO_VA_END(args);
6623 return status;
6624 }
6625
6626 TRIO_PUBLIC int
6627 trio_vfscanf
6628 TRIO_ARGS3((file, format, args),
6629 FILE *file,
6630 TRIO_CONST char *format,
6631 va_list args)
6632 {
6633 assert(VALID(file));
6634 assert(VALID(format));
6635
6636 return TrioScan((trio_pointer_t)file, 0,
6637 TrioInStreamFile,
6638 format, &args, NULL);
6639 }
6640
6641 TRIO_PUBLIC int
6642 trio_fscanfv
6643 TRIO_ARGS3((file, format, args),
6644 FILE *file,
6645 TRIO_CONST char *format,
6646 trio_pointer_t *args)
6647 {
6648 assert(VALID(file));
6649 assert(VALID(format));
6650
6651 return TrioScan((trio_pointer_t)file, 0,
6652 TrioInStreamFile,
6653 format, NULL, args);
6654 }
6655
6656 /*************************************************************************
6657 * dscanf
6658 */
6659 TRIO_PUBLIC int
6660 trio_dscanf
6661 TRIO_VARGS3((fd, format, va_alist),
6662 int fd,
6663 TRIO_CONST char *format,
6664 TRIO_VA_DECL)
6665 {
6666 int status;
6667 va_list args;
6668
6669 assert(VALID(format));
6670
6671 TRIO_VA_START(args, format);
6672 status = TrioScan((trio_pointer_t)&fd, 0,
6673 TrioInStreamFileDescriptor,
6674 format, &args, NULL);
6675 TRIO_VA_END(args);
6676 return status;
6677 }
6678
6679 TRIO_PUBLIC int
6680 trio_vdscanf
6681 TRIO_ARGS3((fd, format, args),
6682 int fd,
6683 TRIO_CONST char *format,
6684 va_list args)
6685 {
6686 assert(VALID(format));
6687
6688 return TrioScan((trio_pointer_t)&fd, 0,
6689 TrioInStreamFileDescriptor,
6690 format, &args, NULL);
6691 }
6692
6693 TRIO_PUBLIC int
6694 trio_dscanfv
6695 TRIO_ARGS3((fd, format, args),
6696 int fd,
6697 TRIO_CONST char *format,
6698 trio_pointer_t *args)
6699 {
6700 assert(VALID(format));
6701
6702 return TrioScan((trio_pointer_t)&fd, 0,
6703 TrioInStreamFileDescriptor,
6704 format, NULL, args);
6705 }
6706
6707 /*************************************************************************
6708 * cscanf
6709 */
6710 TRIO_PUBLIC int
6711 trio_cscanf
6712 TRIO_VARGS4((stream, closure, format, va_alist),
6713 trio_instream_t stream,
6714 trio_pointer_t closure,
6715 TRIO_CONST char *format,
6716 TRIO_VA_DECL)
6717 {
6718 int status;
6719 va_list args;
6720 trio_custom_t data;
6721
6722 assert(VALID(stream));
6723 assert(VALID(format));
6724
6725 TRIO_VA_START(args, format);
6726 data.stream.in = stream;
6727 data.closure = closure;
6728 status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6729 TRIO_VA_END(args);
6730 return status;
6731 }
6732
6733 TRIO_PUBLIC int
6734 trio_vcscanf
6735 TRIO_ARGS4((stream, closure, format, args),
6736 trio_instream_t stream,
6737 trio_pointer_t closure,
6738 TRIO_CONST char *format,
6739 va_list args)
6740 {
6741 trio_custom_t data;
6742
6743 assert(VALID(stream));
6744 assert(VALID(format));
6745
6746 data.stream.in = stream;
6747 data.closure = closure;
6748 return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
6749 }
6750
6751 TRIO_PUBLIC int
6752 trio_cscanfv
6753 TRIO_ARGS4((stream, closure, format, args),
6754 trio_instream_t stream,
6755 trio_pointer_t closure,
6756 TRIO_CONST char *format,
6757 trio_pointer_t *args)
6758 {
6759 trio_custom_t data;
6760
6761 assert(VALID(stream));
6762 assert(VALID(format));
6763
6764 data.stream.in = stream;
6765 data.closure = closure;
6766 return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
6767 }
6768
6769 /*************************************************************************
6770 * sscanf
6771 */
6772 TRIO_PUBLIC int
6773 trio_sscanf
6774 TRIO_VARGS3((buffer, format, va_alist),
6775 TRIO_CONST char *buffer,
6776 TRIO_CONST char *format,
6777 TRIO_VA_DECL)
6778 {
6779 int status;
6780 va_list args;
6781
6782 assert(VALID(buffer));
6783 assert(VALID(format));
6784
6785 TRIO_VA_START(args, format);
6786 status = TrioScan((trio_pointer_t)&buffer, 0,
6787 TrioInStreamString,
6788 format, &args, NULL);
6789 TRIO_VA_END(args);
6790 return status;
6791 }
6792
6793 TRIO_PUBLIC int
6794 trio_vsscanf
6795 TRIO_ARGS3((buffer, format, args),
6796 TRIO_CONST char *buffer,
6797 TRIO_CONST char *format,
6798 va_list args)
6799 {
6800 assert(VALID(buffer));
6801 assert(VALID(format));
6802
6803 return TrioScan((trio_pointer_t)&buffer, 0,
6804 TrioInStreamString,
6805 format, &args, NULL);
6806 }
6807
6808 TRIO_PUBLIC int
6809 trio_sscanfv
6810 TRIO_ARGS3((buffer, format, args),
6811 TRIO_CONST char *buffer,
6812 TRIO_CONST char *format,
6813 trio_pointer_t *args)
6814 {
6815 assert(VALID(buffer));
6816 assert(VALID(format));
6817
6818 return TrioScan((trio_pointer_t)&buffer, 0,
6819 TrioInStreamString,
6820 format, NULL, args);
6821 }
6822
6823 /** @} End of Scanf documentation module */
6824
6825 /*************************************************************************
6826 * trio_strerror
6827 */
6828 TRIO_PUBLIC TRIO_CONST char *
6829 trio_strerror
6830 TRIO_ARGS1((errorcode),
6831 int errorcode)
6832 {
6833 /* Textual versions of the error codes */
6834 switch (TRIO_ERROR_CODE(errorcode))
6835 {
6836 case TRIO_EOF:
6837 return "End of file";
6838 case TRIO_EINVAL:
6839 return "Invalid argument";
6840 case TRIO_ETOOMANY:
6841 return "Too many arguments";
6842 case TRIO_EDBLREF:
6843 return "Double reference";
6844 case TRIO_EGAP:
6845 return "Reference gap";
6846 case TRIO_ENOMEM:
6847 return "Out of memory";
6848 case TRIO_ERANGE:
6849 return "Invalid range";
6850 case TRIO_ECUSTOM:
6851 return "Custom error";
6852 default:
6853 return "Unknown";
6854 }
6855 }
6856