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