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