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