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 <trio/triodef.h>
48 #include <trio/trio.h>
49 #include <trio/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 <trio/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 <trio/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 /* Mednafen modification to fix a gcc warning */
5030 /*TRIO_CONST*/ trio_pointer_t
5031 trio_get_argument
5032 TRIO_ARGS1((ref),
5033 trio_pointer_t ref)
5034 {
5035 #if TRIO_FEATURE_USER_DEFINED
5036 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
5037 #endif
5038
5039 return ((trio_reference_t *)ref)->parameter->data.pointer;
5040 }
5041
5042 /*************************************************************************
5043 * trio_get_width / trio_set_width [public]
5044 */
5045 int
5046 trio_get_width
5047 TRIO_ARGS1((ref),
5048 trio_pointer_t ref)
5049 {
5050 return ((trio_reference_t *)ref)->parameter->width;
5051 }
5052
5053 void
5054 trio_set_width
5055 TRIO_ARGS2((ref, width),
5056 trio_pointer_t ref,
5057 int width)
5058 {
5059 ((trio_reference_t *)ref)->parameter->width = width;
5060 }
5061
5062 /*************************************************************************
5063 * trio_get_precision / trio_set_precision [public]
5064 */
5065 int
5066 trio_get_precision
5067 TRIO_ARGS1((ref),
5068 trio_pointer_t ref)
5069 {
5070 return (((trio_reference_t *)ref)->parameter->precision);
5071 }
5072
5073 void
5074 trio_set_precision
5075 TRIO_ARGS2((ref, precision),
5076 trio_pointer_t ref,
5077 int precision)
5078 {
5079 ((trio_reference_t *)ref)->parameter->precision = precision;
5080 }
5081
5082 /*************************************************************************
5083 * trio_get_base / trio_set_base [public]
5084 */
5085 int
5086 trio_get_base
5087 TRIO_ARGS1((ref),
5088 trio_pointer_t ref)
5089 {
5090 return (((trio_reference_t *)ref)->parameter->base);
5091 }
5092
5093 void
5094 trio_set_base
5095 TRIO_ARGS2((ref, base),
5096 trio_pointer_t ref,
5097 int base)
5098 {
5099 ((trio_reference_t *)ref)->parameter->base = base;
5100 }
5101
5102 /*************************************************************************
5103 * trio_get_long / trio_set_long [public]
5104 */
5105 int
5106 trio_get_long
5107 TRIO_ARGS1((ref),
5108 trio_pointer_t ref)
5109 {
5110 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
5111 ? TRUE
5112 : FALSE;
5113 }
5114
5115 void
5116 trio_set_long
5117 TRIO_ARGS2((ref, is_long),
5118 trio_pointer_t ref,
5119 int is_long)
5120 {
5121 if (is_long)
5122 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
5123 else
5124 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
5125 }
5126
5127 /*************************************************************************
5128 * trio_get_longlong / trio_set_longlong [public]
5129 */
5130 int
5131 trio_get_longlong
5132 TRIO_ARGS1((ref),
5133 trio_pointer_t ref)
5134 {
5135 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
5136 ? TRUE
5137 : FALSE;
5138 }
5139
5140 void
5141 trio_set_longlong
5142 TRIO_ARGS2((ref, is_longlong),
5143 trio_pointer_t ref,
5144 int is_longlong)
5145 {
5146 if (is_longlong)
5147 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
5148 else
5149 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
5150 }
5151
5152 /*************************************************************************
5153 * trio_get_longdouble / trio_set_longdouble [public]
5154 */
5155 # if TRIO_FEATURE_FLOAT
5156 int
5157 trio_get_longdouble
5158 TRIO_ARGS1((ref),
5159 trio_pointer_t ref)
5160 {
5161 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
5162 ? TRUE
5163 : FALSE;
5164 }
5165
5166 void
5167 trio_set_longdouble
5168 TRIO_ARGS2((ref, is_longdouble),
5169 trio_pointer_t ref,
5170 int is_longdouble)
5171 {
5172 if (is_longdouble)
5173 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
5174 else
5175 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
5176 }
5177 # endif /* TRIO_FEATURE_FLOAT */
5178
5179 /*************************************************************************
5180 * trio_get_short / trio_set_short [public]
5181 */
5182 int
5183 trio_get_short
5184 TRIO_ARGS1((ref),
5185 trio_pointer_t ref)
5186 {
5187 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
5188 ? TRUE
5189 : FALSE;
5190 }
5191
5192 void
5193 trio_set_short
5194 TRIO_ARGS2((ref, is_short),
5195 trio_pointer_t ref,
5196 int is_short)
5197 {
5198 if (is_short)
5199 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
5200 else
5201 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
5202 }
5203
5204 /*************************************************************************
5205 * trio_get_shortshort / trio_set_shortshort [public]
5206 */
5207 int
5208 trio_get_shortshort
5209 TRIO_ARGS1((ref),
5210 trio_pointer_t ref)
5211 {
5212 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
5213 ? TRUE
5214 : FALSE;
5215 }
5216
5217 void
5218 trio_set_shortshort
5219 TRIO_ARGS2((ref, is_shortshort),
5220 trio_pointer_t ref,
5221 int is_shortshort)
5222 {
5223 if (is_shortshort)
5224 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
5225 else
5226 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
5227 }
5228
5229 /*************************************************************************
5230 * trio_get_alternative / trio_set_alternative [public]
5231 */
5232 int
5233 trio_get_alternative
5234 TRIO_ARGS1((ref),
5235 trio_pointer_t ref)
5236 {
5237 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
5238 ? TRUE
5239 : FALSE;
5240 }
5241
5242 void
5243 trio_set_alternative
5244 TRIO_ARGS2((ref, is_alternative),
5245 trio_pointer_t ref,
5246 int is_alternative)
5247 {
5248 if (is_alternative)
5249 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
5250 else
5251 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
5252 }
5253
5254 /*************************************************************************
5255 * trio_get_alignment / trio_set_alignment [public]
5256 */
5257 int
5258 trio_get_alignment
5259 TRIO_ARGS1((ref),
5260 trio_pointer_t ref)
5261 {
5262 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
5263 ? TRUE
5264 : FALSE;
5265 }
5266
5267 void
5268 trio_set_alignment
5269 TRIO_ARGS2((ref, is_leftaligned),
5270 trio_pointer_t ref,
5271 int is_leftaligned)
5272 {
5273 if (is_leftaligned)
5274 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
5275 else
5276 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
5277 }
5278
5279 /*************************************************************************
5280 * trio_get_spacing /trio_set_spacing [public]
5281 */
5282 int
5283 trio_get_spacing
5284 TRIO_ARGS1((ref),
5285 trio_pointer_t ref)
5286 {
5287 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
5288 ? TRUE
5289 : FALSE;
5290 }
5291
5292 void
5293 trio_set_spacing
5294 TRIO_ARGS2((ref, is_space),
5295 trio_pointer_t ref,
5296 int is_space)
5297 {
5298 if (is_space)
5299 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
5300 else
5301 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
5302 }
5303
5304 /*************************************************************************
5305 * trio_get_sign / trio_set_sign [public]
5306 */
5307 int
5308 trio_get_sign
5309 TRIO_ARGS1((ref),
5310 trio_pointer_t ref)
5311 {
5312 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
5313 ? TRUE
5314 : FALSE;
5315 }
5316
5317 void
5318 trio_set_sign
5319 TRIO_ARGS2((ref, is_sign),
5320 trio_pointer_t ref,
5321 int is_sign)
5322 {
5323 if (is_sign)
5324 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
5325 else
5326 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
5327 }
5328
5329 /*************************************************************************
5330 * trio_get_padding / trio_set_padding [public]
5331 */
5332 int
5333 trio_get_padding
5334 TRIO_ARGS1((ref),
5335 trio_pointer_t ref)
5336 {
5337 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
5338 ? TRUE
5339 : FALSE;
5340 }
5341
5342 void
5343 trio_set_padding
5344 TRIO_ARGS2((ref, is_padding),
5345 trio_pointer_t ref,
5346 int is_padding)
5347 {
5348 if (is_padding)
5349 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
5350 else
5351 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
5352 }
5353
5354 /*************************************************************************
5355 * trio_get_quote / trio_set_quote [public]
5356 */
5357 # if TRIO_FEATURE_QUOTE
5358 int
5359 trio_get_quote
5360 TRIO_ARGS1((ref),
5361 trio_pointer_t ref)
5362 {
5363 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
5364 ? TRUE
5365 : FALSE;
5366 }
5367
5368 void
5369 trio_set_quote
5370 TRIO_ARGS2((ref, is_quote),
5371 trio_pointer_t ref,
5372 int is_quote)
5373 {
5374 if (is_quote)
5375 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
5376 else
5377 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
5378 }
5379 #endif /* TRIO_FEATURE_QUOTE */
5380
5381 /*************************************************************************
5382 * trio_get_upper / trio_set_upper [public]
5383 */
5384 int
5385 trio_get_upper
5386 TRIO_ARGS1((ref),
5387 trio_pointer_t ref)
5388 {
5389 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
5390 ? TRUE
5391 : FALSE;
5392 }
5393
5394 void
5395 trio_set_upper
5396 TRIO_ARGS2((ref, is_upper),
5397 trio_pointer_t ref,
5398 int is_upper)
5399 {
5400 if (is_upper)
5401 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
5402 else
5403 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
5404 }
5405
5406 /*************************************************************************
5407 * trio_get_largest / trio_set_largest [public]
5408 */
5409 #if TRIO_FEATURE_INTMAX_T
5410 int
5411 trio_get_largest
5412 TRIO_ARGS1((ref),
5413 trio_pointer_t ref)
5414 {
5415 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
5416 ? TRUE
5417 : FALSE;
5418 }
5419
5420 void
5421 trio_set_largest
5422 TRIO_ARGS2((ref, is_largest),
5423 trio_pointer_t ref,
5424 int is_largest)
5425 {
5426 if (is_largest)
5427 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
5428 else
5429 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
5430 }
5431 #endif /* TRIO_FEATURE_INTMAX_T */
5432
5433 /*************************************************************************
5434 * trio_get_ptrdiff / trio_set_ptrdiff [public]
5435 */
5436 #if TRIO_FEATURE_PTRDIFF_T
5437 int
5438 trio_get_ptrdiff
5439 TRIO_ARGS1((ref),
5440 trio_pointer_t ref)
5441 {
5442 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
5443 ? TRUE
5444 : FALSE;
5445 }
5446
5447 void
5448 trio_set_ptrdiff
5449 TRIO_ARGS2((ref, is_ptrdiff),
5450 trio_pointer_t ref,
5451 int is_ptrdiff)
5452 {
5453 if (is_ptrdiff)
5454 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
5455 else
5456 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
5457 }
5458 #endif /* TRIO_FEATURE_PTRDIFF_T */
5459
5460 /*************************************************************************
5461 * trio_get_size / trio_set_size [public]
5462 */
5463 #if TRIO_FEATURE_SIZE_T
5464 int
5465 trio_get_size
5466 TRIO_ARGS1((ref),
5467 trio_pointer_t ref)
5468 {
5469 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
5470 ? TRUE
5471 : FALSE;
5472 }
5473
5474 void
5475 trio_set_size
5476 TRIO_ARGS2((ref, is_size),
5477 trio_pointer_t ref,
5478 int is_size)
5479 {
5480 if (is_size)
5481 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
5482 else
5483 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
5484 }
5485 #endif /* TRIO_FEATURE_SIZE_T */
5486
5487 /*************************************************************************
5488 * trio_print_int [public]
5489 */
5490 void
5491 trio_print_int
5492 TRIO_ARGS2((ref, number),
5493 trio_pointer_t ref,
5494 int number)
5495 {
5496 trio_reference_t *self = (trio_reference_t *)ref;
5497
5498 TrioWriteNumber(self->data,
5499 (trio_uintmax_t)number,
5500 self->parameter->flags,
5501 self->parameter->width,
5502 self->parameter->precision,
5503 self->parameter->base);
5504 }
5505
5506 /*************************************************************************
5507 * trio_print_uint [public]
5508 */
5509 void
5510 trio_print_uint
5511 TRIO_ARGS2((ref, number),
5512 trio_pointer_t ref,
5513 unsigned int number)
5514 {
5515 trio_reference_t *self = (trio_reference_t *)ref;
5516
5517 TrioWriteNumber(self->data,
5518 (trio_uintmax_t)number,
5519 self->parameter->flags | FLAGS_UNSIGNED,
5520 self->parameter->width,
5521 self->parameter->precision,
5522 self->parameter->base);
5523 }
5524
5525 /*************************************************************************
5526 * trio_print_double [public]
5527 */
5528 #if TRIO_FEATURE_FLOAT
5529 void
5530 trio_print_double
5531 TRIO_ARGS2((ref, number),
5532 trio_pointer_t ref,
5533 double number)
5534 {
5535 trio_reference_t *self = (trio_reference_t *)ref;
5536
5537 TrioWriteDouble(self->data,
5538 number,
5539 self->parameter->flags,
5540 self->parameter->width,
5541 self->parameter->precision,
5542 self->parameter->base);
5543 }
5544 #endif /* TRIO_FEATURE_FLOAT */
5545
5546 /*************************************************************************
5547 * trio_print_string [public]
5548 */
5549 void
5550 trio_print_string
5551 TRIO_ARGS2((ref, string),
5552 trio_pointer_t ref,
5553 TRIO_CONST char *string)
5554 {
5555 trio_reference_t *self = (trio_reference_t *)ref;
5556
5557 TrioWriteString(self->data,
5558 string,
5559 self->parameter->flags,
5560 self->parameter->width,
5561 self->parameter->precision);
5562 }
5563
5564 /*************************************************************************
5565 * trio_print_ref [public]
5566 */
5567 int
5568 trio_print_ref
5569 TRIO_VARGS3((ref, format, va_alist),
5570 trio_pointer_t ref,
5571 TRIO_CONST char *format,
5572 TRIO_VA_DECL)
5573 {
5574 int status;
5575 va_list arglist;
5576
5577 assert(VALID(format));
5578
5579 TRIO_VA_START(arglist, format);
5580 status = TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL);
5581 TRIO_VA_END(arglist);
5582 return status;
5583 }
5584
5585 /*************************************************************************
5586 * trio_vprint_ref [public]
5587 */
5588 int
5589 trio_vprint_ref
5590 TRIO_ARGS3((ref, format, arglist),
5591 trio_pointer_t ref,
5592 TRIO_CONST char *format,
5593 va_list arglist)
5594 {
5595 assert(VALID(format));
5596
5597 return TrioFormatRef((trio_reference_t *)ref, format, arglist, NULL);
5598 }
5599
5600 /*************************************************************************
5601 * trio_printv_ref [public]
5602 */
5603 int
5604 trio_printv_ref
5605 TRIO_ARGS3((ref, format, argarray),
5606 trio_pointer_t ref,
5607 TRIO_CONST char *format,
5608 trio_pointer_t *argarray)
5609 {
5610 static va_list unused;
5611
5612 assert(VALID(format));
5613
5614 return TrioFormatRef((trio_reference_t *)ref, format, unused, argarray);
5615 }
5616
5617 #endif
5618
5619 /*************************************************************************
5620 * trio_print_pointer [public]
5621 */
5622 void
5623 trio_print_pointer
5624 TRIO_ARGS2((ref, pointer),
5625 trio_pointer_t ref,
5626 trio_pointer_t pointer)
5627 {
5628 trio_reference_t *self = (trio_reference_t *)ref;
5629 trio_flags_t flags;
5630 trio_uintmax_t number;
5631
5632 if (NULL == pointer)
5633 {
5634 TRIO_CONST char *string = internalNullString;
5635 while (*string)
5636 self->data->OutStream(self->data, *string++);
5637 }
5638 else
5639 {
5640 /*
5641 * The subtraction of the null pointer is a workaround
5642 * to avoid a compiler warning. The performance overhead
5643 * is negligible (and likely to be removed by an
5644 * optimizing compiler). The (char *) casting is done
5645 * to please ANSI C++.
5646 */
5647 number = (trio_uintmax_t)((char *)pointer - (char *)0);
5648 /* Shrink to size of pointer */
5649 number &= (trio_uintmax_t)-1;
5650 flags = self->parameter->flags;
5651 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
5652 FLAGS_NILPADDING);
5653 TrioWriteNumber(self->data,
5654 number,
5655 flags,
5656 POINTER_WIDTH,
5657 NO_PRECISION,
5658 BASE_HEX);
5659 }
5660 }
5661
5662 /** @} End of UserDefined documentation module */
5663
5664 /*************************************************************************
5665 *
5666 * LOCALES
5667 *
5668 ************************************************************************/
5669
5670 /*************************************************************************
5671 * trio_locale_set_decimal_point
5672 *
5673 * Decimal point can only be one character. The input argument is a
5674 * string to enable multibyte characters. At most MB_LEN_MAX characters
5675 * will be used.
5676 */
5677 #if TRIO_FEATURE_LOCALE
5678 TRIO_PUBLIC void
5679 trio_locale_set_decimal_point
5680 TRIO_ARGS1((decimalPoint),
5681 char *decimalPoint)
5682 {
5683 #if defined(USE_LOCALE)
5684 if (NULL == internalLocaleValues)
5685 {
5686 TrioSetLocale();
5687 }
5688 #endif
5689 internalDecimalPointLength = trio_length(decimalPoint);
5690 if (internalDecimalPointLength == 1)
5691 {
5692 internalDecimalPoint = *decimalPoint;
5693 }
5694 else
5695 {
5696 internalDecimalPoint = NIL;
5697 trio_copy_max(internalDecimalPointString,
5698 sizeof(internalDecimalPointString),
5699 decimalPoint);
5700 }
5701 }
5702 #endif
5703
5704 /*************************************************************************
5705 * trio_locale_set_thousand_separator
5706 *
5707 * See trio_locale_set_decimal_point
5708 */
5709 #if TRIO_FEATURE_LOCALE || TRIO_EXTENSION
5710 TRIO_PUBLIC void
5711 trio_locale_set_thousand_separator
5712 TRIO_ARGS1((thousandSeparator),
5713 char *thousandSeparator)
5714 {
5715 # if defined(USE_LOCALE)
5716 if (NULL == internalLocaleValues)
5717 {
5718 TrioSetLocale();
5719 }
5720 # endif
5721 trio_copy_max(internalThousandSeparator,
5722 sizeof(internalThousandSeparator),
5723 thousandSeparator);
5724 internalThousandSeparatorLength = trio_length(internalThousandSeparator);
5725 }
5726 #endif
5727
5728 /*************************************************************************
5729 * trio_locale_set_grouping
5730 *
5731 * Array of bytes. Reversed order.
5732 *
5733 * CHAR_MAX : No further grouping
5734 * 0 : Repeat last group for the remaining digits (not necessary
5735 * as C strings are zero-terminated)
5736 * n : Set current group to n
5737 *
5738 * Same order as the grouping attribute in LC_NUMERIC.
5739 */
5740 #if TRIO_FEATURE_LOCALE || TRIO_EXTENSION
5741 TRIO_PUBLIC void
5742 trio_locale_set_grouping
5743 TRIO_ARGS1((grouping),
5744 char *grouping)
5745 {
5746 # if defined(USE_LOCALE)
5747 if (NULL == internalLocaleValues)
5748 {
5749 TrioSetLocale();
5750 }
5751 # endif
5752 trio_copy_max(internalGrouping,
5753 sizeof(internalGrouping),
5754 grouping);
5755 }
5756 #endif
5757
5758
5759 /*************************************************************************
5760 *
5761 * SCANNING
5762 *
5763 ************************************************************************/
5764
5765 #if TRIO_FEATURE_SCANF
5766
5767 /*************************************************************************
5768 * TrioSkipWhitespaces
5769 */
5770 TRIO_PRIVATE int
5771 TrioSkipWhitespaces
5772 TRIO_ARGS1((self),
5773 trio_class_t *self)
5774 {
5775 int ch;
5776
5777 ch = self->current;
5778 while (isspace(ch))
5779 {
5780 self->InStream(self, &ch);
5781 }
5782 return ch;
5783 }
5784
5785 /*************************************************************************
5786 * TrioGetCollation
5787 */
5788 #if TRIO_EXTENSION
5789 TRIO_PRIVATE void
TrioGetCollation(TRIO_NOARGS)5790 TrioGetCollation(TRIO_NOARGS)
5791 {
5792 int i;
5793 int j;
5794 int k;
5795 char first[2];
5796 char second[2];
5797
5798 /* This is computationally expensive */
5799 first[1] = NIL;
5800 second[1] = NIL;
5801 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5802 {
5803 k = 0;
5804 first[0] = (char)i;
5805 for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5806 {
5807 second[0] = (char)j;
5808 if (trio_equal_locale(first, second))
5809 internalCollationArray[i][k++] = (char)j;
5810 }
5811 internalCollationArray[i][k] = NIL;
5812 }
5813 }
5814 #endif
5815
5816 /*************************************************************************
5817 * TrioGetCharacterClass
5818 *
5819 * FIXME:
5820 * multibyte
5821 */
5822 TRIO_PRIVATE int
5823 TrioGetCharacterClass
5824 TRIO_ARGS4((format, offsetPointer, flagsPointer, characterclass),
5825 TRIO_CONST char *format,
5826 int *offsetPointer,
5827 trio_flags_t *flagsPointer,
5828 int *characterclass)
5829 {
5830 int offset = *offsetPointer;
5831 int i;
5832 char ch;
5833 char range_begin;
5834 char range_end;
5835
5836 *flagsPointer &= ~FLAGS_EXCLUDE;
5837
5838 if (format[offset] == QUALIFIER_CIRCUMFLEX)
5839 {
5840 *flagsPointer |= FLAGS_EXCLUDE;
5841 offset++;
5842 }
5843 /*
5844 * If the ungroup character is at the beginning of the scanlist,
5845 * it will be part of the class, and a second ungroup character
5846 * must follow to end the group.
5847 */
5848 if (format[offset] == SPECIFIER_UNGROUP)
5849 {
5850 characterclass[(int)SPECIFIER_UNGROUP]++;
5851 offset++;
5852 }
5853 /*
5854 * Minus is used to specify ranges. To include minus in the class,
5855 * it must be at the beginning of the list
5856 */
5857 if (format[offset] == QUALIFIER_MINUS)
5858 {
5859 characterclass[(int)QUALIFIER_MINUS]++;
5860 offset++;
5861 }
5862 /* Collect characters */
5863 for (ch = format[offset];
5864 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
5865 ch = format[++offset])
5866 {
5867 switch (ch)
5868 {
5869 case QUALIFIER_MINUS: /* Scanlist ranges */
5870
5871 /*
5872 * Both C99 and UNIX98 describes ranges as implementation-
5873 * defined.
5874 *
5875 * We support the following behaviour (although this may
5876 * change as we become wiser)
5877 * - only increasing ranges, ie. [a-b] but not [b-a]
5878 * - transitive ranges, ie. [a-b-c] == [a-c]
5879 * - trailing minus, ie. [a-] is interpreted as an 'a'
5880 * and a '-'
5881 * - duplicates (although we can easily convert these
5882 * into errors)
5883 */
5884 range_begin = format[offset - 1];
5885 range_end = format[++offset];
5886 if (range_end == SPECIFIER_UNGROUP)
5887 {
5888 /* Trailing minus is included */
5889 characterclass[(int)ch]++;
5890 ch = range_end;
5891 break; /* for */
5892 }
5893 if (range_end == NIL)
5894 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
5895 if (range_begin > range_end)
5896 return TRIO_ERROR_RETURN(TRIO_ERANGE, offset);
5897
5898 for (i = (int)range_begin; i <= (int)range_end; i++)
5899 characterclass[i]++;
5900
5901 ch = range_end;
5902 break;
5903
5904 #if TRIO_EXTENSION
5905
5906 case SPECIFIER_GROUP:
5907
5908 switch (format[offset + 1])
5909 {
5910 case QUALIFIER_DOT: /* Collating symbol */
5911 /*
5912 * FIXME: This will be easier to implement when multibyte
5913 * characters have been implemented. Until now, we ignore
5914 * this feature.
5915 */
5916 for (i = offset + 2; ; i++)
5917 {
5918 if (format[i] == NIL)
5919 /* Error in syntax */
5920 return -1;
5921 else if (format[i] == QUALIFIER_DOT)
5922 break; /* for */
5923 }
5924 if (format[++i] != SPECIFIER_UNGROUP)
5925 return -1;
5926
5927 offset = i;
5928 break;
5929
5930 case QUALIFIER_EQUAL: /* Equivalence class expressions */
5931 {
5932 unsigned int j;
5933 unsigned int k;
5934
5935 if (internalCollationUnconverted)
5936 {
5937 /* Lazy evaluation of collation array */
5938 TrioGetCollation();
5939 internalCollationUnconverted = FALSE;
5940 }
5941 for (i = offset + 2; ; i++)
5942 {
5943 if (format[i] == NIL)
5944 /* Error in syntax */
5945 return -1;
5946 else if (format[i] == QUALIFIER_EQUAL)
5947 break; /* for */
5948 else
5949 {
5950 /* Mark any equivalent character */
5951 k = (unsigned int)format[i];
5952 for (j = 0; internalCollationArray[k][j] != NIL; j++)
5953 characterclass[(int)internalCollationArray[k][j]]++;
5954 }
5955 }
5956 if (format[++i] != SPECIFIER_UNGROUP)
5957 return -1;
5958
5959 offset = i;
5960 }
5961 break;
5962
5963 case QUALIFIER_COLON: /* Character class expressions */
5964
5965 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5966 &format[offset]))
5967 {
5968 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5969 if (isalnum(i))
5970 characterclass[i]++;
5971 offset += sizeof(CLASS_ALNUM) - 1;
5972 }
5973 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5974 &format[offset]))
5975 {
5976 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5977 if (isalpha(i))
5978 characterclass[i]++;
5979 offset += sizeof(CLASS_ALPHA) - 1;
5980 }
5981 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5982 &format[offset]))
5983 {
5984 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5985 if (iscntrl(i))
5986 characterclass[i]++;
5987 offset += sizeof(CLASS_CNTRL) - 1;
5988 }
5989 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5990 &format[offset]))
5991 {
5992 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5993 if (isdigit(i))
5994 characterclass[i]++;
5995 offset += sizeof(CLASS_DIGIT) - 1;
5996 }
5997 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5998 &format[offset]))
5999 {
6000 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6001 if (isgraph(i))
6002 characterclass[i]++;
6003 offset += sizeof(CLASS_GRAPH) - 1;
6004 }
6005 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
6006 &format[offset]))
6007 {
6008 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6009 if (islower(i))
6010 characterclass[i]++;
6011 offset += sizeof(CLASS_LOWER) - 1;
6012 }
6013 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
6014 &format[offset]))
6015 {
6016 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6017 if (isprint(i))
6018 characterclass[i]++;
6019 offset += sizeof(CLASS_PRINT) - 1;
6020 }
6021 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
6022 &format[offset]))
6023 {
6024 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6025 if (ispunct(i))
6026 characterclass[i]++;
6027 offset += sizeof(CLASS_PUNCT) - 1;
6028 }
6029 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
6030 &format[offset]))
6031 {
6032 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6033 if (isspace(i))
6034 characterclass[i]++;
6035 offset += sizeof(CLASS_SPACE) - 1;
6036 }
6037 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
6038 &format[offset]))
6039 {
6040 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6041 if (isupper(i))
6042 characterclass[i]++;
6043 offset += sizeof(CLASS_UPPER) - 1;
6044 }
6045 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
6046 &format[offset]))
6047 {
6048 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
6049 if (isxdigit(i))
6050 characterclass[i]++;
6051 offset += sizeof(CLASS_XDIGIT) - 1;
6052 }
6053 else
6054 {
6055 characterclass[(int)ch]++;
6056 }
6057 break;
6058
6059 default:
6060 characterclass[(int)ch]++;
6061 break;
6062 }
6063 break;
6064
6065 #endif /* TRIO_EXTENSION */
6066
6067 default:
6068 characterclass[(int)ch]++;
6069 break;
6070 }
6071 }
6072 return 0;
6073 }
6074
6075 /*************************************************************************
6076 * TrioReadNumber
6077 *
6078 * We implement our own number conversion in preference of strtol and
6079 * strtoul, because we must handle 'long long' and thousand separators.
6080 */
6081 TRIO_PRIVATE BOOLEAN_T
6082 TrioReadNumber
6083 TRIO_ARGS5((self, target, flags, width, base),
6084 trio_class_t *self,
6085 trio_uintmax_t *target,
6086 trio_flags_t flags,
6087 int width,
6088 int base)
6089 {
6090 trio_uintmax_t number = 0;
6091 int digit;
6092 int count;
6093 BOOLEAN_T isNegative = FALSE;
6094 BOOLEAN_T gotNumber = FALSE;
6095 int j;
6096
6097 assert(VALID(self));
6098 assert(VALID(self->InStream));
6099 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
6100
6101 if (internalDigitsUnconverted)
6102 {
6103 /* Lazy evaluation of digits array */
6104 memset(internalDigitArray, -1, sizeof(internalDigitArray));
6105 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
6106 {
6107 internalDigitArray[(int)internalDigitsLower[j]] = j;
6108 internalDigitArray[(int)internalDigitsUpper[j]] = j;
6109 }
6110 internalDigitsUnconverted = FALSE;
6111 }
6112
6113 TrioSkipWhitespaces(self);
6114
6115 /* Leading sign */
6116 if (self->current == '+')
6117 {
6118 self->InStream(self, NULL);
6119 }
6120 else if (self->current == '-')
6121 {
6122 self->InStream(self, NULL);
6123 isNegative = TRUE;
6124 }
6125
6126 count = self->processed;
6127
6128 if (flags & FLAGS_ALTERNATIVE)
6129 {
6130 switch (base)
6131 {
6132 case NO_BASE:
6133 case BASE_OCTAL:
6134 case BASE_HEX:
6135 case BASE_BINARY:
6136 if (self->current == '0')
6137 {
6138 self->InStream(self, NULL);
6139 if (self->current)
6140 {
6141 if ((base == BASE_HEX) &&
6142 (trio_to_upper(self->current) == 'X'))
6143 {
6144 self->InStream(self, NULL);
6145 }
6146 else if ((base == BASE_BINARY) &&
6147 (trio_to_upper(self->current) == 'B'))
6148 {
6149 self->InStream(self, NULL);
6150 }
6151 }
6152 }
6153 else
6154 return FALSE;
6155 break;
6156 default:
6157 break;
6158 }
6159 }
6160
6161 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
6162 (! ((self->current == EOF) || isspace(self->current))))
6163 {
6164 if (isascii(self->current))
6165 {
6166 digit = internalDigitArray[self->current];
6167 /* Abort if digit is not allowed in the specified base */
6168 if ((digit == -1) || (digit >= base))
6169 break;
6170 }
6171 #if TRIO_FEATURE_QUOTE
6172 else if (flags & FLAGS_QUOTE)
6173 {
6174 /* Compare with thousands separator */
6175 for (j = 0; internalThousandSeparator[j] && self->current; j++)
6176 {
6177 if (internalThousandSeparator[j] != self->current)
6178 break;
6179
6180 self->InStream(self, NULL);
6181 }
6182 if (internalThousandSeparator[j])
6183 break; /* Mismatch */
6184 else
6185 continue; /* Match */
6186 }
6187 #endif
6188 else
6189 break;
6190
6191 number *= base;
6192 number += digit;
6193 gotNumber = TRUE; /* we need at least one digit */
6194
6195 self->InStream(self, NULL);
6196 }
6197
6198 /* Was anything read at all? */
6199 if (!gotNumber)
6200 return FALSE;
6201
6202 if (target)
6203 *target = (isNegative) ? (trio_uintmax_t)(-((trio_intmax_t)number)) : number;
6204 return TRUE;
6205 }
6206
6207 /*************************************************************************
6208 * TrioReadChar
6209 */
6210 TRIO_PRIVATE int
6211 TrioReadChar
6212 TRIO_ARGS4((self, target, flags, width),
6213 trio_class_t *self,
6214 char *target,
6215 trio_flags_t flags,
6216 int width)
6217 {
6218 int i;
6219 char ch;
6220 trio_uintmax_t number;
6221
6222 assert(VALID(self));
6223 assert(VALID(self->InStream));
6224
6225 for (i = 0;
6226 (self->current != EOF) && (i < width);
6227 i++)
6228 {
6229 ch = (char)self->current;
6230 self->InStream(self, NULL);
6231 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
6232 {
6233 switch (self->current)
6234 {
6235 case '\\': ch = '\\'; break;
6236 case 'a': ch = '\007'; break;
6237 case 'b': ch = '\b'; break;
6238 case 'f': ch = '\f'; break;
6239 case 'n': ch = '\n'; break;
6240 case 'r': ch = '\r'; break;
6241 case 't': ch = '\t'; break;
6242 case 'v': ch = '\v'; break;
6243 default:
6244 if (isdigit(self->current))
6245 {
6246 /* Read octal number */
6247 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
6248 return 0;
6249 ch = (char)number;
6250 }
6251 else if (trio_to_upper(self->current) == 'X')
6252 {
6253 /* Read hexadecimal number */
6254 self->InStream(self, NULL);
6255 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
6256 return 0;
6257 ch = (char)number;
6258 }
6259 else
6260 {
6261 ch = (char)self->current;
6262 }
6263 break;
6264 }
6265 }
6266
6267 if (target)
6268 target[i] = ch;
6269 }
6270 return i + 1;
6271 }
6272
6273 /*************************************************************************
6274 * TrioReadString
6275 */
6276 TRIO_PRIVATE BOOLEAN_T
6277 TrioReadString
6278 TRIO_ARGS4((self, target, flags, width),
6279 trio_class_t *self,
6280 char *target,
6281 trio_flags_t flags,
6282 int width)
6283 {
6284 int i;
6285
6286 assert(VALID(self));
6287 assert(VALID(self->InStream));
6288
6289 TrioSkipWhitespaces(self);
6290
6291 /*
6292 * Continue until end of string is reached, a whitespace is encountered,
6293 * or width is exceeded
6294 */
6295 for (i = 0;
6296 ((width == NO_WIDTH) || (i < width)) &&
6297 (! ((self->current == EOF) || isspace(self->current)));
6298 i++)
6299 {
6300 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
6301 break; /* for */
6302 }
6303 if (target)
6304 target[i] = NIL;
6305 return TRUE;
6306 }
6307
6308 /*************************************************************************
6309 * TrioReadWideChar
6310 */
6311 #if TRIO_FEATURE_WIDECHAR
6312 TRIO_PRIVATE int
6313 TrioReadWideChar
6314 TRIO_ARGS4((self, target, flags, width),
6315 trio_class_t *self,
6316 trio_wchar_t *target,
6317 trio_flags_t flags,
6318 int width)
6319 {
6320 int i;
6321 int j;
6322 int size;
6323 int amount = 0;
6324 trio_wchar_t wch;
6325 char buffer[MB_LEN_MAX + 1];
6326
6327 assert(VALID(self));
6328 assert(VALID(self->InStream));
6329
6330 for (i = 0;
6331 (self->current != EOF) && (i < width);
6332 i++)
6333 {
6334 if (isascii(self->current))
6335 {
6336 if (TrioReadChar(self, buffer, flags, 1) == 0)
6337 return 0;
6338 buffer[1] = NIL;
6339 }
6340 else
6341 {
6342 /*
6343 * Collect a multibyte character, by enlarging buffer until
6344 * it contains a fully legal multibyte character, or the
6345 * buffer is full.
6346 */
6347 j = 0;
6348 do
6349 {
6350 buffer[j++] = (char)self->current;
6351 buffer[j] = NIL;
6352 self->InStream(self, NULL);
6353 }
6354 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
6355 }
6356 if (target)
6357 {
6358 size = mbtowc(&wch, buffer, sizeof(buffer));
6359 if (size > 0)
6360 target[i] = wch;
6361 }
6362 amount += size;
6363 self->InStream(self, NULL);
6364 }
6365 return amount;
6366 }
6367 #endif /* TRIO_FEATURE_WIDECHAR */
6368
6369 /*************************************************************************
6370 * TrioReadWideString
6371 */
6372 #if TRIO_FEATURE_WIDECHAR
6373 TRIO_PRIVATE BOOLEAN_T
6374 TrioReadWideString
6375 TRIO_ARGS4((self, target, flags, width),
6376 trio_class_t *self,
6377 trio_wchar_t *target,
6378 trio_flags_t flags,
6379 int width)
6380 {
6381 int i;
6382 int size;
6383
6384 assert(VALID(self));
6385 assert(VALID(self->InStream));
6386
6387 TrioSkipWhitespaces(self);
6388
6389 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
6390 /* Required by TrioReadWideChar */
6391 (void)mblen(NULL, 0);
6392 #endif
6393
6394 /*
6395 * Continue until end of string is reached, a whitespace is encountered,
6396 * or width is exceeded
6397 */
6398 for (i = 0;
6399 ((width == NO_WIDTH) || (i < width)) &&
6400 (! ((self->current == EOF) || isspace(self->current)));
6401 )
6402 {
6403 size = TrioReadWideChar(self, &target[i], flags, 1);
6404 if (size == 0)
6405 break; /* for */
6406
6407 i += size;
6408 }
6409 if (target)
6410 target[i] = WCONST('\0');
6411 return TRUE;
6412 }
6413 #endif /* TRIO_FEATURE_WIDECHAR */
6414
6415 /*************************************************************************
6416 * TrioReadGroup
6417 *
6418 * Reads non-empty character groups.
6419 *
6420 * FIXME: characterclass does not work with multibyte characters
6421 */
6422 TRIO_PRIVATE BOOLEAN_T
6423 TrioReadGroup
6424 TRIO_ARGS5((self, target, characterclass, flags, width),
6425 trio_class_t *self,
6426 char *target,
6427 int *characterclass,
6428 trio_flags_t flags,
6429 int width)
6430 {
6431 int ch;
6432 int i;
6433
6434 assert(VALID(self));
6435 assert(VALID(self->InStream));
6436
6437 ch = self->current;
6438 for (i = 0;
6439 ((width == NO_WIDTH) || (i < width)) &&
6440 (! ((ch == EOF) ||
6441 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
6442 i++)
6443 {
6444 if (target)
6445 target[i] = (char)ch;
6446 self->InStream(self, &ch);
6447 }
6448
6449 if (i == 0)
6450 return FALSE;
6451
6452 /* Terminate the string if input saved */
6453 if (target)
6454 target[i] = NIL;
6455 return TRUE;
6456 }
6457
6458 /*************************************************************************
6459 * TrioReadDouble
6460 *
6461 * FIXME:
6462 * add long double
6463 * handle base
6464 */
6465 #if TRIO_FEATURE_FLOAT
6466 TRIO_PRIVATE BOOLEAN_T
6467 TrioReadDouble
6468 TRIO_ARGS4((self, target, flags, width),
6469 trio_class_t *self,
6470 trio_pointer_t target,
6471 trio_flags_t flags,
6472 int width)
6473 {
6474 int ch;
6475 char doubleString[512];
6476 int offset = 0;
6477 int start;
6478 # if TRIO_FEATURE_QUOTE
6479 int j;
6480 # endif
6481 BOOLEAN_T isHex = FALSE;
6482 trio_long_double_t infinity;
6483
6484 doubleString[0] = 0;
6485
6486 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
6487 width = sizeof(doubleString) - 1;
6488
6489 TrioSkipWhitespaces(self);
6490
6491 /*
6492 * Read entire double number from stream. trio_to_double requires
6493 * a string as input, but InStream can be anything, so we have to
6494 * collect all characters.
6495 */
6496 ch = self->current;
6497 if ((ch == '+') || (ch == '-'))
6498 {
6499 doubleString[offset++] = (char)ch;
6500 self->InStream(self, &ch);
6501 width--;
6502 }
6503
6504 start = offset;
6505 switch (ch)
6506 {
6507 case 'n':
6508 case 'N':
6509 /* Not-a-number */
6510 if (offset != 0)
6511 break;
6512 /* FALLTHROUGH */
6513 case 'i':
6514 case 'I':
6515 /* Infinity */
6516 while (isalpha(ch) && (offset - start < width))
6517 {
6518 doubleString[offset++] = (char)ch;
6519 self->InStream(self, &ch);
6520 }
6521 doubleString[offset] = NIL;
6522
6523 /* Case insensitive string comparison */
6524 if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
6525 trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
6526 {
6527 infinity = ((start == 1) && (doubleString[0] == '-'))
6528 ? trio_ninf()
6529 : trio_pinf();
6530 if (flags & FLAGS_LONGDOUBLE)
6531 {
6532 *((trio_long_double_t *)target) = infinity;
6533 }
6534 else if (flags & FLAGS_LONG)
6535 {
6536 *((double *)target) = infinity;
6537 }
6538 else
6539 {
6540 *((float *)target) = infinity;
6541 }
6542 return TRUE;
6543 }
6544 if (trio_equal(doubleString, NAN_UPPER))
6545 {
6546 /* NaN must not have a preceeding + nor - */
6547 if (flags & FLAGS_LONGDOUBLE)
6548 {
6549 *((trio_long_double_t *)target) = trio_nan();
6550 }
6551 else if (flags & FLAGS_LONG)
6552 {
6553 *((double *)target) = trio_nan();
6554 }
6555 else
6556 {
6557 *((float *)target) = trio_nan();
6558 }
6559 return TRUE;
6560 }
6561 return FALSE;
6562
6563 case '0':
6564 doubleString[offset++] = (char)ch;
6565 self->InStream(self, &ch);
6566 if (trio_to_upper(ch) == 'X')
6567 {
6568 isHex = TRUE;
6569 doubleString[offset++] = (char)ch;
6570 self->InStream(self, &ch);
6571 }
6572 break;
6573
6574 default:
6575 break;
6576 }
6577
6578 while ((ch != EOF) && (offset - start < width))
6579 {
6580 /* Integer part */
6581 if (isHex ? isxdigit(ch) : isdigit(ch))
6582 {
6583 doubleString[offset++] = (char)ch;
6584 self->InStream(self, &ch);
6585 }
6586 # if TRIO_FEATURE_QUOTE
6587 else if (flags & FLAGS_QUOTE)
6588 {
6589 /* Compare with thousands separator */
6590 for (j = 0; internalThousandSeparator[j] && self->current; j++)
6591 {
6592 if (internalThousandSeparator[j] != self->current)
6593 break;
6594
6595 self->InStream(self, &ch);
6596 }
6597 if (internalThousandSeparator[j])
6598 break; /* Mismatch */
6599 else
6600 continue; /* Match */
6601 }
6602 # endif
6603 else
6604 break; /* while */
6605 }
6606 if (ch == '.')
6607 {
6608 /* Decimal part */
6609 doubleString[offset++] = (char)ch;
6610 self->InStream(self, &ch);
6611 while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
6612 (offset - start < width))
6613 {
6614 doubleString[offset++] = (char)ch;
6615 self->InStream(self, &ch);
6616 }
6617 }
6618 if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
6619 {
6620 /* Exponent */
6621 doubleString[offset++] = (char)ch;
6622 self->InStream(self, &ch);
6623 if ((ch == '+') || (ch == '-'))
6624 {
6625 doubleString[offset++] = (char)ch;
6626 self->InStream(self, &ch);
6627 }
6628 while (isdigit(ch) && (offset - start < width))
6629 {
6630 doubleString[offset++] = (char)ch;
6631 self->InStream(self, &ch);
6632 }
6633 }
6634
6635 if ((offset == start) || (*doubleString == NIL))
6636 return FALSE;
6637
6638 doubleString[offset] = 0;
6639
6640 if (flags & FLAGS_LONGDOUBLE)
6641 {
6642 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
6643 }
6644 else if (flags & FLAGS_LONG)
6645 {
6646 *((double *)target) = trio_to_double(doubleString, NULL);
6647 }
6648 else
6649 {
6650 *((float *)target) = trio_to_float(doubleString, NULL);
6651 }
6652 return TRUE;
6653 }
6654 #endif /* TRIO_FEATURE_FLOAT */
6655
6656 /*************************************************************************
6657 * TrioReadPointer
6658 */
6659 TRIO_PRIVATE BOOLEAN_T
6660 TrioReadPointer
6661 TRIO_ARGS3((self, target, flags),
6662 trio_class_t *self,
6663 trio_pointer_t *target,
6664 trio_flags_t flags)
6665 {
6666 trio_uintmax_t number;
6667 char buffer[sizeof(internalNullString)];
6668
6669 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
6670
6671 if (TrioReadNumber(self,
6672 &number,
6673 flags,
6674 POINTER_WIDTH,
6675 BASE_HEX))
6676 {
6677 if (target)
6678 {
6679 #if defined(TRIO_COMPILER_GCC) || defined(TRIO_COMPILER_MIPSPRO)
6680 /*
6681 * The strange assignment of number is a workaround for a compiler
6682 * warning
6683 */
6684 *target = &((char *)0)[number];
6685 #else
6686 *target = (trio_pointer_t)number;
6687 #endif
6688 }
6689 return TRUE;
6690 }
6691 else if (TrioReadString(self,
6692 (flags & FLAGS_IGNORE)
6693 ? NULL
6694 : buffer,
6695 0,
6696 sizeof(internalNullString) - 1))
6697 {
6698 if (trio_equal_case(buffer, internalNullString))
6699 {
6700 if (target)
6701 *target = NULL;
6702 return TRUE;
6703 }
6704 }
6705 return FALSE;
6706 }
6707
6708 /*************************************************************************
6709 * TrioScanProcess
6710 */
6711 TRIO_PRIVATE int
6712 TrioScanProcess
6713 TRIO_ARGS3((data, format, parameters),
6714 trio_class_t *data,
6715 TRIO_CONST char *format,
6716 trio_parameter_t *parameters)
6717 {
6718 int status;
6719 int assignment;
6720 int ch;
6721 int offset; /* Offset of format string */
6722 int i; /* Offset of current parameter */
6723 trio_flags_t flags;
6724 int width;
6725 int base;
6726 trio_pointer_t pointer;
6727
6728 /* Return on empty format string */
6729 if (format[0] == NIL)
6730 return 0;
6731
6732 status = 0;
6733 assignment = 0;
6734 i = 0;
6735 offset = 0;
6736 data->InStream(data, &ch);
6737
6738 for (;;)
6739 {
6740 /* Skip the parameter entries */
6741 while (parameters[i].type == FORMAT_PARAMETER)
6742 {
6743 assert(i <= MAX_PARAMETERS);
6744 i++;
6745 }
6746
6747 /* Compare non conversion-specifier part of format string */
6748 while (offset < parameters[i].beginOffset)
6749 {
6750 if ((CHAR_IDENTIFIER == format[offset]) &&
6751 (CHAR_IDENTIFIER == format[offset + 1]))
6752 {
6753 /* Two % in format matches one % in input stream */
6754 if (CHAR_IDENTIFIER == ch)
6755 {
6756 data->InStream(data, &ch);
6757 offset += 2;
6758 continue; /* while format chars left */
6759 }
6760 else
6761 {
6762 status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
6763 goto end;
6764 }
6765 }
6766 else /* Not an % identifier */
6767 {
6768 if (isspace((int)format[offset]))
6769 {
6770 /* Whitespaces may match any amount of whitespaces */
6771 ch = TrioSkipWhitespaces(data);
6772 }
6773 else if (ch == format[offset])
6774 {
6775 data->InStream(data, &ch);
6776 }
6777 else
6778 {
6779 status = assignment;
6780 goto end;
6781 }
6782
6783 offset++;
6784 }
6785 }
6786
6787 if (parameters[i].type == FORMAT_SENTINEL)
6788 break;
6789
6790 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
6791 {
6792 status = (assignment > 0) ? assignment : EOF;
6793 goto end;
6794 }
6795
6796 flags = parameters[i].flags;
6797
6798 /* Find width */
6799 width = parameters[i].width;
6800 if (flags & FLAGS_WIDTH_PARAMETER)
6801 {
6802 /* Get width from parameter list */
6803 width = (int)parameters[width].data.number.as_signed;
6804 }
6805
6806 /* Find base */
6807 if (NO_BASE != parameters[i].baseSpecifier)
6808 {
6809 /* Base from specifier has priority */
6810 base = parameters[i].baseSpecifier;
6811 }
6812 else if (flags & FLAGS_BASE_PARAMETER)
6813 {
6814 /* Get base from parameter list */
6815 base = parameters[i].base;
6816 base = (int)parameters[base].data.number.as_signed;
6817 }
6818 else
6819 {
6820 /* Use base from format string */
6821 base = parameters[i].base;
6822 }
6823
6824 switch (parameters[i].type)
6825 {
6826 case FORMAT_INT:
6827 {
6828 trio_uintmax_t number;
6829
6830 if (0 == base)
6831 base = BASE_DECIMAL;
6832
6833 if (!TrioReadNumber(data,
6834 &number,
6835 flags,
6836 width,
6837 base))
6838 {
6839 status = assignment;
6840 goto end;
6841 }
6842
6843 if (!(flags & FLAGS_IGNORE))
6844 {
6845 assignment++;
6846
6847 pointer = parameters[i].data.pointer;
6848 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
6849 if (flags & FLAGS_SIZE_T)
6850 *(size_t *)pointer = (size_t)number;
6851 else
6852 #endif
6853 #if TRIO_FEATURE_PTRDIFF_T
6854 if (flags & FLAGS_PTRDIFF_T)
6855 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
6856 else
6857 #endif
6858 #if TRIO_FEATURE_INTMAX_T
6859 if (flags & FLAGS_INTMAX_T)
6860 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
6861 else
6862 #endif
6863 if (flags & FLAGS_QUAD)
6864 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
6865 else if (flags & FLAGS_LONG)
6866 *(long int *)pointer = (long int)number;
6867 else if (flags & FLAGS_SHORT)
6868 *(short int *)pointer = (short int)number;
6869 else
6870 *(int *)pointer = (int)number;
6871 }
6872 }
6873 break; /* FORMAT_INT */
6874
6875 case FORMAT_STRING:
6876 #if TRIO_FEATURE_WIDECHAR
6877 if (flags & FLAGS_WIDECHAR)
6878 {
6879 if (!TrioReadWideString(data,
6880 (flags & FLAGS_IGNORE)
6881 ? NULL
6882 : parameters[i].data.wstring,
6883 flags,
6884 width))
6885 {
6886 status = assignment;
6887 goto end;
6888 }
6889 }
6890 else
6891 #endif
6892 {
6893 if (!TrioReadString(data,
6894 (flags & FLAGS_IGNORE)
6895 ? NULL
6896 : parameters[i].data.string,
6897 flags,
6898 width))
6899 {
6900 status = assignment;
6901 goto end;
6902 }
6903 }
6904 if (!(flags & FLAGS_IGNORE))
6905 assignment++;
6906 break; /* FORMAT_STRING */
6907
6908 #if TRIO_FEATURE_FLOAT
6909 case FORMAT_DOUBLE:
6910 {
6911 if (flags & FLAGS_IGNORE)
6912 {
6913 pointer = NULL;
6914 }
6915 else
6916 {
6917 pointer = (flags & FLAGS_LONGDOUBLE)
6918 ? (trio_pointer_t)parameters[i].data.longdoublePointer
6919 : (trio_pointer_t)parameters[i].data.doublePointer;
6920 }
6921 if (!TrioReadDouble(data, pointer, flags, width))
6922 {
6923 status = assignment;
6924 goto end;
6925 }
6926 if (!(flags & FLAGS_IGNORE))
6927 {
6928 assignment++;
6929 }
6930 break; /* FORMAT_DOUBLE */
6931 }
6932 #endif
6933
6934 case FORMAT_GROUP:
6935 {
6936 int characterclass[MAX_CHARACTER_CLASS + 1];
6937
6938 /* Skip over modifiers */
6939 while (format[offset] != SPECIFIER_GROUP)
6940 {
6941 offset++;
6942 }
6943 /* Skip over group specifier */
6944 offset++;
6945
6946 memset(characterclass, 0, sizeof(characterclass));
6947 status = TrioGetCharacterClass(format,
6948 &offset,
6949 &flags,
6950 characterclass);
6951 if (status < 0)
6952 goto end;
6953
6954 if (!TrioReadGroup(data,
6955 (flags & FLAGS_IGNORE)
6956 ? NULL
6957 : parameters[i].data.string,
6958 characterclass,
6959 flags,
6960 parameters[i].width))
6961 {
6962 status = assignment;
6963 goto end;
6964 }
6965 if (!(flags & FLAGS_IGNORE))
6966 assignment++;
6967 }
6968 break; /* FORMAT_GROUP */
6969
6970 case FORMAT_COUNT:
6971 pointer = parameters[i].data.pointer;
6972 if (NULL != pointer)
6973 {
6974 int count = data->processed;
6975 if (ch != EOF)
6976 count--; /* a character is read, but is not consumed yet */
6977 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
6978 if (flags & FLAGS_SIZE_T)
6979 *(size_t *)pointer = (size_t)count;
6980 else
6981 #endif
6982 #if TRIO_FEATURE_PTRDIFF_T
6983 if (flags & FLAGS_PTRDIFF_T)
6984 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
6985 else
6986 #endif
6987 #if TRIO_FEATURE_INTMAX_T
6988 if (flags & FLAGS_INTMAX_T)
6989 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
6990 else
6991 #endif
6992 if (flags & FLAGS_QUAD)
6993 {
6994 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
6995 }
6996 else if (flags & FLAGS_LONG)
6997 {
6998 *(long int *)pointer = (long int)count;
6999 }
7000 else if (flags & FLAGS_SHORT)
7001 {
7002 *(short int *)pointer = (short int)count;
7003 }
7004 else
7005 {
7006 *(int *)pointer = (int)count;
7007 }
7008 }
7009 break; /* FORMAT_COUNT */
7010
7011 case FORMAT_CHAR:
7012 #if TRIO_FEATURE_WIDECHAR
7013 if (flags & FLAGS_WIDECHAR)
7014 {
7015 if (TrioReadWideChar(data,
7016 (flags & FLAGS_IGNORE)
7017 ? NULL
7018 : parameters[i].data.wstring,
7019 flags,
7020 (width == NO_WIDTH) ? 1 : width) == 0)
7021 {
7022 status = assignment;
7023 goto end;
7024 }
7025 }
7026 else
7027 #endif
7028 {
7029 if (TrioReadChar(data,
7030 (flags & FLAGS_IGNORE)
7031 ? NULL
7032 : parameters[i].data.string,
7033 flags,
7034 (width == NO_WIDTH) ? 1 : width) == 0)
7035 {
7036 status = assignment;
7037 goto end;
7038 }
7039 }
7040 if (!(flags & FLAGS_IGNORE))
7041 assignment++;
7042 break; /* FORMAT_CHAR */
7043
7044 case FORMAT_POINTER:
7045 if (!TrioReadPointer(data,
7046 (flags & FLAGS_IGNORE)
7047 ? NULL
7048 : (trio_pointer_t *)parameters[i].data.pointer,
7049 flags))
7050 {
7051 status = assignment;
7052 goto end;
7053 }
7054 if (!(flags & FLAGS_IGNORE))
7055 assignment++;
7056 break; /* FORMAT_POINTER */
7057
7058 case FORMAT_PARAMETER:
7059 break; /* FORMAT_PARAMETER */
7060
7061 default:
7062 status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
7063 goto end;
7064 }
7065
7066 ch = data->current;
7067 offset = parameters[i].endOffset;
7068 i++;
7069 }
7070
7071 status = assignment;
7072 end:
7073 if (data->UndoStream)
7074 data->UndoStream(data);
7075 return status;
7076 }
7077
7078 /*************************************************************************
7079 * TrioScan
7080 */
7081 TRIO_PRIVATE int
7082 TrioScan
7083 TRIO_ARGS7((source, sourceSize, InStream, UndoStream, format, arglist, argarray),
7084 trio_pointer_t source,
7085 size_t sourceSize,
7086 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
7087 void (*UndoStream) TRIO_PROTO((trio_class_t *)),
7088 TRIO_CONST char *format,
7089 va_list arglist,
7090 trio_pointer_t *argarray)
7091 {
7092 int status;
7093 trio_parameter_t parameters[MAX_PARAMETERS];
7094 trio_class_t data;
7095
7096 assert(VALID(InStream));
7097 assert(VALID(format));
7098
7099 memset(&data, 0, sizeof(data));
7100 data.InStream = InStream;
7101 data.UndoStream = UndoStream;
7102 data.location = (trio_pointer_t)source;
7103 data.max = sourceSize;
7104 data.error = 0;
7105
7106 #if defined(USE_LOCALE)
7107 if (NULL == internalLocaleValues)
7108 {
7109 TrioSetLocale();
7110 }
7111 #endif
7112
7113 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
7114 if (status < 0)
7115 return status;
7116
7117 status = TrioScanProcess(&data, format, parameters);
7118 if (data.error != 0)
7119 {
7120 status = data.error;
7121 }
7122 return status;
7123 }
7124
7125 /*************************************************************************
7126 * TrioInStreamFile
7127 */
7128 #if TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO
7129 TRIO_PRIVATE void
7130 TrioInStreamFile
7131 TRIO_ARGS2((self, intPointer),
7132 trio_class_t *self,
7133 int *intPointer)
7134 {
7135 FILE *file = (FILE *)self->location;
7136
7137 assert(VALID(self));
7138 assert(VALID(file));
7139
7140 self->actually.cached = 0;
7141
7142 /* The initial value of self->current is zero */
7143 if (self->current == EOF)
7144 {
7145 self->error = (ferror(file))
7146 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
7147 : TRIO_ERROR_RETURN(TRIO_EOF, 0);
7148 }
7149 else
7150 {
7151 self->processed++;
7152 self->actually.cached++;
7153 }
7154
7155 self->current = fgetc(file);
7156
7157 if (VALID(intPointer))
7158 {
7159 *intPointer = self->current;
7160 }
7161 }
7162 #endif /* TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO */
7163
7164 /*************************************************************************
7165 * TrioUndoStreamFile
7166 */
7167 #if TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO
7168 TRIO_PRIVATE void
7169 TrioUndoStreamFile
7170 TRIO_ARGS1((self),
7171 trio_class_t *self)
7172 {
7173 FILE *file = (FILE *)self->location;
7174
7175 assert(VALID(self));
7176 assert(VALID(file));
7177
7178 if (self->actually.cached > 0)
7179 {
7180 assert(self->actually.cached == 1);
7181
7182 self->current = ungetc(self->current, file);
7183 self->actually.cached = 0;
7184 }
7185 }
7186 #endif /* TRIO_FEATURE_FILE || TRIO_FEATURE_STDIO */
7187
7188 /*************************************************************************
7189 * TrioInStreamFileDescriptor
7190 */
7191 #if TRIO_FEATURE_FD
7192 TRIO_PRIVATE void
7193 TrioInStreamFileDescriptor
7194 TRIO_ARGS2((self, intPointer),
7195 trio_class_t *self,
7196 int *intPointer)
7197 {
7198 int fd = *((int *)self->location);
7199 int size;
7200 unsigned char input;
7201
7202 assert(VALID(self));
7203
7204 self->actually.cached = 0;
7205
7206 size = read(fd, &input, sizeof(char));
7207 if (size == -1)
7208 {
7209 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
7210 self->current = EOF;
7211 }
7212 else
7213 {
7214 self->current = (size == 0) ? EOF : input;
7215 }
7216 if (self->current != EOF)
7217 {
7218 self->actually.cached++;
7219 self->processed++;
7220 }
7221
7222 if (VALID(intPointer))
7223 {
7224 *intPointer = self->current;
7225 }
7226 }
7227 #endif /* TRIO_FEATURE_FD */
7228
7229 /*************************************************************************
7230 * TrioInStreamCustom
7231 */
7232 #if TRIO_FEATURE_CLOSURE
7233 TRIO_PRIVATE void
7234 TrioInStreamCustom
7235 TRIO_ARGS2((self, intPointer),
7236 trio_class_t *self,
7237 int *intPointer)
7238 {
7239 trio_custom_t *data;
7240
7241 assert(VALID(self));
7242 assert(VALID(self->location));
7243
7244 self->actually.cached = 0;
7245
7246 data = (trio_custom_t *)self->location;
7247
7248 self->current = (data->stream.in == NULL)
7249 ? NIL
7250 : (data->stream.in)(data->closure);
7251
7252 if (self->current == NIL)
7253 {
7254 self->current = EOF;
7255 }
7256 else
7257 {
7258 self->processed++;
7259 self->actually.cached++;
7260 }
7261
7262 if (VALID(intPointer))
7263 {
7264 *intPointer = self->current;
7265 }
7266 }
7267 #endif /* TRIO_FEATURE_CLOSURE */
7268
7269 /*************************************************************************
7270 * TrioInStreamString
7271 */
7272 TRIO_PRIVATE void
7273 TrioInStreamString
7274 TRIO_ARGS2((self, intPointer),
7275 trio_class_t *self,
7276 int *intPointer)
7277 {
7278 unsigned char **buffer;
7279
7280 assert(VALID(self));
7281 assert(VALID(self->location));
7282
7283 self->actually.cached = 0;
7284
7285 buffer = (unsigned char **)self->location;
7286 self->current = (*buffer)[0];
7287 if (self->current == NIL)
7288 {
7289 self->current = EOF;
7290 }
7291 else
7292 {
7293 (*buffer)++;
7294 self->processed++;
7295 self->actually.cached++;
7296 }
7297
7298 if (VALID(intPointer))
7299 {
7300 *intPointer = self->current;
7301 }
7302 }
7303
7304 /*************************************************************************
7305 *
7306 * Formatted scanning functions
7307 *
7308 ************************************************************************/
7309
7310 #if defined(TRIO_DOCUMENTATION)
7311 # include "doc/doc_scanf.h"
7312 #endif
7313 /** @addtogroup Scanf
7314 @{
7315 */
7316
7317 /*************************************************************************
7318 * scanf
7319 */
7320
7321 /**
7322 Scan characters from standard input stream.
7323
7324 @param format Formatting string.
7325 @param ... Arguments.
7326 @return Number of scanned characters.
7327 */
7328 #if TRIO_FEATURE_STDIO
7329 TRIO_PUBLIC int
7330 trio_scanf
7331 TRIO_VARGS2((format, va_alist),
7332 TRIO_CONST char *format,
7333 TRIO_VA_DECL)
7334 {
7335 int status;
7336 va_list args;
7337
7338 assert(VALID(format));
7339
7340 TRIO_VA_START(args, format);
7341 status = TrioScan((trio_pointer_t)stdin, 0,
7342 TrioInStreamFile,
7343 TrioUndoStreamFile,
7344 format, args, NULL);
7345 TRIO_VA_END(args);
7346 return status;
7347 }
7348 #endif /* TRIO_FEATURE_STDIO */
7349
7350 /**
7351 Scan characters from standard input stream.
7352
7353 @param format Formatting string.
7354 @param args Arguments.
7355 @return Number of scanned characters.
7356 */
7357 #if TRIO_FEATURE_STDIO
7358 TRIO_PUBLIC int
7359 trio_vscanf
7360 TRIO_ARGS2((format, args),
7361 TRIO_CONST char *format,
7362 va_list args)
7363 {
7364 assert(VALID(format));
7365
7366 return TrioScan((trio_pointer_t)stdin, 0,
7367 TrioInStreamFile,
7368 TrioUndoStreamFile,
7369 format, args, NULL);
7370 }
7371 #endif /* TRIO_FEATURE_STDIO */
7372
7373 /**
7374 Scan characters from standard input stream.
7375
7376 @param format Formatting string.
7377 @param args Arguments.
7378 @return Number of scanned characters.
7379 */
7380 #if TRIO_FEATURE_STDIO
7381 TRIO_PUBLIC int
7382 trio_scanfv
7383 TRIO_ARGS2((format, args),
7384 TRIO_CONST char *format,
7385 trio_pointer_t *args)
7386 {
7387 static va_list unused;
7388
7389 assert(VALID(format));
7390
7391 return TrioScan((trio_pointer_t)stdin, 0,
7392 TrioInStreamFile,
7393 TrioUndoStreamFile,
7394 format, unused, args);
7395 }
7396 #endif /* TRIO_FEATURE_STDIO */
7397
7398 /*************************************************************************
7399 * fscanf
7400 */
7401
7402 /**
7403 Scan characters from file.
7404
7405 @param file File pointer.
7406 @param format Formatting string.
7407 @param ... Arguments.
7408 @return Number of scanned characters.
7409 */
7410 #if TRIO_FEATURE_FILE
7411 TRIO_PUBLIC int
7412 trio_fscanf
7413 TRIO_VARGS3((file, format, va_alist),
7414 FILE *file,
7415 TRIO_CONST char *format,
7416 TRIO_VA_DECL)
7417 {
7418 int status;
7419 va_list args;
7420
7421 assert(VALID(file));
7422 assert(VALID(format));
7423
7424 TRIO_VA_START(args, format);
7425 status = TrioScan((trio_pointer_t)file, 0,
7426 TrioInStreamFile,
7427 TrioUndoStreamFile,
7428 format, args, NULL);
7429 TRIO_VA_END(args);
7430 return status;
7431 }
7432 #endif /* TRIO_FEATURE_FILE */
7433
7434 /**
7435 Scan characters from file.
7436
7437 @param file File pointer.
7438 @param format Formatting string.
7439 @param args Arguments.
7440 @return Number of scanned characters.
7441 */
7442 #if TRIO_FEATURE_FILE
7443 TRIO_PUBLIC int
7444 trio_vfscanf
7445 TRIO_ARGS3((file, format, args),
7446 FILE *file,
7447 TRIO_CONST char *format,
7448 va_list args)
7449 {
7450 assert(VALID(file));
7451 assert(VALID(format));
7452
7453 return TrioScan((trio_pointer_t)file, 0,
7454 TrioInStreamFile,
7455 TrioUndoStreamFile,
7456 format, args, NULL);
7457 }
7458 #endif /* TRIO_FEATURE_FILE */
7459
7460 /**
7461 Scan characters from file.
7462
7463 @param file File pointer.
7464 @param format Formatting string.
7465 @param args Arguments.
7466 @return Number of scanned characters.
7467 */
7468 #if TRIO_FEATURE_FILE
7469 TRIO_PUBLIC int
7470 trio_fscanfv
7471 TRIO_ARGS3((file, format, args),
7472 FILE *file,
7473 TRIO_CONST char *format,
7474 trio_pointer_t *args)
7475 {
7476 static va_list unused;
7477
7478 assert(VALID(file));
7479 assert(VALID(format));
7480
7481 return TrioScan((trio_pointer_t)file, 0,
7482 TrioInStreamFile,
7483 TrioUndoStreamFile,
7484 format, unused, args);
7485 }
7486 #endif /* TRIO_FEATURE_FILE */
7487
7488 /*************************************************************************
7489 * dscanf
7490 */
7491
7492 /**
7493 Scan characters from file descriptor.
7494
7495 @param fd File descriptor.
7496 @param format Formatting string.
7497 @param ... Arguments.
7498 @return Number of scanned characters.
7499 */
7500 #if TRIO_FEATURE_FD
7501 TRIO_PUBLIC int
7502 trio_dscanf
7503 TRIO_VARGS3((fd, format, va_alist),
7504 int fd,
7505 TRIO_CONST char *format,
7506 TRIO_VA_DECL)
7507 {
7508 int status;
7509 va_list args;
7510
7511 assert(VALID(format));
7512
7513 TRIO_VA_START(args, format);
7514 status = TrioScan((trio_pointer_t)&fd, 0,
7515 TrioInStreamFileDescriptor,
7516 NULL,
7517 format, args, NULL);
7518 TRIO_VA_END(args);
7519 return status;
7520 }
7521 #endif /* TRIO_FEATURE_FD */
7522
7523 /**
7524 Scan characters from file descriptor.
7525
7526 @param fd File descriptor.
7527 @param format Formatting string.
7528 @param args Arguments.
7529 @return Number of scanned characters.
7530 */
7531 #if TRIO_FEATURE_FD
7532 TRIO_PUBLIC int
7533 trio_vdscanf
7534 TRIO_ARGS3((fd, format, args),
7535 int fd,
7536 TRIO_CONST char *format,
7537 va_list args)
7538 {
7539 assert(VALID(format));
7540
7541 return TrioScan((trio_pointer_t)&fd, 0,
7542 TrioInStreamFileDescriptor,
7543 NULL,
7544 format, args, NULL);
7545 }
7546 #endif /* TRIO_FEATURE_FD */
7547
7548 /**
7549 Scan characters from file descriptor.
7550
7551 @param fd File descriptor.
7552 @param format Formatting string.
7553 @param args Arguments.
7554 @return Number of scanned characters.
7555 */
7556 #if TRIO_FEATURE_FD
7557 TRIO_PUBLIC int
7558 trio_dscanfv
7559 TRIO_ARGS3((fd, format, args),
7560 int fd,
7561 TRIO_CONST char *format,
7562 trio_pointer_t *args)
7563 {
7564 static va_list unused;
7565
7566 assert(VALID(format));
7567
7568 return TrioScan((trio_pointer_t)&fd, 0,
7569 TrioInStreamFileDescriptor,
7570 NULL,
7571 format, unused, args);
7572 }
7573 #endif /* TRIO_FEATURE_FD */
7574
7575 /*************************************************************************
7576 * cscanf
7577 */
7578 #if TRIO_FEATURE_CLOSURE
7579 TRIO_PUBLIC int
7580 trio_cscanf
7581 TRIO_VARGS4((stream, closure, format, va_alist),
7582 trio_instream_t stream,
7583 trio_pointer_t closure,
7584 TRIO_CONST char *format,
7585 TRIO_VA_DECL)
7586 {
7587 int status;
7588 va_list args;
7589 trio_custom_t data;
7590
7591 assert(VALID(stream));
7592 assert(VALID(format));
7593
7594 TRIO_VA_START(args, format);
7595 data.stream.in = stream;
7596 data.closure = closure;
7597 status = TrioScan(&data, 0, TrioInStreamCustom, NULL, format, args, NULL);
7598 TRIO_VA_END(args);
7599 return status;
7600 }
7601 #endif /* TRIO_FEATURE_CLOSURE */
7602
7603 #if TRIO_FEATURE_CLOSURE
7604 TRIO_PUBLIC int
7605 trio_vcscanf
7606 TRIO_ARGS4((stream, closure, format, args),
7607 trio_instream_t stream,
7608 trio_pointer_t closure,
7609 TRIO_CONST char *format,
7610 va_list args)
7611 {
7612 trio_custom_t data;
7613
7614 assert(VALID(stream));
7615 assert(VALID(format));
7616
7617 data.stream.in = stream;
7618 data.closure = closure;
7619 return TrioScan(&data, 0, TrioInStreamCustom, NULL, format, args, NULL);
7620 }
7621 #endif /* TRIO_FEATURE_CLOSURE */
7622
7623 #if TRIO_FEATURE_CLOSURE
7624 TRIO_PUBLIC int
7625 trio_cscanfv
7626 TRIO_ARGS4((stream, closure, format, args),
7627 trio_instream_t stream,
7628 trio_pointer_t closure,
7629 TRIO_CONST char *format,
7630 trio_pointer_t *args)
7631 {
7632 static va_list unused;
7633 trio_custom_t data;
7634
7635 assert(VALID(stream));
7636 assert(VALID(format));
7637
7638 data.stream.in = stream;
7639 data.closure = closure;
7640 return TrioScan(&data, 0, TrioInStreamCustom, NULL, format, unused, args);
7641 }
7642 #endif /* TRIO_FEATURE_CLOSURE */
7643
7644 /*************************************************************************
7645 * sscanf
7646 */
7647
7648 /**
7649 Scan characters from string.
7650
7651 @param buffer Input string.
7652 @param format Formatting string.
7653 @param ... Arguments.
7654 @return Number of scanned characters.
7655 */
7656 TRIO_PUBLIC int
7657 trio_sscanf
7658 TRIO_VARGS3((buffer, format, va_alist),
7659 TRIO_CONST char *buffer,
7660 TRIO_CONST char *format,
7661 TRIO_VA_DECL)
7662 {
7663 int status;
7664 va_list args;
7665
7666 assert(VALID(buffer));
7667 assert(VALID(format));
7668
7669 TRIO_VA_START(args, format);
7670 status = TrioScan((trio_pointer_t)&buffer, 0,
7671 TrioInStreamString,
7672 NULL,
7673 format, args, NULL);
7674 TRIO_VA_END(args);
7675 return status;
7676 }
7677
7678 /**
7679 Scan characters from string.
7680
7681 @param buffer Input string.
7682 @param format Formatting string.
7683 @param args Arguments.
7684 @return Number of scanned characters.
7685 */
7686 TRIO_PUBLIC int
7687 trio_vsscanf
7688 TRIO_ARGS3((buffer, format, args),
7689 TRIO_CONST char *buffer,
7690 TRIO_CONST char *format,
7691 va_list args)
7692 {
7693 assert(VALID(buffer));
7694 assert(VALID(format));
7695
7696 return TrioScan((trio_pointer_t)&buffer, 0,
7697 TrioInStreamString,
7698 NULL,
7699 format, args, NULL);
7700 }
7701
7702 /**
7703 Scan characters from string.
7704
7705 @param buffer Input string.
7706 @param format Formatting string.
7707 @param args Arguments.
7708 @return Number of scanned characters.
7709 */
7710 TRIO_PUBLIC int
7711 trio_sscanfv
7712 TRIO_ARGS3((buffer, format, args),
7713 TRIO_CONST char *buffer,
7714 TRIO_CONST char *format,
7715 trio_pointer_t *args)
7716 {
7717 static va_list unused;
7718
7719 assert(VALID(buffer));
7720 assert(VALID(format));
7721
7722 return TrioScan((trio_pointer_t)&buffer, 0,
7723 TrioInStreamString,
7724 NULL,
7725 format, unused, args);
7726 }
7727
7728 #endif /* TRIO_FEATURE_SCANF */
7729
7730 /** @} End of Scanf documentation module */
7731
7732 /*************************************************************************
7733 * trio_strerror
7734 */
7735 TRIO_PUBLIC TRIO_CONST char *
7736 trio_strerror
7737 TRIO_ARGS1((errorcode),
7738 int errorcode)
7739 {
7740 #if TRIO_FEATURE_STRERR
7741 /* Textual versions of the error codes */
7742 switch (TRIO_ERROR_CODE(errorcode))
7743 {
7744 case TRIO_EOF:
7745 return "End of file";
7746 case TRIO_EINVAL:
7747 return "Invalid argument";
7748 case TRIO_ETOOMANY:
7749 return "Too many arguments";
7750 case TRIO_EDBLREF:
7751 return "Double reference";
7752 case TRIO_EGAP:
7753 return "Reference gap";
7754 case TRIO_ENOMEM:
7755 return "Out of memory";
7756 case TRIO_ERANGE:
7757 return "Invalid range";
7758 case TRIO_ECUSTOM:
7759 return "Custom error";
7760 default:
7761 return "Unknown";
7762 }
7763 #else
7764 return "Unknown";
7765 #endif
7766 }
7767