ReactOS  r76032
trio.c
Go to the documentation of this file.
1 /*************************************************************************
2  *
3  * $Id$
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 #include "trionan.h"
51 #if !defined(TRIO_MINIMAL)
52 # include "triostr.h"
53 #endif
54 
55 /**************************************************************************
56  *
57  * Definitions
58  *
59  *************************************************************************/
60 
61 #include <math.h>
62 #include <limits.h>
63 #include <float.h>
64 
65 #if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \
66  || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \
67  && !defined(_WIN32_WCE)
68 # define TRIO_COMPILER_SUPPORTS_MULTIBYTE
69 # if !defined(MB_LEN_MAX)
70 # define MB_LEN_MAX 6
71 # endif
72 #endif
73 
74 #if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
75 # define TRIO_COMPILER_SUPPORTS_MSVC_INT
76 #endif
77 
78 #if defined(_WIN32_WCE)
79 #include <wincecompat.h>
80 #endif
81 
82 /*************************************************************************
83  * Generic definitions
84  */
85 
86 #if !(defined(DEBUG) || defined(NDEBUG))
87 # define NDEBUG
88 #endif
89 
90 #include <assert.h>
91 #include <ctype.h>
92 #if !defined(TRIO_COMPILER_SUPPORTS_C99)
93 # define isblank(x) (((x)==32) || ((x)==9))
94 #endif
95 #if defined(TRIO_COMPILER_ANCIENT)
96 # include <varargs.h>
97 #else
98 # include <stdarg.h>
99 #endif
100 #include <stddef.h>
101 
102 #if defined( HAVE_ERRNO_H ) || defined( __VMS )
103 #include <errno.h>
104 #endif
105 
106 #ifndef NULL
107 # define NULL 0
108 #endif
109 #define NIL ((char)0)
110 #ifndef FALSE
111 # define FALSE (1 == 0)
112 # define TRUE (! FALSE)
113 #endif
114 #define BOOLEAN_T int
115 
116 /* mincore() can be used for debugging purposes */
117 #define VALID(x) (NULL != (x))
118 
119 #if TRIO_ERRORS
120  /*
121  * Encode the error code and the position. This is decoded
122  * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
123  */
124 # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
125 #else
126 # define TRIO_ERROR_RETURN(x,y) (-1)
127 #endif
128 
129 #ifndef VA_LIST_IS_ARRAY
130 #define TRIO_VA_LIST_PTR va_list *
131 #define TRIO_VA_LIST_ADDR(l) (&(l))
132 #define TRIO_VA_LIST_DEREF(l) (*(l))
133 #else
134 #define TRIO_VA_LIST_PTR va_list
135 #define TRIO_VA_LIST_ADDR(l) (l)
136 #define TRIO_VA_LIST_DEREF(l) (l)
137 #endif
138 
139 typedef unsigned long trio_flags_t;
140 
141 
142 /*************************************************************************
143  * Platform specific definitions
144  */
145 #if defined(TRIO_PLATFORM_UNIX) || defined(TRIO_PLATFORM_OS400)
146 # include <unistd.h>
147 # include <signal.h>
148 # include <locale.h>
149 # define USE_LOCALE
150 #endif /* TRIO_PLATFORM_UNIX */
151 #if defined(TRIO_PLATFORM_VMS)
152 # include <unistd.h>
153 #endif
154 #if defined(TRIO_PLATFORM_WIN32)
155 # if defined(_WIN32_WCE)
156 # include <wincecompat.h>
157 # else
158 # include <io.h>
159 # define read _read
160 # define write _write
161 # endif
162 #endif /* TRIO_PLATFORM_WIN32 */
163 
164 #if TRIO_WIDECHAR
165 # if defined(TRIO_COMPILER_SUPPORTS_ISO94)
166 # include <wchar.h>
167 # include <wctype.h>
168 typedef wchar_t trio_wchar_t;
169 typedef wint_t trio_wint_t;
170 # else
171 typedef char trio_wchar_t;
172 typedef int trio_wint_t;
173 # define WCONST(x) L ## x
174 # define WEOF EOF
175 # define iswalnum(x) isalnum(x)
176 # define iswalpha(x) isalpha(x)
177 # define iswblank(x) isblank(x)
178 # define iswcntrl(x) iscntrl(x)
179 # define iswdigit(x) isdigit(x)
180 # define iswgraph(x) isgraph(x)
181 # define iswlower(x) islower(x)
182 # define iswprint(x) isprint(x)
183 # define iswpunct(x) ispunct(x)
184 # define iswspace(x) isspace(x)
185 # define iswupper(x) isupper(x)
186 # define iswxdigit(x) isxdigit(x)
187 # endif
188 #endif
189 
190 
191 /*************************************************************************
192  * Compiler dependent definitions
193  */
194 
195 /* Support for long long */
196 #ifndef __cplusplus
197 # if !defined(USE_LONGLONG)
198 # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
199 # define USE_LONGLONG
200 # elif defined(TRIO_COMPILER_SUNPRO)
201 # define USE_LONGLONG
202 # elif defined(_LONG_LONG) || defined(_LONGLONG)
203 # define USE_LONGLONG
204 # endif
205 # endif
206 #endif
207 
208 /* The extra long numbers */
209 #if defined(USE_LONGLONG)
210 typedef signed long long int trio_longlong_t;
211 typedef unsigned long long int trio_ulonglong_t;
212 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
213 typedef signed __int64 trio_longlong_t;
214 typedef unsigned __int64 trio_ulonglong_t;
215 #else
216 typedef TRIO_SIGNED long int trio_longlong_t;
217 typedef unsigned long int trio_ulonglong_t;
218 #endif
219 
220 /* Maximal and fixed integer types */
221 #if defined(TRIO_COMPILER_SUPPORTS_C99) && !defined( __VMS )
222 # include <stdint.h>
223 typedef intmax_t trio_intmax_t;
224 typedef uintmax_t trio_uintmax_t;
225 typedef int8_t trio_int8_t;
226 typedef int16_t trio_int16_t;
227 typedef int32_t trio_int32_t;
228 typedef int64_t trio_int64_t;
229 #elif defined(TRIO_COMPILER_SUPPORTS_UNIX98) || defined( __VMS )
230 # include <inttypes.h>
231 #ifdef __VMS
232 typedef long long int intmax_t;
233 typedef unsigned long long int uintmax_t;
234 #endif
235 typedef intmax_t trio_intmax_t;
236 typedef uintmax_t trio_uintmax_t;
237 typedef int8_t trio_int8_t;
238 typedef int16_t trio_int16_t;
239 typedef int32_t trio_int32_t;
240 typedef int64_t trio_int64_t;
241 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
244 typedef __int8 trio_int8_t;
245 typedef __int16 trio_int16_t;
246 typedef __int32 trio_int32_t;
247 typedef __int64 trio_int64_t;
248 #else
251 # if defined(TRIO_INT8_T)
252 typedef TRIO_INT8_T trio_int8_t;
253 # else
255 # endif
256 # if defined(TRIO_INT16_T)
257 typedef TRIO_INT16_T trio_int16_t;
258 # else
259 typedef TRIO_SIGNED short trio_int16_t;
260 # endif
261 # if defined(TRIO_INT32_T)
262 typedef TRIO_INT32_T trio_int32_t;
263 # else
265 # endif
266 # if defined(TRIO_INT64_T)
267 typedef TRIO_INT64_T trio_int64_t;
268 # else
270 # endif
271 #endif
272 
273 #if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \
274  || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \
275  && !defined(_WIN32_WCE)
276 # define floorl(x) floor((double)(x))
277 # define fmodl(x,y) fmod((double)(x),(double)(y))
278 # define powl(x,y) pow((double)(x),(double)(y))
279 #endif
280 
281 #define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
282 
283 /*************************************************************************
284  * Internal Definitions
285  */
286 
287 #ifndef DECIMAL_DIG
288 # define DECIMAL_DIG DBL_DIG
289 #endif
290 
291 /* Long double sizes */
292 #ifdef LDBL_DIG
293 # define MAX_MANTISSA_DIGITS LDBL_DIG
294 # define MAX_EXPONENT_DIGITS 4
295 # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
296 #else
297 # define MAX_MANTISSA_DIGITS DECIMAL_DIG
298 # define MAX_EXPONENT_DIGITS 3
299 # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
300 #endif
301 
302 #if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
303 # undef LDBL_DIG
304 # undef LDBL_MANT_DIG
305 # undef LDBL_EPSILON
306 # define LDBL_DIG DBL_DIG
307 # define LDBL_MANT_DIG DBL_MANT_DIG
308 # define LDBL_EPSILON DBL_EPSILON
309 #endif
310 
311 /* The maximal number of digits is for base 2 */
312 #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
313 /* The width of a pointer. The number of bits in a hex digit is 4 */
314 #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
315 
316 /* Infinite and Not-A-Number for floating-point */
317 #define INFINITE_LOWER "inf"
318 #define INFINITE_UPPER "INF"
319 #define LONG_INFINITE_LOWER "infinite"
320 #define LONG_INFINITE_UPPER "INFINITE"
321 #define NAN_LOWER "nan"
322 #define NAN_UPPER "NAN"
323 
324 #if !defined(HAVE_ISASCII) && !defined(isascii)
325 #ifndef __VMS
326 # define isascii(x) ((unsigned int)(x) < 128)
327 #endif
328 #endif
329 
330 /* Various constants */
331 enum {
334 
335  /* Flags. FLAGS_LAST must be less than ULONG_MAX */
369  /* Reused flags */
373  /* Compounded flags */
376 
378  NO_WIDTH = 0,
380  NO_SIZE = -1,
381 
382  /* Do not change these */
383  NO_BASE = -1,
384  MIN_BASE = 2,
385  MAX_BASE = 36,
389  BASE_HEX = 16,
390 
391  /* Maximal number of allowed parameters */
393  /* Maximal number of characters in class */
395 
396  /* Maximal string lengths for user-defined specifiers */
399 
400  /* Maximal length of locale separator strings */
402  /* Maximal number of integers in grouping */
404 
405  /* Initial size of asprintf buffer */
407 };
408 
409 #define NO_GROUPING ((int)CHAR_MAX)
410 
411 /* Fundamental formatting parameter types */
412 #define FORMAT_UNKNOWN 0
413 #define FORMAT_INT 1
414 #define FORMAT_DOUBLE 2
415 #define FORMAT_CHAR 3
416 #define FORMAT_STRING 4
417 #define FORMAT_POINTER 5
418 #define FORMAT_COUNT 6
419 #define FORMAT_PARAMETER 7
420 #define FORMAT_GROUP 8
421 #if TRIO_GNU
422 # define FORMAT_ERRNO 9
423 #endif
424 #if TRIO_EXTENSION
425 # define FORMAT_USER_DEFINED 10
426 #endif
427 
428 /* Character constants */
429 #define CHAR_IDENTIFIER '%'
430 #define CHAR_BACKSLASH '\\'
431 #define CHAR_QUOTE '\"'
432 #define CHAR_ADJUST ' '
433 
434 /* Character class expressions */
435 #define CLASS_ALNUM "[:alnum:]"
436 #define CLASS_ALPHA "[:alpha:]"
437 #define CLASS_BLANK "[:blank:]"
438 #define CLASS_CNTRL "[:cntrl:]"
439 #define CLASS_DIGIT "[:digit:]"
440 #define CLASS_GRAPH "[:graph:]"
441 #define CLASS_LOWER "[:lower:]"
442 #define CLASS_PRINT "[:print:]"
443 #define CLASS_PUNCT "[:punct:]"
444 #define CLASS_SPACE "[:space:]"
445 #define CLASS_UPPER "[:upper:]"
446 #define CLASS_XDIGIT "[:xdigit:]"
447 
448 /*
449  * SPECIFIERS:
450  *
451  *
452  * a Hex-float
453  * A Hex-float
454  * c Character
455  * C Widechar character (wint_t)
456  * d Decimal
457  * e Float
458  * E Float
459  * F Float
460  * F Float
461  * g Float
462  * G Float
463  * i Integer
464  * m Error message
465  * n Count
466  * o Octal
467  * p Pointer
468  * s String
469  * S Widechar string (wchar_t *)
470  * u Unsigned
471  * x Hex
472  * X Hex
473  * [] Group
474  * <> User-defined
475  *
476  * Reserved:
477  *
478  * D Binary Coded Decimal %D(length,precision) (OS/390)
479  */
480 #define SPECIFIER_CHAR 'c'
481 #define SPECIFIER_STRING 's'
482 #define SPECIFIER_DECIMAL 'd'
483 #define SPECIFIER_INTEGER 'i'
484 #define SPECIFIER_UNSIGNED 'u'
485 #define SPECIFIER_OCTAL 'o'
486 #define SPECIFIER_HEX 'x'
487 #define SPECIFIER_HEX_UPPER 'X'
488 #define SPECIFIER_FLOAT_E 'e'
489 #define SPECIFIER_FLOAT_E_UPPER 'E'
490 #define SPECIFIER_FLOAT_F 'f'
491 #define SPECIFIER_FLOAT_F_UPPER 'F'
492 #define SPECIFIER_FLOAT_G 'g'
493 #define SPECIFIER_FLOAT_G_UPPER 'G'
494 #define SPECIFIER_POINTER 'p'
495 #define SPECIFIER_GROUP '['
496 #define SPECIFIER_UNGROUP ']'
497 #define SPECIFIER_COUNT 'n'
498 #if TRIO_UNIX98
499 # define SPECIFIER_CHAR_UPPER 'C'
500 # define SPECIFIER_STRING_UPPER 'S'
501 #endif
502 #if TRIO_C99
503 # define SPECIFIER_HEXFLOAT 'a'
504 # define SPECIFIER_HEXFLOAT_UPPER 'A'
505 #endif
506 #if TRIO_GNU
507 # define SPECIFIER_ERRNO 'm'
508 #endif
509 #if TRIO_EXTENSION
510 # define SPECIFIER_BINARY 'b'
511 # define SPECIFIER_BINARY_UPPER 'B'
512 # define SPECIFIER_USER_DEFINED_BEGIN '<'
513 # define SPECIFIER_USER_DEFINED_END '>'
514 # define SPECIFIER_USER_DEFINED_SEPARATOR ':'
515 #endif
516 
517 /*
518  * QUALIFIERS:
519  *
520  *
521  * Numbers = d,i,o,u,x,X
522  * Float = a,A,e,E,f,F,g,G
523  * String = s
524  * Char = c
525  *
526  *
527  * 9$ Position
528  * Use the 9th parameter. 9 can be any number between 1 and
529  * the maximal argument
530  *
531  * 9 Width
532  * Set width to 9. 9 can be any number, but must not be postfixed
533  * by '$'
534  *
535  * h Short
536  * Numbers:
537  * (unsigned) short int
538  *
539  * hh Short short
540  * Numbers:
541  * (unsigned) char
542  *
543  * l Long
544  * Numbers:
545  * (unsigned) long int
546  * String:
547  * as the S specifier
548  * Char:
549  * as the C specifier
550  *
551  * ll Long Long
552  * Numbers:
553  * (unsigned) long long int
554  *
555  * L Long Double
556  * Float
557  * long double
558  *
559  * # Alternative
560  * Float:
561  * Decimal-point is always present
562  * String:
563  * non-printable characters are handled as \number
564  *
565  * Spacing
566  *
567  * + Sign
568  *
569  * - Alignment
570  *
571  * . Precision
572  *
573  * * Parameter
574  * print: use parameter
575  * scan: no parameter (ignore)
576  *
577  * q Quad
578  *
579  * Z size_t
580  *
581  * w Widechar
582  *
583  * ' Thousands/quote
584  * Numbers:
585  * Integer part grouped in thousands
586  * Binary numbers:
587  * Number grouped in nibbles (4 bits)
588  * String:
589  * Quoted string
590  *
591  * j intmax_t
592  * t prtdiff_t
593  * z size_t
594  *
595  * ! Sticky
596  * @ Parameter (for both print and scan)
597  *
598  * I n-bit Integer
599  * Numbers:
600  * The following options exists
601  * I8 = 8-bit integer
602  * I16 = 16-bit integer
603  * I32 = 32-bit integer
604  * I64 = 64-bit integer
605  */
606 #define QUALIFIER_POSITION '$'
607 #define QUALIFIER_SHORT 'h'
608 #define QUALIFIER_LONG 'l'
609 #define QUALIFIER_LONG_UPPER 'L'
610 #define QUALIFIER_ALTERNATIVE '#'
611 #define QUALIFIER_SPACE ' '
612 #define QUALIFIER_PLUS '+'
613 #define QUALIFIER_MINUS '-'
614 #define QUALIFIER_DOT '.'
615 #define QUALIFIER_STAR '*'
616 #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
617 #if TRIO_C99
618 # define QUALIFIER_SIZE_T 'z'
619 # define QUALIFIER_PTRDIFF_T 't'
620 # define QUALIFIER_INTMAX_T 'j'
621 #endif
622 #if TRIO_BSD || TRIO_GNU
623 # define QUALIFIER_QUAD 'q'
624 #endif
625 #if TRIO_GNU
626 # define QUALIFIER_SIZE_T_UPPER 'Z'
627 #endif
628 #if TRIO_MISC
629 # define QUALIFIER_WIDECHAR 'w'
630 #endif
631 #if TRIO_MICROSOFT
632 # define QUALIFIER_FIXED_SIZE 'I'
633 #endif
634 #if TRIO_EXTENSION
635 # define QUALIFIER_QUOTE '\''
636 # define QUALIFIER_STICKY '!'
637 # define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
638 # define QUALIFIER_PARAM '@' /* Experimental */
639 # define QUALIFIER_COLON ':' /* For scanlists */
640 # define QUALIFIER_EQUAL '=' /* For scanlists */
641 # define QUALIFIER_ROUNDING_UPPER 'R'
642 #endif
643 
644 
645 /*************************************************************************
646  *
647  * Internal Structures
648  *
649  *************************************************************************/
650 
651 /* Parameters */
652 typedef struct {
653  /* An indication of which entry in the data union is used */
654  int type;
655  /* The flags */
657  /* The width qualifier */
658  int width;
659  /* The precision qualifier */
661  /* The base qualifier */
662  int base;
663  /* The size for the variable size qualifier */
664  int varsize;
665  /* The marker of the end of the specifier */
667  /* The data from the argument list */
668  union {
669  char *string;
670 #if TRIO_WIDECHAR
671  trio_wchar_t *wstring;
672 #endif
674  union {
677  } number;
678  double doubleNumber;
679  double *doublePointer;
683  } data;
684  /* For the user-defined specifier */
686  char user_data[MAX_USER_DATA];
688 
689 /* Container for customized functions */
690 typedef struct {
691  union {
692  trio_outstream_t out;
693  trio_instream_t in;
694  } stream;
696 } trio_custom_t;
697 
698 /* General trio "class" */
699 typedef struct _trio_class_t {
700  /*
701  * The function to write characters to a stream.
702  */
703  void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
704  /*
705  * The function to read characters from a stream.
706  */
707  void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
708  /*
709  * The current location in the stream.
710  */
712  /*
713  * The character currently being processed.
714  */
715  int current;
716  /*
717  * The number of characters that would have been written/read
718  * if there had been sufficient space.
719  */
721  /*
722  * The number of characters that are actually written/read.
723  * Processed and committed will only differ for the *nprintf
724  * and *nscanf functions.
725  */
727  /*
728  * The upper limit of characters that may be written/read.
729  */
730  int max;
731  /*
732  * The last output error that was detected.
733  */
734  int error;
735 } trio_class_t;
736 
737 /* References (for user-defined callbacks) */
738 typedef struct _trio_reference_t {
742 
743 /* Registered entries (for user-defined callbacks) */
744 typedef struct _trio_userdef_t {
746  trio_callback_t callback;
747  char *name;
749 
750 /*************************************************************************
751  *
752  * Internal Variables
753  *
754  *************************************************************************/
755 
756 static TRIO_CONST char rcsid[] = "@(#)$Id$";
757 
758 /*
759  * Need this to workaround a parser bug in HP C/iX compiler that fails
760  * to resolves macro definitions that includes type 'long double',
761  * e.g: va_arg(arg_ptr, long double)
762  */
763 #if defined(TRIO_PLATFORM_MPEIX)
764 static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
765 #endif
766 
767 static TRIO_CONST char internalNullString[] = "(nil)";
768 
769 #if defined(USE_LOCALE)
770 static struct lconv *internalLocaleValues = NULL;
771 #endif
772 
773 /*
774  * UNIX98 says "in a locale where the radix character is not defined,
775  * the radix character defaults to a period (.)"
776  */
779 static char internalDecimalPoint = '.';
783 
784 static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
785 static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
787 static int internalDigitArray[128];
788 #if TRIO_EXTENSION
791 #endif
792 
793 #if TRIO_EXTENSION
797 #endif
798 
799 
800 /*************************************************************************
801  *
802  * Internal Functions
803  *
804  ************************************************************************/
805 
806 #if defined(TRIO_MINIMAL)
807 # define TRIO_STRING_PUBLIC static
808 # include "triostr.c"
809 #endif /* defined(TRIO_MINIMAL) */
810 
811 /*************************************************************************
812  * TrioIsQualifier
813  *
814  * Description:
815  * Remember to add all new qualifiers to this function.
816  * QUALIFIER_POSITION must not be added.
817  */
819 TrioIsQualifier
820 TRIO_ARGS1((character),
821  TRIO_CONST char character)
822 {
823  /* QUALIFIER_POSITION is not included */
824  switch (character)
825  {
826  case '0': case '1': case '2': case '3': case '4':
827  case '5': case '6': case '7': case '8': case '9':
828  case QUALIFIER_PLUS:
829  case QUALIFIER_MINUS:
830  case QUALIFIER_SPACE:
831  case QUALIFIER_DOT:
832  case QUALIFIER_STAR:
834  case QUALIFIER_SHORT:
835  case QUALIFIER_LONG:
838 #if defined(QUALIFIER_SIZE_T)
839  case QUALIFIER_SIZE_T:
840 #endif
841 #if defined(QUALIFIER_PTRDIFF_T)
842  case QUALIFIER_PTRDIFF_T:
843 #endif
844 #if defined(QUALIFIER_INTMAX_T)
845  case QUALIFIER_INTMAX_T:
846 #endif
847 #if defined(QUALIFIER_QUAD)
848  case QUALIFIER_QUAD:
849 #endif
850 #if defined(QUALIFIER_SIZE_T_UPPER)
852 #endif
853 #if defined(QUALIFIER_WIDECHAR)
854  case QUALIFIER_WIDECHAR:
855 #endif
856 #if defined(QUALIFIER_QUOTE)
857  case QUALIFIER_QUOTE:
858 #endif
859 #if defined(QUALIFIER_STICKY)
860  case QUALIFIER_STICKY:
861 #endif
862 #if defined(QUALIFIER_VARSIZE)
863  case QUALIFIER_VARSIZE:
864 #endif
865 #if defined(QUALIFIER_PARAM)
866  case QUALIFIER_PARAM:
867 #endif
868 #if defined(QUALIFIER_FIXED_SIZE)
870 #endif
871 #if defined(QUALIFIER_ROUNDING_UPPER)
873 #endif
874  return TRUE;
875  default:
876  return FALSE;
877  }
878 }
879 
880 /*************************************************************************
881  * TrioSetLocale
882  */
883 #if defined(USE_LOCALE)
884 TRIO_PRIVATE void
885 TrioSetLocale(TRIO_NOARGS)
886 {
887  internalLocaleValues = (struct lconv *)localeconv();
888  if (internalLocaleValues)
889  {
890  if ((internalLocaleValues->decimal_point) &&
891  (internalLocaleValues->decimal_point[0] != NIL))
892  {
893  internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
895  {
896  internalDecimalPoint = internalLocaleValues->decimal_point[0];
897  }
898  else
899  {
901  trio_copy_max(internalDecimalPointString,
903  internalLocaleValues->decimal_point);
904  }
905  }
906  if ((internalLocaleValues->thousands_sep) &&
907  (internalLocaleValues->thousands_sep[0] != NIL))
908  {
909  trio_copy_max(internalThousandSeparator,
911  internalLocaleValues->thousands_sep);
913  }
914  if ((internalLocaleValues->grouping) &&
915  (internalLocaleValues->grouping[0] != NIL))
916  {
917  trio_copy_max(internalGrouping,
918  sizeof(internalGrouping),
919  internalLocaleValues->grouping);
920  }
921  }
922 }
923 #endif /* defined(USE_LOCALE) */
924 
925 TRIO_PRIVATE int
926 TrioCalcThousandSeparatorLength
928  int digits)
929 {
930 #if TRIO_EXTENSION
931  int count = 0;
932  int step = NO_GROUPING;
933  char *groupingPointer = internalGrouping;
934 
935  while (digits > 0)
936  {
937  if (*groupingPointer == CHAR_MAX)
938  {
939  /* Disable grouping */
940  break; /* while */
941  }
942  else if (*groupingPointer == 0)
943  {
944  /* Repeat last group */
945  if (step == NO_GROUPING)
946  {
947  /* Error in locale */
948  break; /* while */
949  }
950  }
951  else
952  {
953  step = *groupingPointer++;
954  }
955  if (digits > step)
957  digits -= step;
958  }
959  return count;
960 #else
961  return 0;
962 #endif
963 }
964 
966 TrioFollowedBySeparator
967 TRIO_ARGS1((position),
968  int position)
969 {
970 #if TRIO_EXTENSION
971  int step = 0;
972  char *groupingPointer = internalGrouping;
973 
974  position--;
975  if (position == 0)
976  return FALSE;
977  while (position > 0)
978  {
979  if (*groupingPointer == CHAR_MAX)
980  {
981  /* Disable grouping */
982  break; /* while */
983  }
984  else if (*groupingPointer != 0)
985  {
986  step = *groupingPointer++;
987  }
988  if (step == 0)
989  break;
990  position -= step;
991  }
992  return (position == 0);
993 #else
994  return FALSE;
995 #endif
996 }
997 
998 /*************************************************************************
999  * TrioGetPosition
1000  *
1001  * Get the %n$ position.
1002  */
1003 TRIO_PRIVATE int
1004 TrioGetPosition
1005 TRIO_ARGS2((format, indexPointer),
1006  TRIO_CONST char *format,
1007  int *indexPointer)
1008 {
1009 #if TRIO_UNIX98
1010  char *tmpformat;
1011  int number = 0;
1012  int index = *indexPointer;
1013 
1014  number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
1015  index = (int)(tmpformat - format);
1016  if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
1017  {
1018  *indexPointer = index;
1019  /*
1020  * number is decreased by 1, because n$ starts from 1, whereas
1021  * the array it is indexing starts from 0.
1022  */
1023  return number - 1;
1024  }
1025 #endif
1026  return NO_POSITION;
1027 }
1028 
1029 #if TRIO_EXTENSION
1030 /*************************************************************************
1031  * TrioFindNamespace
1032  *
1033  * Find registered user-defined specifier.
1034  * The prev argument is used for optimization only.
1035  */
1037 TrioFindNamespace
1039  TRIO_CONST char *name,
1040  trio_userdef_t **prev)
1041 {
1042  trio_userdef_t *def;
1043 
1044  if (internalEnterCriticalRegion)
1046 
1047  for (def = internalUserDef; def; def = def->next)
1048  {
1049  /* Case-sensitive string comparison */
1050  if (trio_equal_case(def->name, name))
1051  break;
1052 
1053  if (prev)
1054  *prev = def;
1055  }
1056 
1057  if (internalLeaveCriticalRegion)
1059 
1060  return def;
1061 }
1062 #endif
1063 
1064 /*************************************************************************
1065  * TrioPower
1066  *
1067  * Description:
1068  * Calculate pow(base, exponent), where number and exponent are integers.
1069  */
1071 TrioPower
1072 TRIO_ARGS2((number, exponent),
1073  int number,
1074  int exponent)
1075 {
1077 
1078  if (number == 10)
1079  {
1080  switch (exponent)
1081  {
1082  /* Speed up calculation of common cases */
1083  case 0:
1084  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
1085  break;
1086  case 1:
1087  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
1088  break;
1089  case 2:
1090  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
1091  break;
1092  case 3:
1093  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
1094  break;
1095  case 4:
1096  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
1097  break;
1098  case 5:
1099  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
1100  break;
1101  case 6:
1102  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
1103  break;
1104  case 7:
1105  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
1106  break;
1107  case 8:
1108  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
1109  break;
1110  case 9:
1111  result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
1112  break;
1113  default:
1114  result = powl((trio_long_double_t)number,
1115  (trio_long_double_t)exponent);
1116  break;
1117  }
1118  }
1119  else
1120  {
1121  return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
1122  }
1123  return result;
1124 }
1125 
1126 /*************************************************************************
1127  * TrioLogarithm
1128  */
1129 TRIO_PRIVATE double
1130 TrioLogarithm
1132  double number,
1133  int base)
1134 {
1135  double result;
1136 
1137  if (number <= 0.0)
1138  {
1139  /* xlC crashes on log(0) */
1140  result = (number == 0.0) ? trio_ninf() : trio_nan();
1141  }
1142  else
1143  {
1144  if (base == 10)
1145  {
1146  result = log10(number);
1147  }
1148  else
1149  {
1150  result = log10(number) / log10((double)base);
1151  }
1152  }
1153  return result;
1154 }
1155 
1156 /*************************************************************************
1157  * TrioLogarithmBase
1158  */
1159 TRIO_PRIVATE double
1160 TrioLogarithmBase
1162  int base)
1163 {
1164  switch (base)
1165  {
1166  case BASE_BINARY : return 1.0;
1167  case BASE_OCTAL : return 3.0;
1168  case BASE_DECIMAL: return 3.321928094887362345;
1169  case BASE_HEX : return 4.0;
1170  default : return TrioLogarithm((double)base, 2);
1171  }
1172 }
1173 
1174 /*************************************************************************
1175  * TrioParse
1176  *
1177  * Description:
1178  * Parse the format string
1179  */
1180 TRIO_PRIVATE int
1181 TrioParse
1182 TRIO_ARGS5((type, format, parameters, arglist, argarray),
1183  int type,
1184  TRIO_CONST char *format,
1185  trio_parameter_t *parameters,
1187  trio_pointer_t *argarray)
1188 {
1189  /* Count the number of times a parameter is referenced */
1190  unsigned short usedEntries[MAX_PARAMETERS];
1191  /* Parameter counters */
1192  int parameterPosition;
1193  int currentParam;
1194  int maxParam = -1;
1195  /* Utility variables */
1197  int width;
1198  int precision;
1199  int varsize;
1200  int base;
1201  int index; /* Index into formatting string */
1202  int dots; /* Count number of dots in modifier part */
1203  BOOLEAN_T positional; /* Does the specifier have a positional? */
1204  BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
1205  /*
1206  * indices specifies the order in which the parameters must be
1207  * read from the va_args (this is necessary to handle positionals)
1208  */
1209  int indices[MAX_PARAMETERS];
1210  int pos = 0;
1211  /* Various variables */
1212  char ch;
1213 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1214  int charlen;
1215 #endif
1216  int save_errno;
1217  int i = -1;
1218  int num;
1219  char *tmpformat;
1220 
1221  /* One and only one of arglist and argarray must be used */
1222  assert((arglist != NULL) ^ (argarray != NULL));
1223 
1224  /*
1225  * The 'parameters' array is not initialized, but we need to
1226  * know which entries we have used.
1227  */
1228  memset(usedEntries, 0, sizeof(usedEntries));
1229 
1230  save_errno = errno;
1231  index = 0;
1232  parameterPosition = 0;
1233 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1234  (void)mblen(NULL, 0);
1235 #endif
1236 
1237  while (format[index])
1238  {
1239 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1240  if (! isascii(format[index]))
1241  {
1242  /*
1243  * Multibyte characters cannot be legal specifiers or
1244  * modifiers, so we skip over them.
1245  */
1246  charlen = mblen(&format[index], MB_LEN_MAX);
1247  index += (charlen > 0) ? charlen : 1;
1248  continue; /* while */
1249  }
1250 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
1251  if (CHAR_IDENTIFIER == format[index++])
1252  {
1253  if (CHAR_IDENTIFIER == format[index])
1254  {
1255  index++;
1256  continue; /* while */
1257  }
1258 
1259  flags = FLAGS_NEW;
1260  dots = 0;
1261  currentParam = TrioGetPosition(format, &index);
1262  positional = (NO_POSITION != currentParam);
1263  if (!positional)
1264  {
1265  /* We have no positional, get the next counter */
1266  currentParam = parameterPosition;
1267  }
1268  if(currentParam >= MAX_PARAMETERS)
1269  {
1270  /* Bail out completely to make the error more obvious */
1271  return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
1272  }
1273 
1274  if (currentParam > maxParam)
1275  maxParam = currentParam;
1276 
1277  /* Default values */
1278  width = NO_WIDTH;
1279  precision = NO_PRECISION;
1280  base = NO_BASE;
1281  varsize = NO_SIZE;
1282 
1283  while (TrioIsQualifier(format[index]))
1284  {
1285  ch = format[index++];
1286 
1287  switch (ch)
1288  {
1289  case QUALIFIER_SPACE:
1290  flags |= FLAGS_SPACE;
1291  break;
1292 
1293  case QUALIFIER_PLUS:
1294  flags |= FLAGS_SHOWSIGN;
1295  break;
1296 
1297  case QUALIFIER_MINUS:
1298  flags |= FLAGS_LEFTADJUST;
1299  flags &= ~FLAGS_NILPADDING;
1300  break;
1301 
1302  case QUALIFIER_ALTERNATIVE:
1303  flags |= FLAGS_ALTERNATIVE;
1304  break;
1305 
1306  case QUALIFIER_DOT:
1307  if (dots == 0) /* Precision */
1308  {
1309  dots++;
1310 
1311  /* Skip if no precision */
1312  if (QUALIFIER_DOT == format[index])
1313  break;
1314 
1315  /* After the first dot we have the precision */
1316  flags |= FLAGS_PRECISION;
1317  if ((QUALIFIER_STAR == format[index])
1318 #if defined(QUALIFIER_PARAM)
1319  || (QUALIFIER_PARAM == format[index])
1320 #endif
1321  )
1322  {
1323  index++;
1324  flags |= FLAGS_PRECISION_PARAMETER;
1325 
1326  precision = TrioGetPosition(format, &index);
1327  if (precision == NO_POSITION)
1328  {
1329  parameterPosition++;
1330  if (positional)
1331  precision = parameterPosition;
1332  else
1333  {
1334  precision = currentParam;
1335  currentParam = precision + 1;
1336  }
1337  }
1338  else
1339  {
1340  if (! positional)
1341  currentParam = precision + 1;
1342  if (width > maxParam)
1343  maxParam = precision;
1344  }
1345  if (currentParam > maxParam)
1346  maxParam = currentParam;
1347  }
1348  else
1349  {
1350  precision = trio_to_long(&format[index],
1351  &tmpformat,
1352  BASE_DECIMAL);
1353  index = (int)(tmpformat - format);
1354  }
1355  }
1356  else if (dots == 1) /* Base */
1357  {
1358  dots++;
1359 
1360  /* After the second dot we have the base */
1361  flags |= FLAGS_BASE;
1362  if ((QUALIFIER_STAR == format[index])
1363 #if defined(QUALIFIER_PARAM)
1364  || (QUALIFIER_PARAM == format[index])
1365 #endif
1366  )
1367  {
1368  index++;
1369  flags |= FLAGS_BASE_PARAMETER;
1370  base = TrioGetPosition(format, &index);
1371  if (base == NO_POSITION)
1372  {
1373  parameterPosition++;
1374  if (positional)
1375  base = parameterPosition;
1376  else
1377  {
1378  base = currentParam;
1379  currentParam = base + 1;
1380  }
1381  }
1382  else
1383  {
1384  if (! positional)
1385  currentParam = base + 1;
1386  if (base > maxParam)
1387  maxParam = base;
1388  }
1389  if (currentParam > maxParam)
1390  maxParam = currentParam;
1391  }
1392  else
1393  {
1394  base = trio_to_long(&format[index],
1395  &tmpformat,
1396  BASE_DECIMAL);
1397  if (base > MAX_BASE)
1398  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1399  index = (int)(tmpformat - format);
1400  }
1401  }
1402  else
1403  {
1404  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1405  }
1406  break; /* QUALIFIER_DOT */
1407 
1408 #if defined(QUALIFIER_PARAM)
1409  case QUALIFIER_PARAM:
1410  type = TYPE_PRINT;
1411  /* FALLTHROUGH */
1412 #endif
1413  case QUALIFIER_STAR:
1414  /* This has different meanings for print and scan */
1415  if (TYPE_PRINT == type)
1416  {
1417  /* Read with from parameter */
1418  flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1419  width = TrioGetPosition(format, &index);
1420  if (width == NO_POSITION)
1421  {
1422  parameterPosition++;
1423  if (positional)
1424  width = parameterPosition;
1425  else
1426  {
1427  width = currentParam;
1428  currentParam = width + 1;
1429  }
1430  }
1431  else
1432  {
1433  if (! positional)
1434  currentParam = width + 1;
1435  if (width > maxParam)
1436  maxParam = width;
1437  }
1438  if (currentParam > maxParam)
1439  maxParam = currentParam;
1440  }
1441  else
1442  {
1443  /* Scan, but do not store result */
1444  flags |= FLAGS_IGNORE;
1445  }
1446 
1447  break; /* QUALIFIER_STAR */
1448 
1449  case '0':
1450  if (! (flags & FLAGS_LEFTADJUST))
1451  flags |= FLAGS_NILPADDING;
1452  /* FALLTHROUGH */
1453  case '1': case '2': case '3': case '4':
1454  case '5': case '6': case '7': case '8': case '9':
1455  flags |= FLAGS_WIDTH;
1456  /* &format[index - 1] is used to "rewind" the read
1457  * character from format
1458  */
1459  width = trio_to_long(&format[index - 1],
1460  &tmpformat,
1461  BASE_DECIMAL);
1462  index = (int)(tmpformat - format);
1463  break;
1464 
1465  case QUALIFIER_SHORT:
1466  if (flags & FLAGS_SHORTSHORT)
1467  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1468  else if (flags & FLAGS_SHORT)
1469  flags |= FLAGS_SHORTSHORT;
1470  else
1471  flags |= FLAGS_SHORT;
1472  break;
1473 
1474  case QUALIFIER_LONG:
1475  if (flags & FLAGS_QUAD)
1476  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1477  else if (flags & FLAGS_LONG)
1478  flags |= FLAGS_QUAD;
1479  else
1480  flags |= FLAGS_LONG;
1481  break;
1482 
1483  case QUALIFIER_LONG_UPPER:
1484  flags |= FLAGS_LONGDOUBLE;
1485  break;
1486 
1487 #if defined(QUALIFIER_SIZE_T)
1488  case QUALIFIER_SIZE_T:
1489  flags |= FLAGS_SIZE_T;
1490  /* Modify flags for later truncation of number */
1491  if (sizeof(size_t) == sizeof(trio_ulonglong_t))
1492  flags |= FLAGS_QUAD;
1493  else if (sizeof(size_t) == sizeof(long))
1494  flags |= FLAGS_LONG;
1495  break;
1496 #endif
1497 
1498 #if defined(QUALIFIER_PTRDIFF_T)
1499  case QUALIFIER_PTRDIFF_T:
1500  flags |= FLAGS_PTRDIFF_T;
1501  if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
1502  flags |= FLAGS_QUAD;
1503  else if (sizeof(ptrdiff_t) == sizeof(long))
1504  flags |= FLAGS_LONG;
1505  break;
1506 #endif
1507 
1508 #if defined(QUALIFIER_INTMAX_T)
1509  case QUALIFIER_INTMAX_T:
1510  flags |= FLAGS_INTMAX_T;
1511  if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
1512  flags |= FLAGS_QUAD;
1513  else if (sizeof(trio_intmax_t) == sizeof(long))
1514  flags |= FLAGS_LONG;
1515  break;
1516 #endif
1517 
1518 #if defined(QUALIFIER_QUAD)
1519  case QUALIFIER_QUAD:
1520  flags |= FLAGS_QUAD;
1521  break;
1522 #endif
1523 
1524 #if defined(QUALIFIER_FIXED_SIZE)
1525  case QUALIFIER_FIXED_SIZE:
1526  if (flags & FLAGS_FIXED_SIZE)
1527  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1528 
1529  if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
1531  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1532 
1533  if ((format[index] == '6') &&
1534  (format[index + 1] == '4'))
1535  {
1536  varsize = sizeof(trio_int64_t);
1537  index += 2;
1538  }
1539  else if ((format[index] == '3') &&
1540  (format[index + 1] == '2'))
1541  {
1542  varsize = sizeof(trio_int32_t);
1543  index += 2;
1544  }
1545  else if ((format[index] == '1') &&
1546  (format[index + 1] == '6'))
1547  {
1548  varsize = sizeof(trio_int16_t);
1549  index += 2;
1550  }
1551  else if (format[index] == '8')
1552  {
1553  varsize = sizeof(trio_int8_t);
1554  index++;
1555  }
1556  else
1557  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1558 
1559  flags |= FLAGS_FIXED_SIZE;
1560  break;
1561 #endif
1562 
1563 #if defined(QUALIFIER_WIDECHAR)
1564  case QUALIFIER_WIDECHAR:
1565  flags |= FLAGS_WIDECHAR;
1566  break;
1567 #endif
1568 
1569 #if defined(QUALIFIER_SIZE_T_UPPER)
1571  break;
1572 #endif
1573 
1574 #if defined(QUALIFIER_QUOTE)
1575  case QUALIFIER_QUOTE:
1576  flags |= FLAGS_QUOTE;
1577  break;
1578 #endif
1579 
1580 #if defined(QUALIFIER_STICKY)
1581  case QUALIFIER_STICKY:
1582  flags |= FLAGS_STICKY;
1583  gotSticky = TRUE;
1584  break;
1585 #endif
1586 
1587 #if defined(QUALIFIER_VARSIZE)
1588  case QUALIFIER_VARSIZE:
1589  flags |= FLAGS_VARSIZE_PARAMETER;
1590  parameterPosition++;
1591  if (positional)
1592  varsize = parameterPosition;
1593  else
1594  {
1595  varsize = currentParam;
1596  currentParam = varsize + 1;
1597  }
1598  if (currentParam > maxParam)
1599  maxParam = currentParam;
1600  break;
1601 #endif
1602 
1603 #if defined(QUALIFIER_ROUNDING_UPPER)
1605  flags |= FLAGS_ROUNDING;
1606  break;
1607 #endif
1608 
1609  default:
1610  /* Bail out completely to make the error more obvious */
1611  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1612  }
1613  } /* while qualifier */
1614 
1615  /*
1616  * Parameters only need the type and value. The value is
1617  * read later.
1618  */
1619  if (flags & FLAGS_WIDTH_PARAMETER)
1620  {
1621  usedEntries[width] += 1;
1622  parameters[pos].type = FORMAT_PARAMETER;
1623  parameters[pos].flags = 0;
1624  indices[width] = pos;
1625  width = pos++;
1626  }
1627  if (flags & FLAGS_PRECISION_PARAMETER)
1628  {
1629  usedEntries[precision] += 1;
1630  parameters[pos].type = FORMAT_PARAMETER;
1631  parameters[pos].flags = 0;
1632  indices[precision] = pos;
1633  precision = pos++;
1634  }
1635  if (flags & FLAGS_BASE_PARAMETER)
1636  {
1637  usedEntries[base] += 1;
1638  parameters[pos].type = FORMAT_PARAMETER;
1639  parameters[pos].flags = 0;
1640  indices[base] = pos;
1641  base = pos++;
1642  }
1643  if (flags & FLAGS_VARSIZE_PARAMETER)
1644  {
1645  usedEntries[varsize] += 1;
1646  parameters[pos].type = FORMAT_PARAMETER;
1647  parameters[pos].flags = 0;
1648  indices[varsize] = pos;
1649  varsize = pos++;
1650  }
1651 
1652  indices[currentParam] = pos;
1653 
1654  switch (format[index++])
1655  {
1656 #if defined(SPECIFIER_CHAR_UPPER)
1657  case SPECIFIER_CHAR_UPPER:
1658  flags |= FLAGS_WIDECHAR;
1659  /* FALLTHROUGH */
1660 #endif
1661  case SPECIFIER_CHAR:
1662  if (flags & FLAGS_LONG)
1663  flags |= FLAGS_WIDECHAR;
1664  else if (flags & FLAGS_SHORT)
1665  flags &= ~FLAGS_WIDECHAR;
1666  parameters[pos].type = FORMAT_CHAR;
1667  break;
1668 
1669 #if defined(SPECIFIER_STRING_UPPER)
1671  flags |= FLAGS_WIDECHAR;
1672  /* FALLTHROUGH */
1673 #endif
1674  case SPECIFIER_STRING:
1675  if (flags & FLAGS_LONG)
1676  flags |= FLAGS_WIDECHAR;
1677  else if (flags & FLAGS_SHORT)
1678  flags &= ~FLAGS_WIDECHAR;
1679  parameters[pos].type = FORMAT_STRING;
1680  break;
1681 
1682  case SPECIFIER_GROUP:
1683  if (TYPE_SCAN == type)
1684  {
1685  int depth = 1;
1686  parameters[pos].type = FORMAT_GROUP;
1687  if (format[index] == QUALIFIER_CIRCUMFLEX)
1688  index++;
1689  if (format[index] == SPECIFIER_UNGROUP)
1690  index++;
1691  if (format[index] == QUALIFIER_MINUS)
1692  index++;
1693  /* Skip nested brackets */
1694  while (format[index] != NIL)
1695  {
1696  if (format[index] == SPECIFIER_GROUP)
1697  {
1698  depth++;
1699  }
1700  else if (format[index] == SPECIFIER_UNGROUP)
1701  {
1702  if (--depth <= 0)
1703  {
1704  index++;
1705  break;
1706  }
1707  }
1708  index++;
1709  }
1710  }
1711  break;
1712 
1713  case SPECIFIER_INTEGER:
1714  parameters[pos].type = FORMAT_INT;
1715  break;
1716 
1717  case SPECIFIER_UNSIGNED:
1718  flags |= FLAGS_UNSIGNED;
1719  parameters[pos].type = FORMAT_INT;
1720  break;
1721 
1722  case SPECIFIER_DECIMAL:
1723  /* Disable base modifier */
1724  flags &= ~FLAGS_BASE_PARAMETER;
1725  base = BASE_DECIMAL;
1726  parameters[pos].type = FORMAT_INT;
1727  break;
1728 
1729  case SPECIFIER_OCTAL:
1730  flags |= FLAGS_UNSIGNED;
1731  flags &= ~FLAGS_BASE_PARAMETER;
1732  base = BASE_OCTAL;
1733  parameters[pos].type = FORMAT_INT;
1734  break;
1735 
1736 #if defined(SPECIFIER_BINARY)
1738  flags |= FLAGS_UPPER;
1739  /* FALLTHROUGH */
1740  case SPECIFIER_BINARY:
1741  flags |= FLAGS_NILPADDING;
1742  flags &= ~FLAGS_BASE_PARAMETER;
1743  base = BASE_BINARY;
1744  parameters[pos].type = FORMAT_INT;
1745  break;
1746 #endif
1747 
1748  case SPECIFIER_HEX_UPPER:
1749  flags |= FLAGS_UPPER;
1750  /* FALLTHROUGH */
1751  case SPECIFIER_HEX:
1752  flags |= FLAGS_UNSIGNED;
1753  flags &= ~FLAGS_BASE_PARAMETER;
1754  base = BASE_HEX;
1755  parameters[pos].type = FORMAT_INT;
1756  break;
1757 
1759  flags |= FLAGS_UPPER;
1760  /* FALLTHROUGH */
1761  case SPECIFIER_FLOAT_E:
1762  flags |= FLAGS_FLOAT_E;
1763  parameters[pos].type = FORMAT_DOUBLE;
1764  break;
1765 
1767  flags |= FLAGS_UPPER;
1768  /* FALLTHROUGH */
1769  case SPECIFIER_FLOAT_G:
1770  flags |= FLAGS_FLOAT_G;
1771  parameters[pos].type = FORMAT_DOUBLE;
1772  break;
1773 
1775  flags |= FLAGS_UPPER;
1776  /* FALLTHROUGH */
1777  case SPECIFIER_FLOAT_F:
1778  parameters[pos].type = FORMAT_DOUBLE;
1779  break;
1780 
1781  case SPECIFIER_POINTER:
1782  if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1783  flags |= FLAGS_QUAD;
1784  else if (sizeof(trio_pointer_t) == sizeof(long))
1785  flags |= FLAGS_LONG;
1786  parameters[pos].type = FORMAT_POINTER;
1787  break;
1788 
1789  case SPECIFIER_COUNT:
1790  parameters[pos].type = FORMAT_COUNT;
1791  break;
1792 
1793 #if defined(SPECIFIER_HEXFLOAT)
1794 # if defined(SPECIFIER_HEXFLOAT_UPPER)
1796  flags |= FLAGS_UPPER;
1797  /* FALLTHROUGH */
1798 # endif
1799  case SPECIFIER_HEXFLOAT:
1800  base = BASE_HEX;
1801  parameters[pos].type = FORMAT_DOUBLE;
1802  break;
1803 #endif
1804 
1805 #if defined(FORMAT_ERRNO)
1806  case SPECIFIER_ERRNO:
1807  parameters[pos].type = FORMAT_ERRNO;
1808  break;
1809 #endif
1810 
1811 #if defined(SPECIFIER_USER_DEFINED_BEGIN)
1813  {
1814  unsigned int max;
1815  int without_namespace = TRUE;
1816 
1817  parameters[pos].type = FORMAT_USER_DEFINED;
1818  parameters[pos].user_name[0] = NIL;
1819  tmpformat = (char *)&format[index];
1820 
1821  while ((ch = format[index]))
1822  {
1823  index++;
1824  if (ch == SPECIFIER_USER_DEFINED_END)
1825  {
1826  if (without_namespace)
1827  {
1828  /* We must get the handle first */
1829  parameters[pos].type = FORMAT_PARAMETER;
1830  parameters[pos].indexAfterSpecifier = index;
1831  parameters[pos].flags = FLAGS_USER_DEFINED;
1832  /* Adjust parameters for insertion of new one */
1833  pos++;
1834  usedEntries[currentParam] += 1;
1835  parameters[pos].type = FORMAT_USER_DEFINED;
1836  currentParam++;
1837  indices[currentParam] = pos;
1838  if (currentParam > maxParam)
1839  maxParam = currentParam;
1840  }
1841  /* Copy the user data */
1842  max = (unsigned int)(&format[index] - tmpformat);
1843  if (max > MAX_USER_DATA)
1844  max = MAX_USER_DATA;
1845  trio_copy_max(parameters[pos].user_data,
1846  max,
1847  tmpformat);
1848  break; /* while */
1849  }
1851  {
1852  without_namespace = FALSE;
1853  /* Copy the namespace for later looking-up */
1854  max = (int)(&format[index] - tmpformat);
1855  if (max > MAX_USER_NAME)
1856  max = MAX_USER_NAME;
1857  trio_copy_max(parameters[pos].user_name,
1858  max,
1859  tmpformat);
1860  tmpformat = (char *)&format[index];
1861  }
1862  }
1863  if (ch != SPECIFIER_USER_DEFINED_END)
1864  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1865  }
1866  break;
1867 #endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
1868 
1869  default:
1870  /* Bail out completely to make the error more obvious */
1871  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1872  }
1873 
1874  /* Count the number of times this entry has been used */
1875  usedEntries[currentParam] += 1;
1876 
1877  /* Find last sticky parameters */
1878  if (gotSticky && !(flags & FLAGS_STICKY))
1879  {
1880  for (i = pos - 1; i >= 0; i--)
1881  {
1882  if (parameters[i].type == FORMAT_PARAMETER)
1883  continue;
1884  if ((parameters[i].flags & FLAGS_STICKY) &&
1885  (parameters[i].type == parameters[pos].type))
1886  {
1887  /* Do not overwrite current qualifiers */
1888  flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
1889  if (width == NO_WIDTH)
1890  width = parameters[i].width;
1891  if (precision == NO_PRECISION)
1892  precision = parameters[i].precision;
1893  if (base == NO_BASE)
1894  base = parameters[i].base;
1895  break;
1896  }
1897  }
1898  }
1899 
1900  parameters[pos].indexAfterSpecifier = index;
1901  parameters[pos].flags = flags;
1902  parameters[pos].width = width;
1903  parameters[pos].precision = precision;
1904  parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1905  parameters[pos].varsize = varsize;
1906  pos++;
1907 
1908  if (! positional)
1909  parameterPosition++;
1910 
1911  } /* if identifier */
1912 
1913  } /* while format characters left */
1914 
1915  for (num = 0; num <= maxParam; num++)
1916  {
1917  if (usedEntries[num] != 1)
1918  {
1919  if (usedEntries[num] == 0) /* gap detected */
1920  return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1921  else /* double references detected */
1922  return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1923  }
1924 
1925  i = indices[num];
1926 
1927  /*
1928  * FORMAT_PARAMETERS are only present if they must be read,
1929  * so it makes no sense to check the ignore flag (besides,
1930  * the flags variable is not set for that particular type)
1931  */
1932  if ((parameters[i].type != FORMAT_PARAMETER) &&
1933  (parameters[i].flags & FLAGS_IGNORE))
1934  continue; /* for all arguments */
1935 
1936  /*
1937  * The stack arguments are read according to ANSI C89
1938  * default argument promotions:
1939  *
1940  * char = int
1941  * short = int
1942  * unsigned char = unsigned int
1943  * unsigned short = unsigned int
1944  * float = double
1945  *
1946  * In addition to the ANSI C89 these types are read (the
1947  * default argument promotions of C99 has not been
1948  * considered yet)
1949  *
1950  * long long
1951  * long double
1952  * size_t
1953  * ptrdiff_t
1954  * intmax_t
1955  */
1956  switch (parameters[i].type)
1957  {
1958  case FORMAT_GROUP:
1959  case FORMAT_STRING:
1960 #if TRIO_WIDECHAR
1961  if (flags & FLAGS_WIDECHAR)
1962  {
1963  parameters[i].data.wstring = (argarray == NULL)
1964  ? va_arg(TRIO_VA_LIST_DEREF(arglist), trio_wchar_t *)
1965  : (trio_wchar_t *)(argarray[num]);
1966  }
1967  else
1968 #endif
1969  {
1970  parameters[i].data.string = (argarray == NULL)
1971  ? va_arg(TRIO_VA_LIST_DEREF(arglist), char *)
1972  : (char *)(argarray[num]);
1973  }
1974  break;
1975 
1976 #if defined(FORMAT_USER_DEFINED)
1977  case FORMAT_USER_DEFINED:
1978 #endif
1979  case FORMAT_POINTER:
1980  case FORMAT_COUNT:
1981  case FORMAT_UNKNOWN:
1982  parameters[i].data.pointer = (argarray == NULL)
1984  : argarray[num];
1985  break;
1986 
1987  case FORMAT_CHAR:
1988  case FORMAT_INT:
1989  if (TYPE_SCAN == type)
1990  {
1991  if (argarray == NULL)
1992  parameters[i].data.pointer =
1994  else
1995  {
1996  if (parameters[i].type == FORMAT_CHAR)
1997  parameters[i].data.pointer =
1998  (trio_pointer_t)((char *)argarray[num]);
1999  else if (parameters[i].flags & FLAGS_SHORT)
2000  parameters[i].data.pointer =
2001  (trio_pointer_t)((short *)argarray[num]);
2002  else
2003  parameters[i].data.pointer =
2004  (trio_pointer_t)((int *)argarray[num]);
2005  }
2006  }
2007  else
2008  {
2009 #if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
2010  if (parameters[i].flags
2012  {
2013  if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
2014  {
2015  /*
2016  * Variable sizes are mapped onto the fixed sizes, in
2017  * accordance with integer promotion.
2018  *
2019  * Please note that this may not be portable, as we
2020  * only guess the size, not the layout of the numbers.
2021  * For example, if int is little-endian, and long is
2022  * big-endian, then this will fail.
2023  */
2024  varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
2025  }
2026  else
2027  {
2028  /* Used for the I<bits> modifiers */
2029  varsize = parameters[i].varsize;
2030  }
2031  parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
2032 
2033  if (varsize <= (int)sizeof(int))
2034  ;
2035  else if (varsize <= (int)sizeof(long))
2036  parameters[i].flags |= FLAGS_LONG;
2037 #if defined(QUALIFIER_INTMAX_T)
2038  else if (varsize <= (int)sizeof(trio_longlong_t))
2039  parameters[i].flags |= FLAGS_QUAD;
2040  else
2041  parameters[i].flags |= FLAGS_INTMAX_T;
2042 #else
2043  else
2044  parameters[i].flags |= FLAGS_QUAD;
2045 #endif
2046  }
2047 #endif /* defined(QUALIFIER_VARSIZE) */
2048 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2049  if (parameters[i].flags & FLAGS_SIZE_T)
2050  parameters[i].data.number.as_unsigned = (argarray == NULL)
2051  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), size_t)
2052  : (trio_uintmax_t)(*((size_t *)argarray[num]));
2053  else
2054 #endif
2055 #if defined(QUALIFIER_PTRDIFF_T)
2056  if (parameters[i].flags & FLAGS_PTRDIFF_T)
2057  parameters[i].data.number.as_unsigned = (argarray == NULL)
2059  : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
2060  else
2061 #endif
2062 #if defined(QUALIFIER_INTMAX_T)
2063  if (parameters[i].flags & FLAGS_INTMAX_T)
2064  parameters[i].data.number.as_unsigned = (argarray == NULL)
2066  : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
2067  else
2068 #endif
2069  if (parameters[i].flags & FLAGS_QUAD)
2070  parameters[i].data.number.as_unsigned = (argarray == NULL)
2072  : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
2073  else if (parameters[i].flags & FLAGS_LONG)
2074  parameters[i].data.number.as_unsigned = (argarray == NULL)
2075  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), long)
2076  : (trio_uintmax_t)(*((long *)argarray[num]));
2077  else
2078  {
2079  if (argarray == NULL)
2080  parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int);
2081  else
2082  {
2083  if (parameters[i].type == FORMAT_CHAR)
2084  parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
2085  else if (parameters[i].flags & FLAGS_SHORT)
2086  parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
2087  else
2088  parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
2089  }
2090  }
2091  }
2092  break;
2093 
2094  case FORMAT_PARAMETER:
2095  /*
2096  * The parameter for the user-defined specifier is a pointer,
2097  * whereas the rest (width, precision, base) uses an integer.
2098  */
2099  if (parameters[i].flags & FLAGS_USER_DEFINED)
2100  parameters[i].data.pointer = (argarray == NULL)
2102  : argarray[num];
2103  else
2104  parameters[i].data.number.as_unsigned = (argarray == NULL)
2105  ? (trio_uintmax_t)va_arg(TRIO_VA_LIST_DEREF(arglist), int)
2106  : (trio_uintmax_t)(*((int *)argarray[num]));
2107  break;
2108 
2109  case FORMAT_DOUBLE:
2110  if (TYPE_SCAN == type)
2111  {
2112  if (parameters[i].flags & FLAGS_LONGDOUBLE)
2113  parameters[i].data.longdoublePointer = (argarray == NULL)
2115  : (trio_long_double_t *)argarray[num];
2116  else
2117  {
2118  if (parameters[i].flags & FLAGS_LONG)
2119  parameters[i].data.doublePointer = (argarray == NULL)
2120  ? va_arg(TRIO_VA_LIST_DEREF(arglist), double *)
2121  : (double *)argarray[num];
2122  else
2123  parameters[i].data.doublePointer = (argarray == NULL)
2124  ? (double *)va_arg(TRIO_VA_LIST_DEREF(arglist), float *)
2125  : (double *)((float *)argarray[num]);
2126  }
2127  }
2128  else
2129  {
2130  if (parameters[i].flags & FLAGS_LONGDOUBLE)
2131  parameters[i].data.longdoubleNumber = (argarray == NULL)
2133  : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
2134  else
2135  {
2136  if (argarray == NULL)
2137  parameters[i].data.longdoubleNumber =
2139  else
2140  {
2141  if (parameters[i].flags & FLAGS_SHORT)
2142  parameters[i].data.longdoubleNumber =
2143  (trio_long_double_t)(*((float *)argarray[num]));
2144  else
2145  parameters[i].data.longdoubleNumber =
2146  (trio_long_double_t)(*((double *)argarray[num]));
2147  }
2148  }
2149  }
2150  break;
2151 
2152 #if defined(FORMAT_ERRNO)
2153  case FORMAT_ERRNO:
2154  parameters[i].data.errorNumber = save_errno;
2155  break;
2156 #endif
2157 
2158  default:
2159  break;
2160  }
2161  } /* for all specifiers */
2162  return num;
2163 }
2164 
2165 
2166 /*************************************************************************
2167  *
2168  * FORMATTING
2169  *
2170  ************************************************************************/
2171 
2172 
2173 /*************************************************************************
2174  * TrioWriteNumber
2175  *
2176  * Description:
2177  * Output a number.
2178  * The complexity of this function is a result of the complexity
2179  * of the dependencies of the flags.
2180  */
2181 TRIO_PRIVATE void
2182 TrioWriteNumber
2184  trio_class_t *self,
2187  int width,
2188  int precision,
2189  int base)
2190 {
2191  BOOLEAN_T isNegative;
2192  BOOLEAN_T isNumberZero;
2193  BOOLEAN_T isPrecisionZero;
2194  BOOLEAN_T ignoreNumber;
2196  char *bufferend;
2197  char *pointer;
2198  TRIO_CONST char *digits;
2199  int i;
2200  int length;
2201  char *p;
2202  int count;
2203 
2204  assert(VALID(self));
2205  assert(VALID(self->OutStream));
2206  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2207 
2208  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2209  if (base == NO_BASE)
2210  base = BASE_DECIMAL;
2211 
2212  isNumberZero = (number == 0);
2213  isPrecisionZero = (precision == 0);
2214  ignoreNumber = (isNumberZero
2215  && isPrecisionZero
2216  && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
2217 
2218  if (flags & FLAGS_UNSIGNED)
2219  {
2220  isNegative = FALSE;
2221  flags &= ~FLAGS_SHOWSIGN;
2222  }
2223  else
2224  {
2225  isNegative = ((trio_intmax_t)number < 0);
2226  if (isNegative)
2227  number = -((trio_intmax_t)number);
2228  }
2229 
2230  if (flags & FLAGS_QUAD)
2231  number &= (trio_ulonglong_t)-1;
2232  else if (flags & FLAGS_LONG)
2233  number &= (unsigned long)-1;
2234  else
2235  number &= (unsigned int)-1;
2236 
2237  /* Build number */
2238  pointer = bufferend = &buffer[sizeof(buffer) - 1];
2239  *pointer-- = NIL;
2240  for (i = 1; i < (int)sizeof(buffer); i++)
2241  {
2242  *pointer-- = digits[number % base];
2243  number /= base;
2244  if (number == 0)
2245  break;
2246 
2247  if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
2248  {
2249  /*
2250  * We are building the number from the least significant
2251  * to the most significant digit, so we have to copy the
2252  * thousand separator backwards
2253  */
2255  if (((int)(pointer - buffer) - length) > 0)
2256  {
2257  p = &internalThousandSeparator[length - 1];
2258  while (length-- > 0)
2259  *pointer-- = *p--;
2260  }
2261  }
2262  }
2263 
2264  if (! ignoreNumber)
2265  {
2266  /* Adjust width */
2267  width -= (bufferend - pointer) - 1;
2268  }
2269 
2270  /* Adjust precision */
2271  if (NO_PRECISION != precision)
2272  {
2273  precision -= (bufferend - pointer) - 1;
2274  if (precision < 0)
2275  precision = 0;
2276  flags |= FLAGS_NILPADDING;
2277  }
2278 
2279  /* Calculate padding */
2280  count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2281  ? precision
2282  : 0;
2283 
2284  /* Adjust width further */
2285  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2286  width--;
2287  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2288  {
2289  switch (base)
2290  {
2291  case BASE_BINARY:
2292  case BASE_HEX:
2293  width -= 2;
2294  break;
2295  case BASE_OCTAL:
2296  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2297  width--;
2298  break;
2299  default:
2300  break;
2301  }
2302  }
2303 
2304  /* Output prefixes spaces if needed */
2305  if (! ((flags & FLAGS_LEFTADJUST) ||
2306  ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2307  {
2308  while (width-- > count)
2309  self->OutStream(self, CHAR_ADJUST);
2310  }
2311 
2312  /* width has been adjusted for signs and alternatives */
2313  if (isNegative)
2314  self->OutStream(self, '-');
2315  else if (flags & FLAGS_SHOWSIGN)
2316  self->OutStream(self, '+');
2317  else if (flags & FLAGS_SPACE)
2318  self->OutStream(self, ' ');
2319 
2320  /* Prefix is not written when the value is zero */
2321  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2322  {
2323  switch (base)
2324  {
2325  case BASE_BINARY:
2326  self->OutStream(self, '0');
2327  self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2328  break;
2329 
2330  case BASE_OCTAL:
2331  if (!(flags & FLAGS_NILPADDING) || (count == 0))
2332  self->OutStream(self, '0');
2333  break;
2334 
2335  case BASE_HEX:
2336  self->OutStream(self, '0');
2337  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2338  break;
2339 
2340  default:
2341  break;
2342  } /* switch base */
2343  }
2344 
2345  /* Output prefixed zero padding if needed */
2346  if (flags & FLAGS_NILPADDING)
2347  {
2348  if (precision == NO_PRECISION)
2349  precision = width;
2350  while (precision-- > 0)
2351  {
2352  self->OutStream(self, '0');
2353  width--;
2354  }
2355  }
2356 
2357  if (! ignoreNumber)
2358  {
2359  /* Output the number itself */
2360  while (*(++pointer))
2361  {
2362  self->OutStream(self, *pointer);
2363  }
2364  }
2365 
2366  /* Output trailing spaces if needed */
2367  if (flags & FLAGS_LEFTADJUST)
2368  {
2369  while (width-- > 0)
2370  self->OutStream(self, CHAR_ADJUST);
2371  }
2372 }
2373 
2374 /*************************************************************************
2375  * TrioWriteStringCharacter
2376  *
2377  * Description:
2378  * Output a single character of a string
2379  */
2380 TRIO_PRIVATE void
2381 TrioWriteStringCharacter
2382 TRIO_ARGS3((self, ch, flags),
2383  trio_class_t *self,
2384  int ch,
2386 {
2387  if (flags & FLAGS_ALTERNATIVE)
2388  {
2389  if (! isprint(ch))
2390  {
2391  /*
2392  * Non-printable characters are converted to C escapes or
2393  * \number, if no C escape exists.
2394  */
2395  self->OutStream(self, CHAR_BACKSLASH);
2396  switch (ch)
2397  {
2398  case '\007': self->OutStream(self, 'a'); break;
2399  case '\b': self->OutStream(self, 'b'); break;
2400  case '\f': self->OutStream(self, 'f'); break;
2401  case '\n': self->OutStream(self, 'n'); break;
2402  case '\r': self->OutStream(self, 'r'); break;
2403  case '\t': self->OutStream(self, 't'); break;
2404  case '\v': self->OutStream(self, 'v'); break;
2405  case '\\': self->OutStream(self, '\\'); break;
2406  default:
2407  self->OutStream(self, 'x');
2408  TrioWriteNumber(self, (trio_uintmax_t)ch,
2410  2, 2, BASE_HEX);
2411  break;
2412  }
2413  }
2414  else if (ch == CHAR_BACKSLASH)
2415  {
2416  self->OutStream(self, CHAR_BACKSLASH);
2417  self->OutStream(self, CHAR_BACKSLASH);
2418  }
2419  else
2420  {
2421  self->OutStream(self, ch);
2422  }
2423  }
2424  else
2425  {
2426  self->OutStream(self, ch);
2427  }
2428 }
2429 
2430 /*************************************************************************
2431  * TrioWriteString
2432  *
2433  * Description:
2434  * Output a string
2435  */
2436 TRIO_PRIVATE void
2437 TrioWriteString
2438 TRIO_ARGS5((self, string, flags, width, precision),
2439  trio_class_t *self,
2440  TRIO_CONST char *string,
2442  int width,
2443  int precision)
2444 {
2445  int length;
2446  int ch;
2447 
2448  assert(VALID(self));
2449  assert(VALID(self->OutStream));
2450 
2451  if (string == NULL)
2452  {
2453  string = internalNullString;
2454  length = sizeof(internalNullString) - 1;
2455  /* Disable quoting for the null pointer */
2456  flags &= (~FLAGS_QUOTE);
2457  width = 0;
2458  }
2459  else
2460  {
2461  length = trio_length(string);
2462  }
2463  if ((NO_PRECISION != precision) &&
2464  (precision < length))
2465  {
2466  length = precision;
2467  }
2468  width -= length;
2469 
2470  if (flags & FLAGS_QUOTE)
2471  self->OutStream(self, CHAR_QUOTE);
2472 
2473  if (! (flags & FLAGS_LEFTADJUST))
2474  {
2475  while (width-- > 0)
2476  self->OutStream(self, CHAR_ADJUST);
2477  }
2478 
2479  while (length-- > 0)
2480  {
2481  /* The ctype parameters must be an unsigned char (or EOF) */
2482  ch = (int)((unsigned char)(*string++));
2483  TrioWriteStringCharacter(self, ch, flags);
2484  }
2485 
2486  if (flags & FLAGS_LEFTADJUST)
2487  {
2488  while (width-- > 0)
2489  self->OutStream(self, CHAR_ADJUST);
2490  }
2491  if (flags & FLAGS_QUOTE)
2492  self->OutStream(self, CHAR_QUOTE);
2493 }
2494 
2495 /*************************************************************************
2496  * TrioWriteWideStringCharacter
2497  *
2498  * Description:
2499  * Output a wide string as a multi-byte sequence
2500  */
2501 #if TRIO_WIDECHAR
2502 TRIO_PRIVATE int
2503 TrioWriteWideStringCharacter
2504 TRIO_ARGS4((self, wch, flags, width),
2505  trio_class_t *self,
2506  trio_wchar_t wch,
2508  int width)
2509 {
2510  int size;
2511  int i;
2512  int ch;
2513  char *string;
2514  char buffer[MB_LEN_MAX + 1];
2515 
2516  if (width == NO_WIDTH)
2517  width = sizeof(buffer);
2518 
2519  size = wctomb(buffer, wch);
2520  if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2521  return 0;
2522 
2523  string = buffer;
2524  i = size;
2525  while ((width >= i) && (width-- > 0) && (i-- > 0))
2526  {
2527  /* The ctype parameters must be an unsigned char (or EOF) */
2528  ch = (int)((unsigned char)(*string++));
2529  TrioWriteStringCharacter(self, ch, flags);
2530  }
2531  return size;
2532 }
2533 #endif /* TRIO_WIDECHAR */
2534 
2535 /*************************************************************************
2536  * TrioWriteWideString
2537  *
2538  * Description:
2539  * Output a wide character string as a multi-byte string
2540  */
2541 #if TRIO_WIDECHAR
2542 TRIO_PRIVATE void
2543 TrioWriteWideString
2544 TRIO_ARGS5((self, wstring, flags, width, precision),
2545  trio_class_t *self,
2546  TRIO_CONST trio_wchar_t *wstring,
2547  trio_flags_t flags,
2548  int width,
2549  int precision)
2550 {
2551  int length;
2552  int size;
2553 
2554  assert(VALID(self));
2555  assert(VALID(self->OutStream));
2556 
2557 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2558  (void)mblen(NULL, 0);
2559 #endif
2560 
2561  if (wstring == NULL)
2562  {
2563  TrioWriteString(self, NULL, flags, width, precision);
2564  return;
2565  }
2566 
2567  if (NO_PRECISION == precision)
2568  {
2569  length = INT_MAX;
2570  }
2571  else
2572  {
2573  length = precision;
2574  width -= length;
2575  }
2576 
2577  if (flags & FLAGS_QUOTE)
2578  self->OutStream(self, CHAR_QUOTE);
2579 
2580  if (! (flags & FLAGS_LEFTADJUST))
2581  {
2582  while (width-- > 0)
2583  self->OutStream(self, CHAR_ADJUST);
2584  }
2585 
2586  while (length > 0)
2587  {
2588  size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2589  if (size == 0)
2590  break; /* while */
2591  length -= size;
2592  }
2593 
2594  if (flags & FLAGS_LEFTADJUST)
2595  {
2596  while (width-- > 0)
2597  self->OutStream(self, CHAR_ADJUST);
2598  }
2599  if (flags & FLAGS_QUOTE)
2600  self->OutStream(self, CHAR_QUOTE);
2601 }
2602 #endif /* TRIO_WIDECHAR */
2603 
2604 /*************************************************************************
2605  * TrioWriteDouble
2606  *
2607  * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
2608  *
2609  * "5.2.4.2.2 paragraph #4
2610  *
2611  * The accuracy [...] is implementation defined, as is the accuracy
2612  * of the conversion between floating-point internal representations
2613  * and string representations performed by the libray routine in
2614  * <stdio.h>"
2615  */
2616 /* FIXME: handle all instances of constant long-double number (L)
2617  * and *l() math functions.
2618  */
2619 TRIO_PRIVATE void
2620 TrioWriteDouble
2621 TRIO_ARGS6((self, number, flags, width, precision, base),
2622  trio_class_t *self,
2624  trio_flags_t flags,
2625  int width,
2626  int precision,
2627  int base)
2628 {
2629  trio_long_double_t integerNumber;
2630  trio_long_double_t fractionNumber;
2631  trio_long_double_t workNumber;
2632  int integerDigits;
2633  int fractionDigits;
2634  int exponentDigits;
2635  int baseDigits;
2636  int integerThreshold;
2637  int fractionThreshold;
2638  int expectedWidth;
2639  int exponent = 0;
2640  unsigned int uExponent = 0;
2641  int exponentBase;
2642  trio_long_double_t dblBase;
2643  trio_long_double_t dblIntegerBase;
2644  trio_long_double_t dblFractionBase;
2645  trio_long_double_t integerAdjust;
2646  trio_long_double_t fractionAdjust;
2647  BOOLEAN_T isNegative;
2648  BOOLEAN_T isExponentNegative = FALSE;
2649  BOOLEAN_T requireTwoDigitExponent;
2650  BOOLEAN_T isHex;
2651  TRIO_CONST char *digits;
2652  char *groupingPointer;
2653  int i;
2654  int index;
2655  BOOLEAN_T hasOnlyZeroes;
2656  int zeroes = 0;
2657  register int trailingZeroes;
2658  BOOLEAN_T keepTrailingZeroes;
2659  BOOLEAN_T keepDecimalPoint;
2660  trio_long_double_t epsilon;
2661 
2662  assert(VALID(self));
2663  assert(VALID(self->OutStream));
2664  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
2665 
2666  /* Determine sign and look for special quantities */
2667  switch (trio_fpclassify_and_signbit(number, &isNegative))
2668  {
2669  case TRIO_FP_NAN:
2670  TrioWriteString(self,
2671  (flags & FLAGS_UPPER)
2672  ? NAN_UPPER
2673  : NAN_LOWER,
2674  flags, width, precision);
2675  return;
2676 
2677  case TRIO_FP_INFINITE:
2678  if (isNegative)
2679  {
2680  /* Negative infinity */
2681  TrioWriteString(self,
2682  (flags & FLAGS_UPPER)
2683  ? "-" INFINITE_UPPER
2684  : "-" INFINITE_LOWER,
2685  flags, width, precision);
2686  return;
2687  }
2688  else
2689  {
2690  /* Positive infinity */
2691  TrioWriteString(self,
2692  (flags & FLAGS_UPPER)
2693  ? INFINITE_UPPER
2694  : INFINITE_LOWER,
2695  flags, width, precision);
2696  return;
2697  }
2698 
2699  default:
2700  /* Finitude */
2701  break;
2702  }
2703 
2704  /* Normal numbers */
2705  if (flags & FLAGS_LONGDOUBLE)
2706  {
2707  baseDigits = (base == 10)
2708  ? LDBL_DIG
2709  : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
2710  epsilon = LDBL_EPSILON;
2711  }
2712  else if (flags & FLAGS_SHORT)
2713  {
2714  baseDigits = (base == BASE_DECIMAL)
2715  ? FLT_DIG
2716  : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
2717  epsilon = FLT_EPSILON;
2718  }
2719  else
2720  {
2721  baseDigits = (base == BASE_DECIMAL)
2722  ? DBL_DIG
2723  : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
2724  epsilon = DBL_EPSILON;
2725  }
2726 
2727  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
2728  isHex = (base == BASE_HEX);
2729  if (base == NO_BASE)
2730  base = BASE_DECIMAL;
2731  dblBase = (trio_long_double_t)base;
2732  keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
2733  ( (flags & FLAGS_FLOAT_G) &&
2734  !(flags & FLAGS_ALTERNATIVE) ) );
2735 
2736  if (flags & FLAGS_ROUNDING)
2737  precision = baseDigits;
2738 
2739  if (precision == NO_PRECISION)
2740  {
2741  if (isHex)
2742  {
2743  keepTrailingZeroes = FALSE;
2744  precision = FLT_MANT_DIG;
2745  }
2746  else
2747  {
2748  precision = FLT_DIG;
2749  }
2750  }
2751 
2752  if (isNegative)
2753  number = -number;
2754 
2755  if (isHex)
2756  flags |= FLAGS_FLOAT_E;
2757 
2758  if (flags & FLAGS_FLOAT_G)
2759  {
2760  if (precision == 0)
2761  precision = 1;
2762 
2763  if ((number < 1.0E-4) || (number > powl(base,
2764  (trio_long_double_t)precision)))
2765  {
2766  /* Use scientific notation */
2767  flags |= FLAGS_FLOAT_E;
2768  }
2769  else if (number < 1.0)
2770  {
2771  /*
2772  * Use normal notation. If the integer part of the number is
2773  * zero, then adjust the precision to include leading fractional
2774  * zeros.
2775  */
2776  workNumber = TrioLogarithm(number, base);
2777  workNumber = TRIO_FABS(workNumber);
2778  if (workNumber - floorl(workNumber) < 0.001)
2779  workNumber--;
2780  zeroes = (int)floorl(workNumber);
2781  }
2782  }
2783 
2784  if (flags & FLAGS_FLOAT_E)
2785  {
2786  /* Scale the number */
2787  workNumber = TrioLogarithm(number, base);
2788  if (trio_isinf(workNumber) == -1)
2789  {
2790  exponent = 0;
2791  /* Undo setting */
2792  if (flags & FLAGS_FLOAT_G)
2793  flags &= ~FLAGS_FLOAT_E;
2794  }
2795  else
2796  {
2797  exponent = (int)floorl(workNumber);
2798  number /= powl(dblBase, (trio_long_double_t)exponent);
2799  isExponentNegative = (exponent < 0);
2800  uExponent = (isExponentNegative) ? -exponent : exponent;
2801  if (isHex)
2802  uExponent *= 4; /* log16(2) */
2803  /* No thousand separators */
2804  flags &= ~FLAGS_QUOTE;
2805  }
2806  }
2807 
2808  integerNumber = floorl(number);
2809  fractionNumber = number - integerNumber;
2810 
2811  /*
2812  * Truncated number.
2813  *
2814  * Precision is number of significant digits for FLOAT_G
2815  * and number of fractional digits for others.
2816  */
2817  integerDigits = (integerNumber > epsilon)
2818  ? 1 + (int)TrioLogarithm(integerNumber, base)
2819  : 1;
2820  fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
2821  ? precision - integerDigits
2822  : zeroes + precision;
2823 
2824  dblFractionBase = TrioPower(base, fractionDigits);
2825 
2826  workNumber = number + 0.5 / dblFractionBase;
2827  if (floorl(number) != floorl(workNumber))
2828  {
2829  if (flags & FLAGS_FLOAT_E)
2830  {
2831  /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
2832  exponent++;
2833  isExponentNegative = (exponent < 0);
2834  uExponent = (isExponentNegative) ? -exponent : exponent;
2835  if (isHex)
2836  uExponent *= 4; /* log16(2) */
2837  workNumber = (number + 0.5 / dblFractionBase) / dblBase;
2838  integerNumber = floorl(workNumber);
2839  fractionNumber = workNumber - integerNumber;
2840  }
2841  else
2842  {
2843  /* Adjust if number was rounded up one digit (ie. 99 to 100) */
2844  integerNumber = floorl(number + 0.5);
2845  fractionNumber = 0.0;
2846  integerDigits = (integerNumber > epsilon)
2847  ? 1 + (int)TrioLogarithm(integerNumber, base)
2848  : 1;
2849  }
2850  }
2851 
2852  /* Estimate accuracy */
2853  integerAdjust = fractionAdjust = 0.5;
2854  if (flags & FLAGS_ROUNDING)
2855  {
2856  if (integerDigits > baseDigits)
2857  {
2858  integerThreshold = baseDigits;
2859  fractionDigits = 0;
2860  dblFractionBase = 1.0;
2861  fractionThreshold = 0;
2862  precision = 0; /* Disable decimal-point */
2863  integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
2864  fractionAdjust = 0.0;
2865  }
2866  else
2867  {
2868  integerThreshold = integerDigits;
2869  fractionThreshold = fractionDigits - integerThreshold;
2870  fractionAdjust = 1.0;
2871  }
2872  }
2873  else
2874  {
2875  integerThreshold = INT_MAX;
2876  fractionThreshold = INT_MAX;
2877  }
2878 
2879  /*
2880  * Calculate expected width.
2881  * sign + integer part + thousands separators + decimal point
2882  * + fraction + exponent
2883  */
2884  fractionAdjust /= dblFractionBase;
2885  hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
2886  keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
2887  !((precision == 0) ||
2888  (!keepTrailingZeroes && hasOnlyZeroes)) );
2889  if (flags & FLAGS_FLOAT_E)
2890  {
2891  exponentDigits = (uExponent == 0)
2892  ? 1
2893  : (int)ceil(TrioLogarithm((double)(uExponent + 1),
2894  (isHex) ? 10.0 : base));
2895  }
2896  else
2897  exponentDigits = 0;
2898  requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
2899 
2900  expectedWidth = integerDigits + fractionDigits
2901  + (keepDecimalPoint
2903  : 0)
2904  + ((flags & FLAGS_QUOTE)
2905  ? TrioCalcThousandSeparatorLength(integerDigits)
2906  : 0);
2907  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2908  expectedWidth += sizeof("-") - 1;
2909  if (exponentDigits > 0)
2910  expectedWidth += exponentDigits +
2911  ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
2912  if (isHex)
2913  expectedWidth += sizeof("0X") - 1;
2914 
2915  /* Output prefixing */
2916  if (flags & FLAGS_NILPADDING)
2917  {
2918  /* Leading zeros must be after sign */
2919  if (isNegative)
2920  self->OutStream(self, '-');
2921  else if (flags & FLAGS_SHOWSIGN)
2922  self->OutStream(self, '+');
2923  else if (flags & FLAGS_SPACE)
2924  self->OutStream(self, ' ');
2925  if (isHex)
2926  {
2927  self->OutStream(self, '0');
2928  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2929  }
2930  if (!(flags & FLAGS_LEFTADJUST))
2931  {
2932  for (i = expectedWidth; i < width; i++)
2933  {
2934  self->OutStream(self, '0');
2935  }
2936  }
2937  }
2938  else
2939  {
2940  /* Leading spaces must be before sign */
2941  if (!(flags & FLAGS_LEFTADJUST))
2942  {
2943  for (i = expectedWidth; i < width; i++)
2944  {
2945  self->OutStream(self, CHAR_ADJUST);
2946  }
2947  }
2948  if (isNegative)
2949  self->OutStream(self, '-');
2950  else if (flags & FLAGS_SHOWSIGN)
2951  self->OutStream(self, '+');
2952  else if (flags & FLAGS_SPACE)
2953  self->OutStream(self, ' ');
2954  if (isHex)
2955  {
2956  self->OutStream(self, '0');
2957  self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2958  }
2959  }
2960 
2961  /* Output the integer part and thousand separators */
2962  dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
2963  for (i = 0; i < integerDigits; i++)
2964  {
2965  workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
2966  if (i > integerThreshold)
2967  {
2968  /* Beyond accuracy */
2969  self->OutStream(self, digits[0]);
2970  }
2971  else
2972  {
2973  self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
2974  }
2975  dblIntegerBase *= dblBase;
2976 
2977  if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2978  && TrioFollowedBySeparator(integerDigits - i))
2979  {
2980  for (groupingPointer = internalThousandSeparator;
2981  *groupingPointer != NIL;
2982  groupingPointer++)
2983  {
2984  self->OutStream(self, *groupingPointer);
2985  }
2986  }
2987  }
2988 
2989  /* Insert decimal point and build the fraction part */
2990  trailingZeroes = 0;
2991 
2992  if (keepDecimalPoint)
2993  {
2995  {
2996  self->OutStream(self, internalDecimalPoint);
2997  }
2998  else
2999  {
3000  for (i = 0; i < internalDecimalPointLength; i++)
3001  {
3002  self->OutStream(self, internalDecimalPointString[i]);
3003  }
3004  }
3005  }
3006 
3007  for (i = 0; i < fractionDigits; i++)
3008  {
3009  if ((integerDigits > integerThreshold) || (i > fractionThreshold))
3010  {
3011  /* Beyond accuracy */
3012  trailingZeroes++;
3013  }
3014  else
3015  {
3016  fractionNumber *= dblBase;
3017  fractionAdjust *= dblBase;
3018  workNumber = floorl(fractionNumber + fractionAdjust);
3019  fractionNumber -= workNumber;
3020  index = (int)fmodl(workNumber, dblBase);
3021  if (index == 0)
3022  {
3023  trailingZeroes++;
3024  }
3025  else
3026  {
3027  while (trailingZeroes > 0)
3028  {
3029  /* Not trailing zeroes after all */
3030  self->OutStream(self, digits[0]);
3031  trailingZeroes--;
3032  }
3033  self->OutStream(self, digits[index]);
3034  }
3035  }
3036  }
3037 
3038  if (keepTrailingZeroes)
3039  {
3040  while (trailingZeroes > 0)
3041  {
3042  self->OutStream(self, digits[0]);
3043  trailingZeroes--;
3044  }
3045  }
3046 
3047  /* Output exponent */
3048  if (exponentDigits > 0)
3049  {
3050  self->OutStream(self,
3051  isHex
3052  ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
3053  : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
3054  self->OutStream(self, (isExponentNegative) ? '-' : '+');
3055 
3056  /* The exponent must contain at least two digits */
3057  if (requireTwoDigitExponent)
3058  self->OutStream(self, '0');
3059 
3060  if (isHex)
3061  base = 10.0;
3062  exponentBase = (int)TrioPower(base, exponentDigits - 1);
3063  for (i = 0; i < exponentDigits; i++)
3064  {
3065  self->OutStream(self, digits[(uExponent / exponentBase) % base]);
3066  exponentBase /= base;
3067  }
3068  }
3069  /* Output trailing spaces */
3070  if (flags & FLAGS_LEFTADJUST)
3071  {
3072  for (i = expectedWidth; i < width; i++)
3073  {
3074  self->OutStream(self, CHAR_ADJUST);
3075  }
3076  }
3077 }
3078 
3079 /*************************************************************************
3080  * TrioFormatProcess
3081  *
3082  * Description:
3083  * This is the main engine for formatting output
3084  */
3085 TRIO_PRIVATE int
3086 TrioFormatProcess
3087 TRIO_ARGS3((data, format, parameters),
3088  trio_class_t *data,
3089  TRIO_CONST char *format,
3090  trio_parameter_t *parameters)
3091 {
3092 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3093  int charlen;
3094 #endif
3095  int i;
3096  TRIO_CONST char *string;
3099  int width;
3100  int precision;
3101  int base;
3102  int index;
3103 
3104  index = 0;
3105  i = 0;
3106 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3107  (void)mblen(NULL, 0);
3108 #endif
3109 
3110  while (format[index])
3111  {
3112 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3113  if (! isascii(format[index]))
3114  {
3115  charlen = mblen(&format[index], MB_LEN_MAX);
3116  /*
3117  * Only valid multibyte characters are handled here. Invalid
3118  * multibyte characters (charlen == -1) are handled as normal
3119  * characters.
3120  */
3121  if (charlen != -1)
3122  {
3123  while (charlen-- > 0)
3124  {
3125  data->OutStream(data, format[index++]);
3126  }
3127  continue; /* while characters left in formatting string */
3128  }
3129  }
3130 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
3131  if (CHAR_IDENTIFIER == format[index])
3132  {
3133  if (CHAR_IDENTIFIER == format[index + 1])
3134  {
3135  data->OutStream(data, CHAR_IDENTIFIER);
3136  index += 2;
3137  }
3138  else
3139  {
3140  /* Skip the parameter entries */
3141  while (parameters[i].type == FORMAT_PARAMETER)
3142  i++;
3143 
3144  flags = parameters[i].flags;
3145 
3146  /* Find width */
3147  width = parameters[i].width;
3148  if (flags & FLAGS_WIDTH_PARAMETER)
3149  {
3150  /* Get width from parameter list */
3151  width = (int)parameters[width].data.number.as_signed;
3152  if (width < 0)
3153  {
3154  /*
3155  * A negative width is the same as the - flag and
3156  * a positive width.
3157  */
3158  flags |= FLAGS_LEFTADJUST;
3159  flags &= ~FLAGS_NILPADDING;
3160  width = -width;
3161  }
3162  }
3163 
3164  /* Find precision */
3165  if (flags & FLAGS_PRECISION)
3166  {
3167  precision = parameters[i].precision;
3168  if (flags & FLAGS_PRECISION_PARAMETER)
3169  {
3170  /* Get precision from parameter list */
3171  precision = (int)parameters[precision].data.number.as_signed;
3172  if (precision < 0)
3173  {
3174  /*
3175  * A negative precision is the same as no
3176  * precision
3177  */
3178  precision = NO_PRECISION;
3179  }
3180  }
3181  }
3182  else
3183  {
3184  precision = NO_PRECISION;
3185  }
3186 
3187  /* Find base */
3188  base = parameters[i].base;
3189  if (flags & FLAGS_BASE_PARAMETER)
3190  {
3191  /* Get base from parameter list */
3192  base = (int)parameters[base].data.number.as_signed;
3193  }
3194 
3195  switch (parameters[i].type)
3196  {
3197  case FORMAT_CHAR:
3198  if (flags & FLAGS_QUOTE)
3199  data->OutStream(data, CHAR_QUOTE);
3200  if (! (flags & FLAGS_LEFTADJUST))
3201  {
3202  while (--width > 0)
3203  data->OutStream(data, CHAR_ADJUST);
3204  }
3205 #if TRIO_WIDECHAR
3206  if (flags & FLAGS_WIDECHAR)
3207  {
3208  TrioWriteWideStringCharacter(data,
3209  (trio_wchar_t)parameters[i].data.number.as_signed,
3210  flags,
3211  NO_WIDTH);
3212  }
3213  else
3214 #endif
3215  {
3216  TrioWriteStringCharacter(data,
3217  (int)parameters[i].data.number.as_signed,
3218  flags);
3219  }
3220 
3221  if (flags & FLAGS_LEFTADJUST)
3222  {
3223  while(--width > 0)
3224  data->OutStream(data, CHAR_ADJUST);
3225  }
3226  if (flags & FLAGS_QUOTE)
3227  data->OutStream(data, CHAR_QUOTE);
3228 
3229  break; /* FORMAT_CHAR */
3230 
3231  case FORMAT_INT:
3232  TrioWriteNumber(data,
3233  parameters[i].data.number.as_unsigned,
3234  flags,
3235  width,
3236  precision,
3237  base);
3238 
3239  break; /* FORMAT_INT */
3240 
3241  case FORMAT_DOUBLE:
3242  TrioWriteDouble(data,
3243  parameters[i].data.longdoubleNumber,
3244  flags,
3245  width,
3246  precision,
3247  base);
3248  break; /* FORMAT_DOUBLE */
3249 
3250  case FORMAT_STRING:
3251 #if TRIO_WIDECHAR
3252  if (flags & FLAGS_WIDECHAR)
3253  {
3254  TrioWriteWideString(data,
3255  parameters[i].data.wstring,
3256  flags,
3257  width,
3258  precision);
3259  }
3260  else
3261 #endif
3262  {
3263  TrioWriteString(data,
3264  parameters[i].data.string,
3265  flags,
3266  width,
3267  precision);
3268  }
3269  break; /* FORMAT_STRING */
3270 
3271  case FORMAT_POINTER:
3272  {
3274 
3275  reference.data = data;
3276  reference.parameter = &parameters[i];
3277  trio_print_pointer(&reference, parameters[i].data.pointer);
3278  }
3279  break; /* FORMAT_POINTER */
3280 
3281  case FORMAT_COUNT:
3282  pointer = parameters[i].data.pointer;
3283  if (NULL != pointer)
3284  {
3285  /*
3286  * C99 paragraph 7.19.6.1.8 says "the number of
3287  * characters written to the output stream so far by
3288  * this call", which is data->committed
3289  */
3290 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3291  if (flags & FLAGS_SIZE_T)
3292  *(size_t *)pointer = (size_t)data->committed;
3293  else
3294 #endif
3295 #if defined(QUALIFIER_PTRDIFF_T)
3296  if (flags & FLAGS_PTRDIFF_T)
3297  *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3298  else
3299 #endif
3300 #if defined(QUALIFIER_INTMAX_T)
3301  if (flags & FLAGS_INTMAX_T)
3302  *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
3303  else
3304 #endif
3305  if (flags & FLAGS_QUAD)
3306  {
3307  *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
3308  }
3309  else if (flags & FLAGS_LONG)
3310  {
3311  *(long int *)pointer = (long int)data->committed;
3312  }
3313  else if (flags & FLAGS_SHORT)
3314  {
3315  *(short int *)pointer = (short int)data->committed;
3316  }
3317  else
3318  {
3319  *(int *)pointer = (int)data->committed;
3320  }
3321  }
3322  break; /* FORMAT_COUNT */
3323 
3324  case FORMAT_PARAMETER:
3325  break; /* FORMAT_PARAMETER */
3326 
3327 #if defined(FORMAT_ERRNO)
3328  case FORMAT_ERRNO:
3329  string = trio_error(parameters[i].data.errorNumber);
3330  if (string)
3331  {
3332  TrioWriteString(data,
3333  string,
3334  flags,
3335  width,
3336  precision);
3337  }
3338  else
3339  {
3340  data->OutStream(data, '#');
3341  TrioWriteNumber(data,
3342  (trio_uintmax_t)parameters[i].data.errorNumber,
3343  flags,
3344  width,
3345  precision,
3346  BASE_DECIMAL);
3347  }
3348  break; /* FORMAT_ERRNO */
3349 #endif /* defined(FORMAT_ERRNO) */
3350 
3351 #if defined(FORMAT_USER_DEFINED)
3352  case FORMAT_USER_DEFINED:
3353  {
3355  trio_userdef_t *def = NULL;
3356 
3357  if (parameters[i].user_name[0] == NIL)
3358  {
3359  /* Use handle */
3360  if ((i > 0) ||
3361  (parameters[i - 1].type == FORMAT_PARAMETER))
3362  def = (trio_userdef_t *)parameters[i - 1].data.pointer;
3363  }
3364  else
3365  {
3366  /* Look up namespace */
3367  def = TrioFindNamespace(parameters[i].user_name, NULL);
3368  }
3369  if (def) {
3370  reference.data = data;
3371  reference.parameter = &parameters[i];
3372  def->callback(&reference);
3373  }
3374  }
3375  break;
3376 #endif /* defined(FORMAT_USER_DEFINED) */
3377 
3378  default:
3379  break;
3380  } /* switch parameter type */
3381 
3382  /* Prepare for next */
3383  index = parameters[i].indexAfterSpecifier;
3384  i++;
3385  }
3386  }
3387  else /* not identifier */
3388  {
3389  data->OutStream(data, format[index++]);
3390  }
3391  }
3392  return data->processed;
3393 }
3394 
3395 /*************************************************************************
3396  * TrioFormatRef
3397  */
3398 TRIO_PRIVATE int
3399 TrioFormatRef
3402  TRIO_CONST char *format,
3404  trio_pointer_t *argarray)
3405 {
3406  int status;
3407  trio_parameter_t parameters[MAX_PARAMETERS];
3408 
3409  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3410  if (status < 0)
3411  return status;
3412 
3413  status = TrioFormatProcess(reference->data, format, parameters);
3414  if (reference->data->error != 0)
3415  {
3416  status = reference->data->error;
3417  }
3418  return status;
3419 }
3420 
3421 /*************************************************************************
3422  * TrioFormat
3423  */
3424 TRIO_PRIVATE int
3425 TrioFormat
3426 TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
3427  trio_pointer_t destination,
3428  size_t destinationSize,
3429  void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
3430  TRIO_CONST char *format,
3432  trio_pointer_t *argarray)
3433 {
3434  int status;
3436  trio_parameter_t parameters[MAX_PARAMETERS];
3437 
3438  assert(VALID(OutStream));
3439  assert(VALID(format));
3440 
3441  memset(&data, 0, sizeof(data));
3442  data.OutStream = OutStream;
3443  data.location = destination;
3444  data.max = destinationSize;
3445  data.error = 0;
3446 
3447 #if defined(USE_LOCALE)
3448  if (NULL == internalLocaleValues)
3449  {
3450  TrioSetLocale();
3451  }
3452 #endif
3453 
3454  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
3455  if (status < 0)
3456  return status;
3457 
3458  status = TrioFormatProcess(&data, format, parameters);
3459  if (data.error != 0)
3460  {
3461  status = data.error;
3462  }
3463  return status;
3464 }
3465 
3466 /*************************************************************************
3467  * TrioOutStreamFile
3468  */
3469 TRIO_PRIVATE void
3470 TrioOutStreamFile
3472  trio_class_t *self,
3473  int output)
3474 {
3475  FILE *file;
3476 
3477  assert(VALID(self));
3478  assert(VALID(self->location));
3479 
3480  file = (FILE *)self->location;
3481  self->processed++;
3482  if (fputc(output, file) == EOF)
3483  {
3484  self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
3485  }
3486  else
3487  {
3488  self->committed++;
3489  }
3490 }
3491 
3492 /*************************************************************************
3493  * TrioOutStreamFileDescriptor
3494  */
3495 TRIO_PRIVATE void
3496 TrioOutStreamFileDescriptor
3497 TRIO_ARGS2((self, output),
3498  trio_class_t *self,
3499  int output)
3500 {
3501  int fd;
3502  char ch;
3503 
3504  assert(VALID(self));
3505 
3506  fd = *((int *)self->location);
3507  ch = (char)output;
3508  self->processed++;
3509  if (write(fd, &ch, sizeof(char)) == -1)
3510  {
3511  self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
3512  }
3513  else
3514  {
3515  self->committed++;
3516  }
3517 }
3518 
3519 /*************************************************************************
3520  * TrioOutStreamCustom
3521  */
3522 TRIO_PRIVATE void
3523 TrioOutStreamCustom
3524 TRIO_ARGS2((self, output),
3525  trio_class_t *self,
3526  int output)
3527 {
3528  int status;
3530 
3531  assert(VALID(self));
3532  assert(VALID(self->location));
3533 
3534  data = (trio_custom_t *)self->location;
3535  if (data->stream.out)
3536  {
3537  status = (data->stream.out)(data->closure, output);
3538  if (status >= 0)
3539  {
3540  self->committed++;
3541  }
3542  else
3543  {
3544  if (self->error == 0)
3545  {
3546  self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
3547  }
3548  }
3549  }
3550  self->processed++;
3551 }
3552 
3553 /*************************************************************************
3554  * TrioOutStreamString
3555  */
3556 TRIO_PRIVATE void
3557 TrioOutStreamString
3558 TRIO_ARGS2((self, output),
3559  trio_class_t *self,
3560  int output)
3561 {
3562  char **buffer;
3563 
3564  assert(VALID(self));
3565  assert(VALID(self->location));
3566 
3567  buffer = (char **)self->location;
3568  **buffer = (char)output;
3569  (*buffer)++;
3570  self->processed++;
3571  self->committed++;
3572 }
3573 
3574 /*************************************************************************
3575  * TrioOutStreamStringMax
3576  */
3577 TRIO_PRIVATE void
3578 TrioOutStreamStringMax
3579 TRIO_ARGS2((self, output),
3580  trio_class_t *self,
3581  int output)
3582 {
3583  char **buffer;
3584 
3585  assert(VALID(self));
3586  assert(VALID(self->location));
3587 
3588  buffer = (char **)self->location;
3589 
3590  if (self->processed < self->max)
3591  {
3592  **buffer = (char)output;
3593  (*buffer)++;
3594  self->committed++;
3595  }
3596  self->processed++;
3597 }
3598 
3599 /*************************************************************************
3600  * TrioOutStreamStringDynamic
3601  */
3602 TRIO_PRIVATE void
3603 TrioOutStreamStringDynamic
3604 TRIO_ARGS2((self, output),
3605  trio_class_t *self,
3606  int output)
3607 {
3608  assert(VALID(self));
3609  assert(VALID(self->location));
3610 
3611  if (self->error == 0)
3612  {
3613  trio_xstring_append_char((trio_string_t *)self->location,
3614  (char)output);
3615  self->committed++;
3616  }
3617  /* The processed variable must always be increased */
3618  self->processed++;
3619 }
3620 
3621 /*************************************************************************
3622  *
3623  * Formatted printing functions
3624  *
3625  ************************************************************************/
3626 
3627 #if defined(TRIO_DOCUMENTATION)
3628 # include "doc/doc_printf.h"
3629 #endif
3630 
3634 /*************************************************************************
3635  * printf
3636  */
3637 
3645 TRIO_PUBLIC int
3646 trio_printf
3647 TRIO_VARGS2((format, va_alist),
3648  TRIO_CONST char *format,
3649  TRIO_VA_DECL)
3650 {
3651  int status;
3652  va_list args;
3653 
3654  assert(VALID(format));
3655 
3656  TRIO_VA_START(args, format);
3657  status = TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3658  TRIO_VA_END(args);
3659  return status;
3660 }
3661 
3669 TRIO_PUBLIC int
3670 trio_vprintf
3672  TRIO_CONST char *format,
3673  va_list args)
3674 {
3675  assert(VALID(format));
3676 
3677  return TrioFormat(stdout, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3678 }
3679 
3687 TRIO_PUBLIC int
3688 trio_printfv
3690  TRIO_CONST char *format,
3691  trio_pointer_t * args)
3692 {
3693  assert(VALID(format));
3694 
3695  return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
3696 }
3697 
3698 /*************************************************************************
3699  * fprintf
3700  */
3701 
3710 TRIO_PUBLIC int
3711 trio_fprintf
3712 TRIO_VARGS3((file, format, va_alist),
3713  FILE *file,
3714  TRIO_CONST char *format,
3715  TRIO_VA_DECL)
3716 {
3717  int status;
3718  va_list args;
3719 
3720  assert(VALID(file));
3721  assert(VALID(format));
3722 
3723  TRIO_VA_START(args, format);
3724  status = TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3725  TRIO_VA_END(args);
3726  return status;
3727 }
3728 
3737 TRIO_PUBLIC int
3738 trio_vfprintf
3740  FILE *file,
3741  TRIO_CONST char *format,
3742  va_list args)
3743 {
3744  assert(VALID(file));
3745  assert(VALID(format));
3746 
3747  return TrioFormat(file, 0, TrioOutStreamFile, format, TRIO_VA_LIST_ADDR(args), NULL);
3748 }
3749 
3758 TRIO_PUBLIC int
3759 trio_fprintfv
3761  FILE *file,
3762  TRIO_CONST char *format,
3763  trio_pointer_t * args)
3764 {
3765  assert(VALID(file));
3766  assert(VALID(format));
3767 
3768  return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
3769 }
3770 
3771 /*************************************************************************
3772  * dprintf
3773  */
3774 
3783 TRIO_PUBLIC int
3784 trio_dprintf
3785 TRIO_VARGS3((fd, format, va_alist),
3786  int fd,
3787  TRIO_CONST char *format,
3788  TRIO_VA_DECL)
3789 {
3790  int status;
3791  va_list args;
3792 
3793  assert(VALID(format));
3794 
3795  TRIO_VA_START(args, format);
3796  status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
3797  TRIO_VA_END(args);
3798  return status;
3799 }
3800 
3809 TRIO_PUBLIC int
3810 trio_vdprintf
3812  int fd,
3813  TRIO_CONST char *format,
3814  va_list args)
3815 {
3816  assert(VALID(format));
3817 
3818  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, TRIO_VA_LIST_ADDR(args), NULL);
3819 }
3820 
3829 TRIO_PUBLIC int
3830 trio_dprintfv
3832  int fd,
3833  TRIO_CONST char *format,
3835 {
3836  assert(VALID(format));
3837 
3838  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
3839 }
3840 
3841 /*************************************************************************
3842  * cprintf
3843  */
3844 TRIO_PUBLIC int
3845 trio_cprintf
3846 TRIO_VARGS4((stream, closure, format, va_alist),
3847  trio_outstream_t stream,
3848  trio_pointer_t closure,
3849  TRIO_CONST char *format,
3850  TRIO_VA_DECL)
3851 {
3852  int status;
3853  va_list args;
3855 
3856  assert(VALID(stream));
3857  assert(VALID(format));
3858 
3859  TRIO_VA_START(args, format);
3860  data.stream.out = stream;
3861  data.closure = closure;
3862  status = TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
3863  TRIO_VA_END(args);
3864  return status;
3865 }
3866 
3867 TRIO_PUBLIC int
3868 trio_vcprintf
3870  trio_outstream_t stream,
3871  trio_pointer_t closure,
3872  TRIO_CONST char *format,
3873  va_list args)
3874 {
3876 
3877  assert(VALID(stream));
3878  assert(VALID(format));
3879 
3880  data.stream.out = stream;
3881  data.closure = closure;
3882  return TrioFormat(&data, 0, TrioOutStreamCustom, format, TRIO_VA_LIST_ADDR(args), NULL);
3883 }
3884 
3885 TRIO_PUBLIC int
3886 trio_cprintfv
3888  trio_outstream_t stream,
3889  trio_pointer_t closure,
3890  TRIO_CONST char *format,
3891  void **args)
3892 {
3894 
3895  assert(VALID(stream));
3896  assert(VALID(format));
3897 
3898  data.stream.out = stream;
3899  data.closure = closure;
3900  return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
3901 }
3902 
3903 /*************************************************************************
3904  * sprintf
3905  */
3906 
3915 TRIO_PUBLIC int
3916 trio_sprintf
3917 TRIO_VARGS3((buffer, format, va_alist),
3918  char *buffer,
3919  TRIO_CONST char *format,
3920  TRIO_VA_DECL)
3921 {
3922  int status;
3923  va_list args;
3924 
3925  assert(VALID(buffer));
3926  assert(VALID(format));
3927 
3928  TRIO_VA_START(args, format);
3929  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
3930  *buffer = NIL; /* Terminate with NIL character */
3931  TRIO_VA_END(args);
3932  return status;
3933 }
3934 
3943 TRIO_PUBLIC int
3944 trio_vsprintf
3946  char *buffer,
3947  TRIO_CONST char *format,
3948  va_list args)
3949 {
3950  int status;
3951 
3952  assert(VALID(buffer));
3953  assert(VALID(format));
3954 
3955  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, TRIO_VA_LIST_ADDR(args), NULL);
3956  *buffer = NIL;
3957  return status;
3958 }
3959 
3968 TRIO_PUBLIC int
3969 trio_sprintfv
3971  char *buffer,
3972  TRIO_CONST char *format,
3974 {
3975  int status;
3976 
3977  assert(VALID(buffer));
3978  assert(VALID(format));
3979 
3980  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
3981  *buffer = NIL;
3982  return status;
3983 }
3984 
3985 /*************************************************************************
3986  * snprintf
3987  */
3988 
3998 TRIO_PUBLIC int
3999 trio_snprintf
4000 TRIO_VARGS4((buffer, max, format, va_alist),
4001  char *buffer,
4002  size_t max,
4003  TRIO_CONST char *format,
4004  TRIO_VA_DECL)
4005 {
4006  int status;
4007  va_list args;
4008 
4009  assert(VALID(buffer));
4010  assert(VALID(format));
4011 
4012  TRIO_VA_START(args, format);
4013  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4014  TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4015  if (max > 0)
4016  *buffer = NIL;
4017  TRIO_VA_END(args);
4018  return status;
4019 }
4020 
4030 TRIO_PUBLIC int
4031 trio_vsnprintf
4033  char *buffer,
4034  size_t max,
4035  TRIO_CONST char *format,
4036  va_list args)
4037 {
4038  int status;
4039 
4040  assert(VALID(buffer));
4041  assert(VALID(format));
4042 
4043  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4044  TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4045  if (max > 0)
4046  *buffer = NIL;
4047  return status;
4048 }
4049 
4059 TRIO_PUBLIC int
4060 trio_snprintfv
4062  char *buffer,
4063  size_t max,
4064  TRIO_CONST char *format,
4066 {
4067  int status;
4068 
4069  assert(VALID(buffer));
4070  assert(VALID(format));
4071 
4072  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
4073  TrioOutStreamStringMax, format, NULL, args);
4074  if (max > 0)
4075  *buffer = NIL;
4076  return status;
4077 }
4078 
4079 /*************************************************************************
4080  * snprintfcat
4081  * Appends the new string to the buffer string overwriting the '\0'
4082  * character at the end of buffer.
4083  */
4084 TRIO_PUBLIC int
4085 trio_snprintfcat
4086 TRIO_VARGS4((buffer, max, format, va_alist),
4087  char *buffer,
4088  size_t max,
4089  TRIO_CONST char *format,
4090  TRIO_VA_DECL)
4091 {
4092  int status;
4093  va_list args;
4094  size_t buf_len;
4095 
4096  TRIO_VA_START(args, format);
4097 
4098  assert(VALID(buffer));
4099  assert(VALID(format));
4100 
4101  buf_len = trio_length(buffer);
4102  buffer = &buffer[buf_len];
4103 
4104  status = TrioFormat(&buffer, max - 1 - buf_len,
4105  TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4106  TRIO_VA_END(args);
4107  *buffer = NIL;
4108  return status;
4109 }
4110 
4111 TRIO_PUBLIC int
4112 trio_vsnprintfcat
4113 TRIO_ARGS4((buffer, max, format, args),
4114  char *buffer,
4115  size_t max,
4116  TRIO_CONST char *format,
4117  va_list args)
4118 {
4119  int status;
4120  size_t buf_len;
4121 
4122  assert(VALID(buffer));
4123  assert(VALID(format));
4124 
4125  buf_len = trio_length(buffer);
4126  buffer = &buffer[buf_len];
4127  status = TrioFormat(&buffer, max - 1 - buf_len,
4128  TrioOutStreamStringMax, format, TRIO_VA_LIST_ADDR(args), NULL);
4129  *buffer = NIL;
4130  return status;
4131 }
4132 
4133 /*************************************************************************
4134  * trio_aprintf
4135  */
4136 
4137 /* Deprecated */
4138 TRIO_PUBLIC char *
4139 trio_aprintf
4140 TRIO_VARGS2((format, va_alist),
4141  TRIO_CONST char *format,
4142  TRIO_VA_DECL)
4143 {
4144  va_list args;
4146  char *result = NULL;
4147 
4148  assert(VALID(format));
4149 
4150  info = trio_xstring_duplicate("");
4151  if (info)
4152  {
4153  TRIO_VA_START(args, format);
4154  (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4155  format, TRIO_VA_LIST_ADDR(args), NULL);
4156  TRIO_VA_END(args);
4157 
4158  trio_string_terminate(info);
4159  result = trio_string_extract(info);
4160  trio_string_destroy(info);
4161  }
4162  return result;
4163 }
4164 
4165 /* Deprecated */
4166 TRIO_PUBLIC char *
4167 trio_vaprintf
4168 TRIO_ARGS2((format, args),
4169  TRIO_CONST char *format,
4170  va_list args)
4171 {
4173  char *result = NULL;
4174 
4175  assert(VALID(format));
4176 
4177  info = trio_xstring_duplicate("");
4178  if (info)
4179  {
4180  (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
4181  format, TRIO_VA_LIST_ADDR(args), NULL);
4182  trio_string_terminate(info);
4183  result = trio_string_extract(info);
4184  trio_string_destroy(info);
4185  }
4186  return result;
4187 }
4188 
4189 TRIO_PUBLIC int
4190 trio_asprintf
4191 TRIO_VARGS3((result, format, va_alist),
4192  char **result,
4193  TRIO_CONST char *format,
4194  TRIO_VA_DECL)
4195 {
4196  va_list args;
4197  int status;
4199 
4200  assert(VALID(format));
4201 
4202  *result = NULL;
4203 
4204  info = trio_xstring_duplicate("");
4205  if (info == NULL)
4206  {
4207  status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4208  }
4209  else
4210  {
4211  TRIO_VA_START(args, format);
4212  status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4213  format, TRIO_VA_LIST_ADDR(args), NULL);
4214  TRIO_VA_END(args);
4215  if (status >= 0)
4216  {
4217  trio_string_terminate(info);
4218  *result = trio_string_extract(info);
4219  }
4220  trio_string_destroy(info);
4221  }
4222  return status;
4223 }
4224 
4225 TRIO_PUBLIC int
4226 trio_vasprintf
4227 TRIO_ARGS3((result, format, args),
4228  char **result,
4229  TRIO_CONST char *format,
4230  va_list args)
4231 {
4232  int status;
4234 
4235  assert(VALID(format));
4236 
4237  *result = NULL;
4238 
4239  info = trio_xstring_duplicate("");
4240  if (info == NULL)
4241  {
4242  status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
4243  }
4244  else
4245  {
4246  status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
4247  format, TRIO_VA_LIST_ADDR(args), NULL);
4248  if (status >= 0)
4249  {
4250  trio_string_terminate(info);
4251  *result = trio_string_extract(info);
4252  }
4253  trio_string_destroy(info);
4254  }
4255  return status;
4256 }
4257 
4260 /*************************************************************************
4261  *
4262  * CALLBACK
4263  *
4264  ************************************************************************/
4265 
4266 #if defined(TRIO_DOCUMENTATION)
4267 # include "doc/doc_register.h"
4268 #endif
4269 
4274 #if TRIO_EXTENSION
4275 
4276 /*************************************************************************
4277  * trio_register
4278  */
4279 
4288 trio_register
4290  trio_callback_t callback,
4291  TRIO_CONST char *name)
4292 {
4293  trio_userdef_t *def;
4294  trio_userdef_t *prev = NULL;
4295 
4296  if (callback == NULL)
4297  return NULL;
4298 
4299  if (name)
4300  {
4301  /* Handle built-in namespaces */
4302  if (name[0] == ':')
4303  {
4304  if (trio_equal(name, ":enter"))
4305  {
4306  internalEnterCriticalRegion = callback;
4307  }
4308  else if (trio_equal(name, ":leave"))
4309  {
4310  internalLeaveCriticalRegion = callback;
4311  }
4312  return NULL;
4313  }
4314 
4315  /* Bail out if namespace is too long */
4316  if (trio_length(name) >= MAX_USER_NAME)
4317  return NULL;
4318 
4319  /* Bail out if namespace already is registered */
4320  def = TrioFindNamespace(name, &prev);
4321  if (def)
4322  return NULL;
4323  }
4324 
4325  def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
4326  if (def)
4327  {
4328  if (internalEnterCriticalRegion)
4330 
4331  if (name)
4332  {
4333  /* Link into internal list */
4334  if (prev == NULL)
4335  internalUserDef = def;
4336  else
4337  prev->next = def;
4338  }
4339  /* Initialize */
4340  def->callback = callback;
4341  def->name = (name == NULL)
4342  ? NULL
4343  : trio_duplicate(name);
4344  def->next = NULL;
4345 
4346  if (internalLeaveCriticalRegion)
4348  }
4349  return (trio_pointer_t)def;
4350 }
4351 
4357 void
4358 trio_unregister
4361 {
4362  trio_userdef_t *self = (trio_userdef_t *)handle;
4363  trio_userdef_t *def;
4364  trio_userdef_t *prev = NULL;
4365 
4366  assert(VALID(self));
4367 
4368  if (self->name)
4369  {
4370  def = TrioFindNamespace(self->name, &prev);
4371  if (def)
4372  {
4373  if (internalEnterCriticalRegion)
4375 
4376  if (prev == NULL)
4377  internalUserDef = NULL;
4378  else
4379  prev->next = def->next;
4380 
4381  if (internalLeaveCriticalRegion)
4383  }
4384  trio_destroy(self->name);
4385  }
4386  TRIO_FREE(self);
4387 }
4388 
4389 /*************************************************************************
4390  * trio_get_format [public]
4391  */
4392 TRIO_CONST char *
4393 trio_get_format
4396 {
4397 #if defined(FORMAT_USER_DEFINED)
4398  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4399 #endif
4400 
4401  return (((trio_reference_t *)ref)->parameter->user_data);
4402 }
4403 
4404 /*************************************************************************
4405  * trio_get_argument [public]
4406  */
4408 trio_get_argument
4409 TRIO_ARGS1((ref),
4411 {
4412 #if defined(FORMAT_USER_DEFINED)
4413  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
4414 #endif
4415 
4416  return ((trio_reference_t *)ref)->parameter->data.pointer;
4417 }
4418 
4419 /*************************************************************************
4420  * trio_get_width / trio_set_width [public]
4421  */
4422 int
4423 trio_get_width
4424 TRIO_ARGS1((ref),
4425  trio_pointer_t ref)
4426 {
4427  return ((trio_reference_t *)ref)->parameter->width;
4428 }
4429 
4430 void
4431 trio_set_width
4432 TRIO_ARGS2((ref, width),
4433  trio_pointer_t ref,
4434  int width)
4435 {
4436  ((trio_reference_t *)ref)->parameter->width = width;
4437 }
4438 
4439 /*************************************************************************
4440  * trio_get_precision / trio_set_precision [public]
4441  */
4442 int
4443 trio_get_precision
4444 TRIO_ARGS1((ref),
4445  trio_pointer_t ref)
4446 {
4447  return (((trio_reference_t *)ref)->parameter->precision);
4448 }
4449 
4450 void
4451 trio_set_precision
4452 TRIO_ARGS2((ref, precision),
4453  trio_pointer_t ref,
4454  int precision)
4455 {
4456  ((trio_reference_t *)ref)->parameter->precision = precision;
4457 }
4458 
4459 /*************************************************************************
4460  * trio_get_base / trio_set_base [public]
4461  */
4462 int
4463 trio_get_base
4464 TRIO_ARGS1((ref),
4465  trio_pointer_t ref)
4466 {
4467  return (((trio_reference_t *)ref)->parameter->base);
4468 }
4469 
4470 void
4471 trio_set_base
4473  trio_pointer_t ref,
4474  int base)
4475 {
4476  ((trio_reference_t *)ref)->parameter->base = base;
4477 }
4478 
4479 /*************************************************************************
4480  * trio_get_long / trio_set_long [public]
4481  */
4482 int
4483 trio_get_long
4484 TRIO_ARGS1((ref),
4485  trio_pointer_t ref)
4486 {
4487  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
4488  ? TRUE
4489  : FALSE;
4490 }
4491 
4492 void
4493 trio_set_long
4494 TRIO_ARGS2((ref, is_long),
4495  trio_pointer_t ref,
4496  int is_long)
4497 {
4498  if (is_long)
4499  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
4500  else
4501  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
4502 }
4503 
4504 /*************************************************************************
4505  * trio_get_longlong / trio_set_longlong [public]
4506  */
4507 int
4508 trio_get_longlong
4509 TRIO_ARGS1((ref),
4510  trio_pointer_t ref)
4511 {
4512  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
4513  ? TRUE
4514  : FALSE;
4515 }
4516 
4517 void
4518 trio_set_longlong
4519 TRIO_ARGS2((ref, is_longlong),
4520  trio_pointer_t ref,
4521  int is_longlong)
4522 {
4523  if (is_longlong)
4524  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
4525  else
4526  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
4527 }
4528 
4529 /*************************************************************************
4530  * trio_get_longdouble / trio_set_longdouble [public]
4531  */
4532 int
4533 trio_get_longdouble
4534 TRIO_ARGS1((ref),
4535  trio_pointer_t ref)
4536 {
4537  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
4538  ? TRUE
4539  : FALSE;
4540 }
4541 
4542 void
4543 trio_set_longdouble
4544 TRIO_ARGS2((ref, is_longdouble),
4545  trio_pointer_t ref,
4546  int is_longdouble)
4547 {
4548  if (is_longdouble)
4549  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
4550  else
4551  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
4552 }
4553 
4554 /*************************************************************************
4555  * trio_get_short / trio_set_short [public]
4556  */
4557 int
4558 trio_get_short
4559 TRIO_ARGS1((ref),
4560  trio_pointer_t ref)
4561 {
4562  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
4563  ? TRUE
4564  : FALSE;
4565 }
4566 
4567 void
4568 trio_set_short
4569 TRIO_ARGS2((ref, is_short),
4570  trio_pointer_t ref,
4571  int is_short)
4572 {
4573  if (is_short)
4574  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
4575  else
4576  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
4577 }
4578 
4579 /*************************************************************************
4580  * trio_get_shortshort / trio_set_shortshort [public]
4581  */
4582 int
4583 trio_get_shortshort
4584 TRIO_ARGS1((ref),
4585  trio_pointer_t ref)
4586 {
4587  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
4588  ? TRUE
4589  : FALSE;
4590 }
4591 
4592 void
4593 trio_set_shortshort
4594 TRIO_ARGS2((ref, is_shortshort),
4595  trio_pointer_t ref,
4596  int is_shortshort)
4597 {
4598  if (is_shortshort)
4599  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
4600  else
4601  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
4602 }
4603 
4604 /*************************************************************************
4605  * trio_get_alternative / trio_set_alternative [public]
4606  */
4607 int
4608 trio_get_alternative
4609 TRIO_ARGS1((ref),
4610  trio_pointer_t ref)
4611 {
4612  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
4613  ? TRUE
4614  : FALSE;
4615 }
4616 
4617 void
4618 trio_set_alternative
4619 TRIO_ARGS2((ref, is_alternative),
4620  trio_pointer_t ref,
4621  int is_alternative)
4622 {
4623  if (is_alternative)
4624  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
4625  else
4626  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
4627 }
4628 
4629 /*************************************************************************
4630  * trio_get_alignment / trio_set_alignment [public]
4631  */
4632 int
4633 trio_get_alignment
4634 TRIO_ARGS1((ref),
4635  trio_pointer_t ref)
4636 {
4637  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
4638  ? TRUE
4639  : FALSE;
4640 }
4641 
4642 void
4643 trio_set_alignment
4644 TRIO_ARGS2((ref, is_leftaligned),
4645  trio_pointer_t ref,
4646  int is_leftaligned)
4647 {
4648  if (is_leftaligned)
4649  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
4650  else
4651  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
4652 }
4653 
4654 /*************************************************************************
4655  * trio_get_spacing /trio_set_spacing [public]
4656  */
4657 int
4658 trio_get_spacing
4659 TRIO_ARGS1((ref),
4660  trio_pointer_t ref)
4661 {
4662  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
4663  ? TRUE
4664  : FALSE;
4665 }
4666 
4667 void
4668 trio_set_spacing
4670  trio_pointer_t ref,
4671  int is_space)
4672 {
4673  if (is_space)
4674  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
4675  else
4676  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
4677 }
4678 
4679 /*************************************************************************
4680  * trio_get_sign / trio_set_sign [public]
4681  */
4682 int
4683 trio_get_sign
4684 TRIO_ARGS1((ref),
4685  trio_pointer_t ref)
4686 {
4687  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
4688  ? TRUE
4689  : FALSE;
4690 }
4691 
4692 void
4693 trio_set_sign
4694 TRIO_ARGS2((ref, is_sign),
4695  trio_pointer_t ref,
4696  int is_sign)
4697 {
4698  if (is_sign)
4699  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
4700  else
4701  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
4702 }
4703 
4704 /*************************************************************************
4705  * trio_get_padding / trio_set_padding [public]
4706  */
4707 int
4708 trio_get_padding
4709 TRIO_ARGS1((ref),
4710  trio_pointer_t ref)
4711 {
4712  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
4713  ? TRUE
4714  : FALSE;
4715 }
4716 
4717 void
4718 trio_set_padding
4719 TRIO_ARGS2((ref, is_padding),
4720  trio_pointer_t ref,
4721  int is_padding)
4722 {
4723  if (is_padding)
4724  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
4725  else
4726  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
4727 }
4728 
4729 /*************************************************************************
4730  * trio_get_quote / trio_set_quote [public]
4731  */
4732 int
4733 trio_get_quote
4734 TRIO_ARGS1((ref),
4735  trio_pointer_t ref)
4736 {
4737  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
4738  ? TRUE
4739  : FALSE;
4740 }
4741 
4742 void
4743 trio_set_quote
4744 TRIO_ARGS2((ref, is_quote),
4745  trio_pointer_t ref,
4746  int is_quote)
4747 {
4748  if (is_quote)
4749  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
4750  else
4751  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
4752 }
4753 
4754 /*************************************************************************
4755  * trio_get_upper / trio_set_upper [public]
4756  */
4757 int
4758 trio_get_upper
4759 TRIO_ARGS1((ref),
4760  trio_pointer_t ref)
4761 {
4762  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
4763  ? TRUE
4764  : FALSE;
4765 }
4766 
4767 void
4768 trio_set_upper
4770  trio_pointer_t ref,
4771  int is_upper)
4772 {
4773  if (is_upper)
4774  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
4775  else
4776  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
4777 }
4778 
4779 /*************************************************************************
4780  * trio_get_largest / trio_set_largest [public]
4781  */
4782 #if TRIO_C99
4783 int
4784 trio_get_largest
4785 TRIO_ARGS1((ref),
4786  trio_pointer_t ref)
4787 {
4788  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
4789  ? TRUE
4790  : FALSE;
4791 }
4792 
4793 void
4794 trio_set_largest
4795 TRIO_ARGS2((ref, is_largest),
4796  trio_pointer_t ref,
4797  int is_largest)
4798 {
4799  if (is_largest)
4800  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
4801  else
4802  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
4803 }
4804 #endif
4805 
4806 /*************************************************************************
4807  * trio_get_ptrdiff / trio_set_ptrdiff [public]
4808  */
4809 int
4810 trio_get_ptrdiff
4811 TRIO_ARGS1((ref),
4812  trio_pointer_t ref)
4813 {
4814  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
4815  ? TRUE
4816  : FALSE;
4817 }
4818 
4819 void
4820 trio_set_ptrdiff
4821 TRIO_ARGS2((ref, is_ptrdiff),
4822  trio_pointer_t ref,
4823  int is_ptrdiff)
4824 {
4825  if (is_ptrdiff)
4826  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
4827  else
4828  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
4829 }
4830 
4831 /*************************************************************************
4832  * trio_get_size / trio_set_size [public]
4833  */
4834 #if TRIO_C99
4835 int
4836 trio_get_size
4837 TRIO_ARGS1((ref),
4838  trio_pointer_t ref)
4839 {
4840  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
4841  ? TRUE
4842  : FALSE;
4843 }
4844 
4845 void
4846 trio_set_size
4847 TRIO_ARGS2((ref, is_size),
4848  trio_pointer_t ref,
4849  int is_size)
4850 {
4851  if (is_size)
4852  ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
4853  else
4854  ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
4855 }
4856 #endif
4857 
4858 /*************************************************************************
4859  * trio_print_int [public]
4860  */
4861 void
4862 trio_print_int
4864  trio_pointer_t ref,
4865  int number)
4866 {
4867  trio_reference_t *self = (trio_reference_t *)ref;
4868 
4869  TrioWriteNumber(self->data,
4870  (trio_uintmax_t)number,
4871  self->parameter->flags,
4872  self->parameter->width,
4873  self->parameter->precision,
4874  self->parameter->base);
4875 }
4876 
4877 /*************************************************************************
4878  * trio_print_uint [public]
4879  */
4880 void
4881 trio_print_uint
4883  trio_pointer_t ref,
4884  unsigned int number)
4885 {
4886  trio_reference_t *self = (trio_reference_t *)ref;
4887 
4888  TrioWriteNumber(self->data,
4889  (trio_uintmax_t)number,
4890  self->parameter->flags | FLAGS_UNSIGNED,
4891  self->parameter->width,
4892  self->parameter->precision,
4893  self->parameter->base);
4894 }
4895 
4896 /*************************************************************************
4897  * trio_print_double [public]
4898  */
4899 void
4900 trio_print_double
4902  trio_pointer_t ref,
4903  double number)
4904 {
4905  trio_reference_t *self = (trio_reference_t *)ref;
4906 
4907  TrioWriteDouble(self->data,
4908  number,
4909  self->parameter->flags,
4910  self->parameter->width,
4911  self->parameter->precision,
4912  self->parameter->base);
4913 }
4914 
4915 /*************************************************************************
4916  * trio_print_string [public]
4917  */
4918 void
4919 trio_print_string
4920 TRIO_ARGS2((ref, string),
4921  trio_pointer_t ref,
4922  char *string)
4923 {
4924  trio_reference_t *self = (trio_reference_t *)ref;
4925 
4926  TrioWriteString(self->data,
4927  string,
4928  self->parameter->flags,
4929  self->parameter->width,
4930  self->parameter->precision);
4931 }
4932 
4933 /*************************************************************************
4934  * trio_print_ref [public]
4935  */
4936 int
4937 trio_print_ref
4938 TRIO_VARGS3((ref, format, va_alist),
4939  trio_pointer_t ref,
4940  TRIO_CONST char *format,
4941  TRIO_VA_DECL)
4942 {
4943  int status;
4944  va_list arglist;
4945 
4946  assert(VALID(format));
4947 
4948  TRIO_VA_START(arglist, format);
4949  status = TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
4950  TRIO_VA_END(arglist);
4951  return status;
4952 }
4953 
4954 /*************************************************************************
4955  * trio_vprint_ref [public]
4956  */
4957 int
4958 trio_vprint_ref
4959 TRIO_ARGS3((ref, format, arglist),
4960  trio_pointer_t ref,
4961  TRIO_CONST char *format,
4962  va_list arglist)
4963 {
4964  assert(VALID(format));
4965 
4966  return TrioFormatRef((trio_reference_t *)ref, format, TRIO_VA_LIST_ADDR(arglist), NULL);
4967 }
4968 
4969 /*************************************************************************
4970  * trio_printv_ref [public]
4971  */
4972 int
4973 trio_printv_ref
4974 TRIO_ARGS3((ref, format, argarray),
4975  trio_pointer_t ref,
4976  TRIO_CONST char *format,
4977  trio_pointer_t *argarray)
4978 {
4979  assert(VALID(format));
4980 
4981  return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
4982 }
4983 
4984 #endif /* TRIO_EXTENSION */
4985 
4986 /*************************************************************************
4987  * trio_print_pointer [public]
4988  */
4989 void
4990 trio_print_pointer
4992  trio_pointer_t ref,
4994 {
4995  trio_reference_t *self = (trio_reference_t *)ref;
4998 
4999  if (NULL == pointer)
5000  {
5001  TRIO_CONST char *string = internalNullString;
5002  while (*string)
5003  self->data->OutStream(self->data, *string++);
5004  }
5005  else
5006  {
5007  /*
5008  * The subtraction of the null pointer is a workaround
5009  * to avoid a compiler warning. The performance overhead
5010  * is negligible (and likely to be removed by an
5011  * optimizing compiler). The (char *) casting is done
5012  * to please ANSI C++.
5013  */
5014  number = (trio_uintmax_t)((char *)pointer - (char *)0);
5015  /* Shrink to size of pointer */
5016  number &= (trio_uintmax_t)-1;
5017  flags = self->parameter->flags;
5018  flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
5020  TrioWriteNumber(self->data,
5021  number,
5022  flags,
5023  POINTER_WIDTH,
5024  NO_PRECISION,
5025  BASE_HEX);
5026  }
5027 }
5028 
5031 /*************************************************************************
5032  *
5033  * LOCALES
5034  *
5035  ************************************************************************/
5036 
5037 /*************************************************************************
5038  * trio_locale_set_decimal_point
5039  *
5040  * Decimal point can only be one character. The input argument is a
5041  * string to enable multibyte characters. At most MB_LEN_MAX characters
5042  * will be used.
5043  */
5044 TRIO_PUBLIC void
5045 trio_locale_set_decimal_point
5046 TRIO_ARGS1((decimalPoint),
5047  char *decimalPoint)
5048 {
5049 #if defined(USE_LOCALE)
5050  if (NULL == internalLocaleValues)
5051  {
5052  TrioSetLocale();
5053  }
5054 #endif
5055  internalDecimalPointLength = trio_length(decimalPoint);
5056  if (internalDecimalPointLength == 1)
5057  {
5058  internalDecimalPoint = *decimalPoint;
5059  }
5060  else
5061  {
5063  trio_copy_max(internalDecimalPointString,
5065  decimalPoint);
5066  }
5067 }
5068 
5069 /*************************************************************************
5070  * trio_locale_set_thousand_separator
5071  *
5072  * See trio_locale_set_decimal_point
5073  */
5074 TRIO_PUBLIC void
5075 trio_locale_set_thousand_separator
5076 TRIO_ARGS1((thousandSeparator),
5077  char *thousandSeparator)
5078 {
5079 #if defined(USE_LOCALE)
5080  if (NULL == internalLocaleValues)
5081  {
5082  TrioSetLocale();
5083  }
5084 #endif
5085  trio_copy_max(internalThousandSeparator,
5086  sizeof(internalThousandSeparator),
5087  thousandSeparator);
5089 }
5090 
5091 /*************************************************************************
5092  * trio_locale_set_grouping
5093  *
5094  * Array of bytes. Reversed order.
5095  *
5096  * CHAR_MAX : No further grouping
5097  * 0 : Repeat last group for the remaining digits (not necessary
5098  * as C strings are zero-terminated)
5099  * n : Set current group to n
5100  *
5101  * Same order as the grouping attribute in LC_NUMERIC.
5102  */
5103 TRIO_PUBLIC void
5104 trio_locale_set_grouping
5106  char *grouping)
5107 {
5108 #if defined(USE_LOCALE)
5109  if (NULL == internalLocaleValues)
5110  {
5111  TrioSetLocale();
5112  }
5113 #endif
5114  trio_copy_max(internalGrouping,
5115  sizeof(internalGrouping),
5116  grouping);
5117 }
5118 
5119 
5120 /*************************************************************************
5121  *
5122  * SCANNING
5123  *
5124  ************************************************************************/
5125 
5126 /*************************************************************************
5127  * TrioSkipWhitespaces
5128  */
5129 TRIO_PRIVATE int
5130 TrioSkipWhitespaces
5131 TRIO_ARGS1((self),
5132  trio_class_t *self)
5133 {
5134  int ch;
5135 
5136  ch = self->current;
5137  while (isspace(ch))
5138  {
5139  self->InStream(self, &ch);
5140  }
5141  return ch;
5142 }
5143 
5144 /*************************************************************************
5145  * TrioGetCollation
5146  */
5147 #if TRIO_EXTENSION
5148 TRIO_PRIVATE void
5150 {
5151  int i;
5152  int j;
5153  int k;
5154  char first[2];
5155  char second[2];
5156 
5157  /* This is computationally expensive */
5158  first[1] = NIL;
5159  second[1] = NIL;
5160  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5161  {
5162  k = 0;
5163  first[0] = (char)i;
5164  for (j = 0; j < MAX_CHARACTER_CLASS; j++)
5165  {
5166  second[0] = (char)j;
5167  if (trio_equal_locale(first, second))
5168  internalCollationArray[i][k++] = (char)j;
5169  }
5170  internalCollationArray[i][k] = NIL;
5171  }
5172 }
5173 #endif
5174 
5175 /*************************************************************************
5176  * TrioGetCharacterClass
5177  *
5178  * FIXME:
5179  * multibyte
5180  */
5181 TRIO_PRIVATE int
5182 TrioGetCharacterClass
5183 TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
5184  TRIO_CONST char *format,
5185  int *indexPointer,
5186  trio_flags_t *flagsPointer,
5187  int *characterclass)
5188 {
5189  int index = *indexPointer;
5190  int i;
5191  char ch;
5192  char range_begin;
5193  char range_end;
5194 
5195  *flagsPointer &= ~FLAGS_EXCLUDE;
5196 
5197  if (format[index] == QUALIFIER_CIRCUMFLEX)
5198  {
5199  *flagsPointer |= FLAGS_EXCLUDE;
5200  index++;
5201  }
5202  /*
5203  * If the ungroup character is at the beginning of the scanlist,
5204  * it will be part of the class, and a second ungroup character
5205  * must follow to end the group.
5206  */
5207  if (format[index] == SPECIFIER_UNGROUP)
5208  {
5209  characterclass[(int)SPECIFIER_UNGROUP]++;
5210  index++;
5211  }
5212  /*
5213  * Minus is used to specify ranges. To include minus in the class,
5214  * it must be at the beginning of the list
5215  */
5216  if (format[index] == QUALIFIER_MINUS)
5217  {
5218  characterclass[(int)QUALIFIER_MINUS]++;
5219  index++;
5220  }
5221  /* Collect characters */
5222  for (ch = format[index];
5223  (ch != SPECIFIER_UNGROUP) && (ch != NIL);
5224  ch = format[++index])
5225  {
5226  switch (ch)
5227  {
5228  case QUALIFIER_MINUS: /* Scanlist ranges */
5229 
5230  /*
5231  * Both C99 and UNIX98 describes ranges as implementation-
5232  * defined.
5233  *
5234  * We support the following behaviour (although this may
5235  * change as we become wiser)
5236  * - only increasing ranges, ie. [a-b] but not [b-a]
5237  * - transitive ranges, ie. [a-b-c] == [a-c]
5238  * - trailing minus, ie. [a-] is interpreted as an 'a'
5239  * and a '-'
5240  * - duplicates (although we can easily convert these
5241  * into errors)
5242  */
5243  range_begin = format[index - 1];
5244  range_end = format[++index];
5245  if (range_end == SPECIFIER_UNGROUP)
5246  {
5247  /* Trailing minus is included */
5248  characterclass[(int)ch]++;
5249  ch = range_end;
5250  break; /* for */
5251  }
5252  if (range_end == NIL)
5253  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
5254  if (range_begin > range_end)
5255  return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
5256 
5257  for (i = (int)range_begin; i <= (int)range_end; i++)
5258  characterclass[i]++;
5259 
5260  ch = range_end;
5261  break;
5262 
5263 #if TRIO_EXTENSION
5264 
5265  case SPECIFIER_GROUP:
5266 
5267  switch (format[index + 1])
5268  {
5269  case QUALIFIER_DOT: /* Collating symbol */
5270  /*
5271  * FIXME: This will be easier to implement when multibyte
5272  * characters have been implemented. Until now, we ignore
5273  * this feature.
5274  */
5275  for (i = index + 2; ; i++)
5276  {
5277  if (format[i] == NIL)
5278  /* Error in syntax */
5279  return -1;
5280  else if (format[i] == QUALIFIER_DOT)
5281  break; /* for */
5282  }
5283  if (format[++i] != SPECIFIER_UNGROUP)
5284  return -1;
5285 
5286  index = i;
5287  break;
5288 
5289  case QUALIFIER_EQUAL: /* Equivalence class expressions */
5290  {
5291  unsigned int j;
5292  unsigned int k;
5293 
5294  if (internalCollationUnconverted)
5295  {
5296  /* Lazy evaluation of collation array */
5297  TrioGetCollation();
5298  internalCollationUnconverted = FALSE;
5299  }
5300  for (i = index + 2; ; i++)
5301  {
5302  if (format[i] == NIL)
5303  /* Error in syntax */
5304  return -1;
5305  else if (format[i] == QUALIFIER_EQUAL)
5306  break; /* for */
5307  else
5308  {
5309  /* Mark any equivalent character */
5310  k = (unsigned int)format[i];
5311  for (j = 0; internalCollationArray[k][j] != NIL; j++)
5312  characterclass[(int)internalCollationArray[k][j]]++;
5313  }
5314  }
5315  if (format[++i] != SPECIFIER_UNGROUP)
5316  return -1;
5317 
5318  index = i;
5319  }
5320  break;
5321 
5322  case QUALIFIER_COLON: /* Character class expressions */
5323 
5324  if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
5325  &format[index]))
5326  {
5327  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5328  if (isalnum(i))
5329  characterclass[i]++;
5330  index += sizeof(CLASS_ALNUM) - 1;
5331  }
5332  else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
5333  &format[index]))
5334  {
5335  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5336  if (isalpha(i))
5337  characterclass[i]++;
5338  index += sizeof(CLASS_ALPHA) - 1;
5339  }
5340  else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
5341  &format[index]))
5342  {
5343  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5344  if (iscntrl(i))
5345  characterclass[i]++;
5346  index += sizeof(CLASS_CNTRL) - 1;
5347  }
5348  else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
5349  &format[index]))
5350  {
5351  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5352  if (isdigit(i))
5353  characterclass[i]++;
5354  index += sizeof(CLASS_DIGIT) - 1;
5355  }
5356  else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
5357  &format[index]))
5358  {
5359  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5360  if (isgraph(i))
5361  characterclass[i]++;
5362  index += sizeof(CLASS_GRAPH) - 1;
5363  }
5364  else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
5365  &format[index]))
5366  {
5367  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5368  if (islower(i))
5369  characterclass[i]++;
5370  index += sizeof(CLASS_LOWER) - 1;
5371  }
5372  else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
5373  &format[index]))
5374  {
5375  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5376  if (isprint(i))
5377  characterclass[i]++;
5378  index += sizeof(CLASS_PRINT) - 1;
5379  }
5380  else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
5381  &format[index]))
5382  {
5383  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5384  if (ispunct(i))
5385  characterclass[i]++;
5386  index += sizeof(CLASS_PUNCT) - 1;
5387  }
5388  else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
5389  &format[index]))
5390  {
5391  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5392  if (isspace(i))
5393  characterclass[i]++;
5394  index += sizeof(CLASS_SPACE) - 1;
5395  }
5396  else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
5397  &format[index]))
5398  {
5399  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5400  if (isupper(i))
5401  characterclass[i]++;
5402  index += sizeof(CLASS_UPPER) - 1;
5403  }
5404  else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
5405  &format[index]))
5406  {
5407  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
5408  if (isxdigit(i))
5409  characterclass[i]++;
5410  index += sizeof(CLASS_XDIGIT) - 1;
5411  }
5412  else
5413  {
5414  characterclass[(int)ch]++;
5415  }
5416  break;
5417 
5418  default:
5419  characterclass[(int)ch]++;
5420  break;
5421  }
5422  break;
5423 
5424 #endif /* TRIO_EXTENSION */
5425 
5426  default:
5427  characterclass[(int)ch]++;
5428  break;
5429  }
5430  }
5431  return 0;
5432 }
5433 
5434 /*************************************************************************
5435  * TrioReadNumber
5436  *
5437  * We implement our own number conversion in preference of strtol and
5438  * strtoul, because we must handle 'long long' and thousand separators.
5439  */
5441 TrioReadNumber
5442 TRIO_ARGS5((self, target, flags, width, base),
5443  trio_class_t *self,
5445  trio_flags_t flags,
5446  int width,
5447  int base)
5448 {
5449  trio_uintmax_t number = 0;
5450  int digit;
5451  int count;
5452  BOOLEAN_T isNegative = FALSE;
5453  BOOLEAN_T gotNumber = FALSE;
5454  int j;
5455 
5456  assert(VALID(self));
5457  assert(VALID(self->InStream));
5458  assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
5459 
5460  if (internalDigitsUnconverted)
5461  {
5462  /* Lazy evaluation of digits array */
5463  memset(internalDigitArray, -1, sizeof(internalDigitArray));
5464  for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
5465  {
5466  internalDigitArray[(int)internalDigitsLower[j]] = j;
5467  internalDigitArray[(int)internalDigitsUpper[j]] = j;
5468  }
5469  internalDigitsUnconverted = FALSE;
5470  }
5471 
5472  TrioSkipWhitespaces(self);
5473 
5474  if (!(flags & FLAGS_UNSIGNED))
5475  {
5476  /* Leading sign */
5477  if (self->current == '+')
5478  {
5479  self->InStream(self, NULL);
5480  }
5481  else if (self->current == '-')
5482  {
5483  self->InStream(self, NULL);
5484  isNegative = TRUE;
5485  }
5486  }
5487 
5488  count = self->processed;
5489 
5490  if (flags & FLAGS_ALTERNATIVE)
5491  {
5492  switch (base)
5493  {
5494  case NO_BASE:
5495  case BASE_OCTAL:
5496  case BASE_HEX:
5497  case BASE_BINARY:
5498  if (self->current == '0')
5499  {
5500  self->InStream(self, NULL);
5501  if (self->current)
5502  {
5503  if ((base == BASE_HEX) &&
5504  (trio_to_upper(self->current) == 'X'))
5505  {
5506  self->InStream(self, NULL);
5507  }
5508  else if ((base == BASE_BINARY) &&
5509  (trio_to_upper(self->current) == 'B'))
5510  {
5511  self->InStream(self, NULL);
5512  }
5513  }
5514  }
5515  else
5516  return FALSE;
5517  break;
5518  default:
5519  break;
5520  }
5521  }
5522 
5523  while (((width == NO_WIDTH) || (self->processed - count < width)) &&
5524  (! ((self->current == EOF) || isspace(self->current))))
5525  {
5526  if (isascii(self->current))
5527  {
5528  digit = internalDigitArray[self->current];
5529  /* Abort if digit is not allowed in the specified base */
5530  if ((digit == -1) || (digit >= base))
5531  break;
5532  }
5533  else if (flags & FLAGS_QUOTE)
5534  {
5535  /* Compare with thousands separator */
5536  for (j = 0; internalThousandSeparator[j] && self->current; j++)
5537  {
5538  if (internalThousandSeparator[j] != self->current)
5539  break;
5540 
5541  self->InStream(self, NULL);
5542  }
5544  break; /* Mismatch */
5545  else
5546  continue; /* Match */
5547  }
5548  else
5549  break;
5550 
5551  number *= base;
5552  number += digit;
5553  gotNumber = TRUE; /* we need at least one digit */
5554 
5555  self->InStream(self, NULL);
5556  }
5557 
5558  /* Was anything read at all? */
5559  if (!gotNumber)
5560  return FALSE;
5561 
5562  if (target)
5563  *target = (isNegative) ? -((trio_intmax_t)number) : number;
5564  return TRUE;
5565 }
5566 
5567 /*************************************************************************
5568  * TrioReadChar
5569  */
5570 TRIO_PRIVATE int
5571 TrioReadChar
5572 TRIO_ARGS4((self, target, flags, width),
5573  trio_class_t *self,
5574  char *target,
5575  trio_flags_t flags,
5576  int width)
5577 {
5578  int i;
5579  char ch;
5581 
5582  assert(VALID(self));
5583  assert(VALID(self->InStream));
5584 
5585  for (i = 0;
5586  (self->current != EOF) && (i < width);
5587  i++)
5588  {
5589  ch = (char)self->current;
5590  self->InStream(self, NULL);
5591  if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
5592  {
5593  switch (self->current)
5594  {
5595  case '\\': ch = '\\'; break;
5596  case 'a': ch = '\007'; break;
5597  case 'b': ch = '\b'; break;
5598  case 'f': ch = '\f'; break;
5599  case 'n': ch = '\n'; break;
5600  case 'r': ch = '\r'; break;
5601  case 't': ch = '\t'; break;
5602  case 'v': ch = '\v'; break;
5603  default:
5604  if (isdigit(self->current))
5605  {
5606  /* Read octal number */
5607  if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
5608  return 0;
5609  ch = (char)number;
5610  }
5611  else if (trio_to_upper(self->current) == 'X')
5612  {
5613  /* Read hexadecimal number */
5614  self->InStream(self, NULL);
5615  if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
5616  return 0;
5617  ch = (char)number;
5618  }
5619  else
5620  {
5621  ch = (char)self->current;
5622  }
5623  break;
5624  }
5625  }
5626 
5627  if (target)
5628  target[i] = ch;
5629  }
5630  return i + 1;
5631 }
5632 
5633 /*************************************************************************
5634  * TrioReadString
5635  */
5637 TrioReadString
5638 TRIO_ARGS4((self, target, flags, width),
5639  trio_class_t *self,
5640  char *target,
5641  trio_flags_t flags,
5642  int width)
5643 {
5644  int i;
5645 
5646  assert(VALID(self));
5647  assert(VALID(self->InStream));
5648 
5649  TrioSkipWhitespaces(self);
5650 
5651  /*
5652  * Continue until end of string is reached, a whitespace is encountered,
5653  * or width is exceeded
5654  */
5655  for (i = 0;
5656  ((width == NO_WIDTH) || (i < width)) &&
5657  (! ((self->current == EOF) || isspace(self->current)));
5658  i++)
5659  {
5660  if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
5661  break; /* for */
5662  }
5663  if (target)
5664  target[i] = NIL;
5665  return TRUE;
5666 }
5667 
5668 /*************************************************************************
5669  * TrioReadWideChar
5670  */
5671 #if TRIO_WIDECHAR
5672 TRIO_PRIVATE int
5673 TrioReadWideChar
5674 TRIO_ARGS4((self, target, flags, width),
5675  trio_class_t *self,
5676  trio_wchar_t *target,
5677  trio_flags_t flags,
5678  int width)
5679 {
5680  int i;
5681  int j;
5682  int size;
5683  int amount = 0;
5684  trio_wchar_t wch;
5685  char buffer[MB_LEN_MAX + 1];
5686 
5687  assert(VALID(self));
5688  assert(VALID(self->InStream));
5689 
5690  for (i = 0;
5691  (self->current != EOF) && (i < width);
5692  i++)
5693  {
5694  if (isascii(self->current))
5695  {
5696  if (TrioReadChar(self, buffer, flags, 1) == 0)
5697  return 0;
5698  buffer[1] = NIL;
5699  }
5700  else
5701  {
5702  /*
5703  * Collect a multibyte character, by enlarging buffer until
5704  * it contains a fully legal multibyte character, or the
5705  * buffer is full.
5706  */
5707  j = 0;
5708  do
5709  {
5710  buffer[j++] = (char)self->current;
5711  buffer[j] = NIL;
5712  self->InStream(self, NULL);
5713  }
5714  while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
5715  }
5716  if (target)
5717  {
5718  size = mbtowc(&wch, buffer, sizeof(buffer));
5719  if (size > 0)
5720  target[i] = wch;
5721  }
5722  amount += size;
5723  self->InStream(self, NULL);
5724  }
5725  return amount;
5726 }
5727 #endif /* TRIO_WIDECHAR */
5728 
5729 /*************************************************************************
5730  * TrioReadWideString
5731  */
5732 #if TRIO_WIDECHAR
5734 TrioReadWideString
5735 TRIO_ARGS4((self, target, flags, width),
5736  trio_class_t *self,
5737  trio_wchar_t *target,
5738  trio_flags_t flags,
5739  int width)
5740 {
5741  int i;
5742  int size;
5743 
5744  assert(VALID(self));
5745  assert(VALID(self->InStream));
5746 
5747  TrioSkipWhitespaces(self);
5748 
5749 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
5750  (void)mblen(NULL, 0);
5751 #endif
5752 
5753  /*
5754  * Continue until end of string is reached, a whitespace is encountered,
5755  * or width is exceeded
5756  */
5757  for (i = 0;
5758  ((width == NO_WIDTH) || (i < width)) &&
5759  (! ((self->current == EOF) || isspace(self->current)));
5760  )
5761  {
5762  size = TrioReadWideChar(self, &target[i], flags, 1);
5763  if (size == 0)
5764  break; /* for */
5765 
5766  i += size;
5767  }
5768  if (target)
5769  target[i] = WCONST('\0');
5770  return TRUE;
5771 }
5772 #endif /* TRIO_WIDECHAR */
5773 
5774 /*************************************************************************
5775  * TrioReadGroup
5776  *
5777  * FIXME: characterclass does not work with multibyte characters
5778  */