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