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