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