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