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