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