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