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