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