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