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