Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentrio.c
Go to the documentation of this file.
00001 /************************************************************************* 00002 * 00003 * $Id$ 00004 * 00005 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. 00006 * 00007 * Permission to use, copy, modify, and distribute this software for any 00008 * purpose with or without fee is hereby granted, provided that the above 00009 * copyright notice and this permission notice appear in all copies. 00010 * 00011 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 00012 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 00013 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND 00014 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. 00015 * 00016 ************************************************************************* 00017 * 00018 * A note to trio contributors: 00019 * 00020 * Avoid heap allocation at all costs to ensure that the trio functions 00021 * are async-safe. The exceptions are the printf/fprintf functions, which 00022 * uses fputc, and the asprintf functions and the <alloc> modifier, which 00023 * by design are required to allocate form the heap. 00024 * 00025 ************************************************************************/ 00026 00027 /* 00028 * TODO: 00029 * - Scan is probably too permissive about its modifiers. 00030 * - C escapes in %#[] ? 00031 * - Multibyte characters (done for format parsing, except scan groups) 00032 * - Complex numbers? (C99 _Complex) 00033 * - Boolean values? (C99 _Bool) 00034 * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used 00035 * to print the mantissa, e.g. NaN(0xc000000000000000) 00036 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack 00037 * for %a, because C99 used %a for other purposes. If specified as 00038 * %as or %a[ it is interpreted as the alloc modifier, otherwise as 00039 * the C99 hex-float. This means that you cannot scan %as as a hex-float 00040 * immediately followed by an 's'. 00041 * - Scanning of collating symbols. 00042 */ 00043 00044 /************************************************************************* 00045 * Trio include files 00046 */ 00047 #include "triodef.h" 00048 #include "trio.h" 00049 #include "triop.h" 00050 #include "trionan.h" 00051 #if !defined(TRIO_MINIMAL) 00052 # include "triostr.h" 00053 #endif 00054 00055 /************************************************************************** 00056 * 00057 * Definitions 00058 * 00059 *************************************************************************/ 00060 00061 #include <math.h> 00062 #include <limits.h> 00063 #include <float.h> 00064 00065 #if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \ 00066 || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \ 00067 && !defined(_WIN32_WCE) 00068 # define TRIO_COMPILER_SUPPORTS_MULTIBYTE 00069 # if !defined(MB_LEN_MAX) 00070 # define MB_LEN_MAX 6 00071 # endif 00072 #endif 00073 00074 #if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB) 00075 # define TRIO_COMPILER_SUPPORTS_MSVC_INT 00076 #endif 00077 00078 #if defined(_WIN32_WCE) 00079 #include <wincecompat.h> 00080 #endif 00081 00082 /************************************************************************* 00083 * Generic definitions 00084 */ 00085 00086 #if !(defined(DEBUG) || defined(NDEBUG)) 00087 # define NDEBUG 00088 #endif 00089 00090 #include <assert.h> 00091 #include <ctype.h> 00092 #if !defined(TRIO_COMPILER_SUPPORTS_C99) 00093 # define isblank(x) (((x)==32) || ((x)==9)) 00094 #endif 00095 #if defined(TRIO_COMPILER_ANCIENT) 00096 # include <varargs.h> 00097 #else 00098 # include <stdarg.h> 00099 #endif 00100 #include <stddef.h> 00101 00102 #ifdef HAVE_ERRNO_H 00103 #include <errno.h> 00104 #endif 00105 00106 #ifndef NULL 00107 # define NULL 0 00108 #endif 00109 #define NIL ((char)0) 00110 #ifndef FALSE 00111 # define FALSE (1 == 0) 00112 # define TRUE (! FALSE) 00113 #endif 00114 #define BOOLEAN_T int 00115 00116 /* mincore() can be used for debugging purposes */ 00117 #define VALID(x) (NULL != (x)) 00118 00119 #if TRIO_ERRORS 00120 /* 00121 * Encode the error code and the position. This is decoded 00122 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION. 00123 */ 00124 # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8))) 00125 #else 00126 # define TRIO_ERROR_RETURN(x,y) (-1) 00127 #endif 00128 00129 typedef unsigned long trio_flags_t; 00130 00131 00132 /************************************************************************* 00133 * Platform specific definitions 00134 */ 00135 #if defined(TRIO_PLATFORM_UNIX) 00136 # include <unistd.h> 00137 # include <signal.h> 00138 # include <locale.h> 00139 # define USE_LOCALE 00140 #endif /* TRIO_PLATFORM_UNIX */ 00141 #if defined(TRIO_PLATFORM_VMS) 00142 # include <unistd.h> 00143 #endif 00144 #if defined(TRIO_PLATFORM_WIN32) 00145 # if defined(_WIN32_WCE) 00146 # include <wincecompat.h> 00147 # else 00148 # include <io.h> 00149 # define read _read 00150 # define write _write 00151 # endif 00152 #endif /* TRIO_PLATFORM_WIN32 */ 00153 00154 #if TRIO_WIDECHAR 00155 # if defined(TRIO_COMPILER_SUPPORTS_ISO94) 00156 # include <wchar.h> 00157 # include <wctype.h> 00158 typedef wchar_t trio_wchar_t; 00159 typedef wint_t trio_wint_t; 00160 # else 00161 typedef char trio_wchar_t; 00162 typedef int trio_wint_t; 00163 # define WCONST(x) L ## x 00164 # define WEOF EOF 00165 # define iswalnum(x) isalnum(x) 00166 # define iswalpha(x) isalpha(x) 00167 # define iswblank(x) isblank(x) 00168 # define iswcntrl(x) iscntrl(x) 00169 # define iswdigit(x) isdigit(x) 00170 # define iswgraph(x) isgraph(x) 00171 # define iswlower(x) islower(x) 00172 # define iswprint(x) isprint(x) 00173 # define iswpunct(x) ispunct(x) 00174 # define iswspace(x) isspace(x) 00175 # define iswupper(x) isupper(x) 00176 # define iswxdigit(x) isxdigit(x) 00177 # endif 00178 #endif 00179 00180 00181 /************************************************************************* 00182 * Compiler dependent definitions 00183 */ 00184 00185 /* Support for long long */ 00186 #ifndef __cplusplus 00187 # if !defined(USE_LONGLONG) 00188 # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__) 00189 # define USE_LONGLONG 00190 # elif defined(TRIO_COMPILER_SUNPRO) 00191 # define USE_LONGLONG 00192 # elif defined(_LONG_LONG) || defined(_LONGLONG) 00193 # define USE_LONGLONG 00194 # endif 00195 # endif 00196 #endif 00197 00198 /* The extra long numbers */ 00199 #if defined(USE_LONGLONG) 00200 typedef signed long long int trio_longlong_t; 00201 typedef unsigned long long int trio_ulonglong_t; 00202 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT) 00203 typedef signed __int64 trio_longlong_t; 00204 typedef unsigned __int64 trio_ulonglong_t; 00205 #else 00206 typedef TRIO_SIGNED long int trio_longlong_t; 00207 typedef unsigned long int trio_ulonglong_t; 00208 #endif 00209 00210 /* Maximal and fixed integer types */ 00211 #if defined(TRIO_COMPILER_SUPPORTS_C99) 00212 # include <stdint.h> 00213 typedef intmax_t trio_intmax_t; 00214 typedef uintmax_t trio_uintmax_t; 00215 typedef int8_t trio_int8_t; 00216 typedef int16_t trio_int16_t; 00217 typedef int32_t trio_int32_t; 00218 typedef int64_t trio_int64_t; 00219 #elif defined(TRIO_COMPILER_SUPPORTS_UNIX98) 00220 # include <inttypes.h> 00221 typedef intmax_t trio_intmax_t; 00222 typedef uintmax_t trio_uintmax_t; 00223 typedef int8_t trio_int8_t; 00224 typedef int16_t trio_int16_t; 00225 typedef int32_t trio_int32_t; 00226 typedef int64_t trio_int64_t; 00227 #elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT) 00228 typedef trio_longlong_t trio_intmax_t; 00229 typedef trio_ulonglong_t trio_uintmax_t; 00230 typedef __int8 trio_int8_t; 00231 typedef __int16 trio_int16_t; 00232 typedef __int32 trio_int32_t; 00233 typedef __int64 trio_int64_t; 00234 #else 00235 typedef trio_longlong_t trio_intmax_t; 00236 typedef trio_ulonglong_t trio_uintmax_t; 00237 # if defined(TRIO_INT8_T) 00238 typedef TRIO_INT8_T trio_int8_t; 00239 # else 00240 typedef TRIO_SIGNED char trio_int8_t; 00241 # endif 00242 # if defined(TRIO_INT16_T) 00243 typedef TRIO_INT16_T trio_int16_t; 00244 # else 00245 typedef TRIO_SIGNED short trio_int16_t; 00246 # endif 00247 # if defined(TRIO_INT32_T) 00248 typedef TRIO_INT32_T trio_int32_t; 00249 # else 00250 typedef TRIO_SIGNED int trio_int32_t; 00251 # endif 00252 # if defined(TRIO_INT64_T) 00253 typedef TRIO_INT64_T trio_int64_t; 00254 # else 00255 typedef trio_longlong_t trio_int64_t; 00256 # endif 00257 #endif 00258 00259 #if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \ 00260 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \ 00261 && !defined(_WIN32_WCE) 00262 # define floorl(x) floor((double)(x)) 00263 # define fmodl(x,y) fmod((double)(x),(double)(y)) 00264 # define powl(x,y) pow((double)(x),(double)(y)) 00265 #endif 00266 00267 #define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x)) 00268 00269 /************************************************************************* 00270 * Internal Definitions 00271 */ 00272 00273 #ifndef DECIMAL_DIG 00274 # define DECIMAL_DIG DBL_DIG 00275 #endif 00276 00277 /* Long double sizes */ 00278 #ifdef LDBL_DIG 00279 # define MAX_MANTISSA_DIGITS LDBL_DIG 00280 # define MAX_EXPONENT_DIGITS 4 00281 # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP 00282 #else 00283 # define MAX_MANTISSA_DIGITS DECIMAL_DIG 00284 # define MAX_EXPONENT_DIGITS 3 00285 # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP 00286 #endif 00287 00288 #if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG) 00289 # undef LDBL_DIG 00290 # undef LDBL_MANT_DIG 00291 # undef LDBL_EPSILON 00292 # define LDBL_DIG DBL_DIG 00293 # define LDBL_MANT_DIG DBL_MANT_DIG 00294 # define LDBL_EPSILON DBL_EPSILON 00295 #endif 00296 00297 /* The maximal number of digits is for base 2 */ 00298 #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT) 00299 /* The width of a pointer. The number of bits in a hex digit is 4 */ 00300 #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4) 00301 00302 /* Infinite and Not-A-Number for floating-point */ 00303 #define INFINITE_LOWER "inf" 00304 #define INFINITE_UPPER "INF" 00305 #define LONG_INFINITE_LOWER "infinite" 00306 #define LONG_INFINITE_UPPER "INFINITE" 00307 #define NAN_LOWER "nan" 00308 #define NAN_UPPER "NAN" 00309 00310 /* Various constants */ 00311 enum { 00312 TYPE_PRINT = 1, 00313 TYPE_SCAN = 2, 00314 00315 /* Flags. FLAGS_LAST must be less than ULONG_MAX */ 00316 FLAGS_NEW = 0, 00317 FLAGS_STICKY = 1, 00318 FLAGS_SPACE = 2 * FLAGS_STICKY, 00319 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE, 00320 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN, 00321 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST, 00322 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE, 00323 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT, 00324 FLAGS_LONG = 2 * FLAGS_SHORTSHORT, 00325 FLAGS_QUAD = 2 * FLAGS_LONG, 00326 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD, 00327 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE, 00328 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T, 00329 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T, 00330 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T, 00331 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING, 00332 FLAGS_UPPER = 2 * FLAGS_UNSIGNED, 00333 FLAGS_WIDTH = 2 * FLAGS_UPPER, 00334 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH, 00335 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER, 00336 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION, 00337 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER, 00338 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE, 00339 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER, 00340 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E, 00341 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G, 00342 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE, 00343 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR, 00344 FLAGS_IGNORE = 2 * FLAGS_ALLOC, 00345 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE, 00346 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER, 00347 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER, 00348 FLAGS_LAST = FLAGS_FIXED_SIZE, 00349 /* Reused flags */ 00350 FLAGS_EXCLUDE = FLAGS_SHORT, 00351 FLAGS_USER_DEFINED = FLAGS_IGNORE, 00352 FLAGS_ROUNDING = FLAGS_INTMAX_T, 00353 /* Compounded flags */ 00354 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T, 00355 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT, 00356 00357 NO_POSITION = -1, 00358 NO_WIDTH = 0, 00359 NO_PRECISION = -1, 00360 NO_SIZE = -1, 00361 00362 /* Do not change these */ 00363 NO_BASE = -1, 00364 MIN_BASE = 2, 00365 MAX_BASE = 36, 00366 BASE_BINARY = 2, 00367 BASE_OCTAL = 8, 00368 BASE_DECIMAL = 10, 00369 BASE_HEX = 16, 00370 00371 /* Maximal number of allowed parameters */ 00372 MAX_PARAMETERS = 64, 00373 /* Maximal number of characters in class */ 00374 MAX_CHARACTER_CLASS = UCHAR_MAX + 1, 00375 00376 /* Maximal string lengths for user-defined specifiers */ 00377 MAX_USER_NAME = 64, 00378 MAX_USER_DATA = 256, 00379 00380 /* Maximal length of locale separator strings */ 00381 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX, 00382 /* Maximal number of integers in grouping */ 00383 MAX_LOCALE_GROUPS = 64, 00384 00385 /* Initial size of asprintf buffer */ 00386 DYNAMIC_START_SIZE = 32 00387 }; 00388 00389 #define NO_GROUPING ((int)CHAR_MAX) 00390 00391 /* Fundamental formatting parameter types */ 00392 #define FORMAT_UNKNOWN 0 00393 #define FORMAT_INT 1 00394 #define FORMAT_DOUBLE 2 00395 #define FORMAT_CHAR 3 00396 #define FORMAT_STRING 4 00397 #define FORMAT_POINTER 5 00398 #define FORMAT_COUNT 6 00399 #define FORMAT_PARAMETER 7 00400 #define FORMAT_GROUP 8 00401 #if TRIO_GNU 00402 # define FORMAT_ERRNO 9 00403 #endif 00404 #if TRIO_EXTENSION 00405 # define FORMAT_USER_DEFINED 10 00406 #endif 00407 00408 /* Character constants */ 00409 #define CHAR_IDENTIFIER '%' 00410 #define CHAR_BACKSLASH '\\' 00411 #define CHAR_QUOTE '\"' 00412 #define CHAR_ADJUST ' ' 00413 00414 /* Character class expressions */ 00415 #define CLASS_ALNUM "[:alnum:]" 00416 #define CLASS_ALPHA "[:alpha:]" 00417 #define CLASS_BLANK "[:blank:]" 00418 #define CLASS_CNTRL "[:cntrl:]" 00419 #define CLASS_DIGIT "[:digit:]" 00420 #define CLASS_GRAPH "[:graph:]" 00421 #define CLASS_LOWER "[:lower:]" 00422 #define CLASS_PRINT "[:print:]" 00423 #define CLASS_PUNCT "[:punct:]" 00424 #define CLASS_SPACE "[:space:]" 00425 #define CLASS_UPPER "[:upper:]" 00426 #define CLASS_XDIGIT "[:xdigit:]" 00427 00428 /* 00429 * SPECIFIERS: 00430 * 00431 * 00432 * a Hex-float 00433 * A Hex-float 00434 * c Character 00435 * C Widechar character (wint_t) 00436 * d Decimal 00437 * e Float 00438 * E Float 00439 * F Float 00440 * F Float 00441 * g Float 00442 * G Float 00443 * i Integer 00444 * m Error message 00445 * n Count 00446 * o Octal 00447 * p Pointer 00448 * s String 00449 * S Widechar string (wchar_t *) 00450 * u Unsigned 00451 * x Hex 00452 * X Hex 00453 * [] Group 00454 * <> User-defined 00455 * 00456 * Reserved: 00457 * 00458 * D Binary Coded Decimal %D(length,precision) (OS/390) 00459 */ 00460 #define SPECIFIER_CHAR 'c' 00461 #define SPECIFIER_STRING 's' 00462 #define SPECIFIER_DECIMAL 'd' 00463 #define SPECIFIER_INTEGER 'i' 00464 #define SPECIFIER_UNSIGNED 'u' 00465 #define SPECIFIER_OCTAL 'o' 00466 #define SPECIFIER_HEX 'x' 00467 #define SPECIFIER_HEX_UPPER 'X' 00468 #define SPECIFIER_FLOAT_E 'e' 00469 #define SPECIFIER_FLOAT_E_UPPER 'E' 00470 #define SPECIFIER_FLOAT_F 'f' 00471 #define SPECIFIER_FLOAT_F_UPPER 'F' 00472 #define SPECIFIER_FLOAT_G 'g' 00473 #define SPECIFIER_FLOAT_G_UPPER 'G' 00474 #define SPECIFIER_POINTER 'p' 00475 #define SPECIFIER_GROUP '[' 00476 #define SPECIFIER_UNGROUP ']' 00477 #define SPECIFIER_COUNT 'n' 00478 #if TRIO_UNIX98 00479 # define SPECIFIER_CHAR_UPPER 'C' 00480 # define SPECIFIER_STRING_UPPER 'S' 00481 #endif 00482 #if TRIO_C99 00483 # define SPECIFIER_HEXFLOAT 'a' 00484 # define SPECIFIER_HEXFLOAT_UPPER 'A' 00485 #endif 00486 #if TRIO_GNU 00487 # define SPECIFIER_ERRNO 'm' 00488 #endif 00489 #if TRIO_EXTENSION 00490 # define SPECIFIER_BINARY 'b' 00491 # define SPECIFIER_BINARY_UPPER 'B' 00492 # define SPECIFIER_USER_DEFINED_BEGIN '<' 00493 # define SPECIFIER_USER_DEFINED_END '>' 00494 # define SPECIFIER_USER_DEFINED_SEPARATOR ':' 00495 #endif 00496 00497 /* 00498 * QUALIFIERS: 00499 * 00500 * 00501 * Numbers = d,i,o,u,x,X 00502 * Float = a,A,e,E,f,F,g,G 00503 * String = s 00504 * Char = c 00505 * 00506 * 00507 * 9$ Position 00508 * Use the 9th parameter. 9 can be any number between 1 and 00509 * the maximal argument 00510 * 00511 * 9 Width 00512 * Set width to 9. 9 can be any number, but must not be postfixed 00513 * by '$' 00514 * 00515 * h Short 00516 * Numbers: 00517 * (unsigned) short int 00518 * 00519 * hh Short short 00520 * Numbers: 00521 * (unsigned) char 00522 * 00523 * l Long 00524 * Numbers: 00525 * (unsigned) long int 00526 * String: 00527 * as the S specifier 00528 * Char: 00529 * as the C specifier 00530 * 00531 * ll Long Long 00532 * Numbers: 00533 * (unsigned) long long int 00534 * 00535 * L Long Double 00536 * Float 00537 * long double 00538 * 00539 * # Alternative 00540 * Float: 00541 * Decimal-point is always present 00542 * String: 00543 * non-printable characters are handled as \number 00544 * 00545 * Spacing 00546 * 00547 * + Sign 00548 * 00549 * - Alignment 00550 * 00551 * . Precision 00552 * 00553 * * Parameter 00554 * print: use parameter 00555 * scan: no parameter (ignore) 00556 * 00557 * q Quad 00558 * 00559 * Z size_t 00560 * 00561 * w Widechar 00562 * 00563 * ' Thousands/quote 00564 * Numbers: 00565 * Integer part grouped in thousands 00566 * Binary numbers: 00567 * Number grouped in nibbles (4 bits) 00568 * String: 00569 * Quoted string 00570 * 00571 * j intmax_t 00572 * t prtdiff_t 00573 * z size_t 00574 * 00575 * ! Sticky 00576 * @ Parameter (for both print and scan) 00577 * 00578 * I n-bit Integer 00579 * Numbers: 00580 * The following options exists 00581 * I8 = 8-bit integer 00582 * I16 = 16-bit integer 00583 * I32 = 32-bit integer 00584 * I64 = 64-bit integer 00585 */ 00586 #define QUALIFIER_POSITION '$' 00587 #define QUALIFIER_SHORT 'h' 00588 #define QUALIFIER_LONG 'l' 00589 #define QUALIFIER_LONG_UPPER 'L' 00590 #define QUALIFIER_ALTERNATIVE '#' 00591 #define QUALIFIER_SPACE ' ' 00592 #define QUALIFIER_PLUS '+' 00593 #define QUALIFIER_MINUS '-' 00594 #define QUALIFIER_DOT '.' 00595 #define QUALIFIER_STAR '*' 00596 #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */ 00597 #if TRIO_C99 00598 # define QUALIFIER_SIZE_T 'z' 00599 # define QUALIFIER_PTRDIFF_T 't' 00600 # define QUALIFIER_INTMAX_T 'j' 00601 #endif 00602 #if TRIO_BSD || TRIO_GNU 00603 # define QUALIFIER_QUAD 'q' 00604 #endif 00605 #if TRIO_GNU 00606 # define QUALIFIER_SIZE_T_UPPER 'Z' 00607 #endif 00608 #if TRIO_MISC 00609 # define QUALIFIER_WIDECHAR 'w' 00610 #endif 00611 #if TRIO_MICROSOFT 00612 # define QUALIFIER_FIXED_SIZE 'I' 00613 #endif 00614 #if TRIO_EXTENSION 00615 # define QUALIFIER_QUOTE '\'' 00616 # define QUALIFIER_STICKY '!' 00617 # define QUALIFIER_VARSIZE '&' /* This should remain undocumented */ 00618 # define QUALIFIER_PARAM '@' /* Experimental */ 00619 # define QUALIFIER_COLON ':' /* For scanlists */ 00620 # define QUALIFIER_EQUAL '=' /* For scanlists */ 00621 # define QUALIFIER_ROUNDING_UPPER 'R' 00622 #endif 00623 00624 00625 /************************************************************************* 00626 * 00627 * Internal Structures 00628 * 00629 *************************************************************************/ 00630 00631 /* Parameters */ 00632 typedef struct { 00633 /* An indication of which entry in the data union is used */ 00634 int type; 00635 /* The flags */ 00636 trio_flags_t flags; 00637 /* The width qualifier */ 00638 int width; 00639 /* The precision qualifier */ 00640 int precision; 00641 /* The base qualifier */ 00642 int base; 00643 /* The size for the variable size qualifier */ 00644 int varsize; 00645 /* The marker of the end of the specifier */ 00646 int indexAfterSpecifier; 00647 /* The data from the argument list */ 00648 union { 00649 char *string; 00650 #if TRIO_WIDECHAR 00651 trio_wchar_t *wstring; 00652 #endif 00653 trio_pointer_t pointer; 00654 union { 00655 trio_intmax_t as_signed; 00656 trio_uintmax_t as_unsigned; 00657 } number; 00658 double doubleNumber; 00659 double *doublePointer; 00660 trio_long_double_t longdoubleNumber; 00661 trio_long_double_t *longdoublePointer; 00662 int errorNumber; 00663 } data; 00664 /* For the user-defined specifier */ 00665 char user_name[MAX_USER_NAME]; 00666 char user_data[MAX_USER_DATA]; 00667 } trio_parameter_t; 00668 00669 /* Container for customized functions */ 00670 typedef struct { 00671 union { 00672 trio_outstream_t out; 00673 trio_instream_t in; 00674 } stream; 00675 trio_pointer_t closure; 00676 } trio_custom_t; 00677 00678 /* General trio "class" */ 00679 typedef struct _trio_class_t { 00680 /* 00681 * The function to write characters to a stream. 00682 */ 00683 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int)); 00684 /* 00685 * The function to read characters from a stream. 00686 */ 00687 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *)); 00688 /* 00689 * The current location in the stream. 00690 */ 00691 trio_pointer_t location; 00692 /* 00693 * The character currently being processed. 00694 */ 00695 int current; 00696 /* 00697 * The number of characters that would have been written/read 00698 * if there had been sufficient space. 00699 */ 00700 int processed; 00701 /* 00702 * The number of characters that are actually written/read. 00703 * Processed and committed will only differ for the *nprintf 00704 * and *nscanf functions. 00705 */ 00706 int committed; 00707 /* 00708 * The upper limit of characters that may be written/read. 00709 */ 00710 int max; 00711 /* 00712 * The last output error that was detected. 00713 */ 00714 int error; 00715 } trio_class_t; 00716 00717 /* References (for user-defined callbacks) */ 00718 typedef struct _trio_reference_t { 00719 trio_class_t *data; 00720 trio_parameter_t *parameter; 00721 } trio_reference_t; 00722 00723 /* Registered entries (for user-defined callbacks) */ 00724 typedef struct _trio_userdef_t { 00725 struct _trio_userdef_t *next; 00726 trio_callback_t callback; 00727 char *name; 00728 } trio_userdef_t; 00729 00730 /************************************************************************* 00731 * 00732 * Internal Variables 00733 * 00734 *************************************************************************/ 00735 00736 static TRIO_CONST char rcsid[] = "@(#)$Id$"; 00737 00738 /* 00739 * Need this to workaround a parser bug in HP C/iX compiler that fails 00740 * to resolves macro definitions that includes type 'long double', 00741 * e.g: va_arg(arg_ptr, long double) 00742 */ 00743 #if defined(TRIO_PLATFORM_MPEIX) 00744 static TRIO_CONST trio_long_double_t ___dummy_long_double = 0; 00745 #endif 00746 00747 static TRIO_CONST char internalNullString[] = "(nil)"; 00748 00749 #if defined(USE_LOCALE) 00750 static struct lconv *internalLocaleValues = NULL; 00751 #endif 00752 00753 /* 00754 * UNIX98 says "in a locale where the radix character is not defined, 00755 * the radix character defaults to a period (.)" 00756 */ 00757 static int internalDecimalPointLength = 1; 00758 static int internalThousandSeparatorLength = 1; 00759 static char internalDecimalPoint = '.'; 00760 static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = "."; 00761 static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ","; 00762 static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING }; 00763 00764 static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 00765 static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 00766 static BOOLEAN_T internalDigitsUnconverted = TRUE; 00767 static int internalDigitArray[128]; 00768 #if TRIO_EXTENSION 00769 static BOOLEAN_T internalCollationUnconverted = TRUE; 00770 static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS]; 00771 #endif 00772 00773 #if TRIO_EXTENSION 00774 static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL; 00775 static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL; 00776 static trio_userdef_t *internalUserDef = NULL; 00777 #endif 00778 00779 00780 /************************************************************************* 00781 * 00782 * Internal Functions 00783 * 00784 ************************************************************************/ 00785 00786 #if defined(TRIO_MINIMAL) 00787 # define TRIO_STRING_PUBLIC static 00788 # include "triostr.c" 00789 #endif /* defined(TRIO_MINIMAL) */ 00790 00791 /************************************************************************* 00792 * TrioIsQualifier 00793 * 00794 * Description: 00795 * Remember to add all new qualifiers to this function. 00796 * QUALIFIER_POSITION must not be added. 00797 */ 00798 TRIO_PRIVATE BOOLEAN_T 00799 TrioIsQualifier 00800 TRIO_ARGS1((character), 00801 TRIO_CONST char character) 00802 { 00803 /* QUALIFIER_POSITION is not included */ 00804 switch (character) 00805 { 00806 case '0': case '1': case '2': case '3': case '4': 00807 case '5': case '6': case '7': case '8': case '9': 00808 case QUALIFIER_PLUS: 00809 case QUALIFIER_MINUS: 00810 case QUALIFIER_SPACE: 00811 case QUALIFIER_DOT: 00812 case QUALIFIER_STAR: 00813 case QUALIFIER_ALTERNATIVE: 00814 case QUALIFIER_SHORT: 00815 case QUALIFIER_LONG: 00816 case QUALIFIER_LONG_UPPER: 00817 case QUALIFIER_CIRCUMFLEX: 00818 #if defined(QUALIFIER_SIZE_T) 00819 case QUALIFIER_SIZE_T: 00820 #endif 00821 #if defined(QUALIFIER_PTRDIFF_T) 00822 case QUALIFIER_PTRDIFF_T: 00823 #endif 00824 #if defined(QUALIFIER_INTMAX_T) 00825 case QUALIFIER_INTMAX_T: 00826 #endif 00827 #if defined(QUALIFIER_QUAD) 00828 case QUALIFIER_QUAD: 00829 #endif 00830 #if defined(QUALIFIER_SIZE_T_UPPER) 00831 case QUALIFIER_SIZE_T_UPPER: 00832 #endif 00833 #if defined(QUALIFIER_WIDECHAR) 00834 case QUALIFIER_WIDECHAR: 00835 #endif 00836 #if defined(QUALIFIER_QUOTE) 00837 case QUALIFIER_QUOTE: 00838 #endif 00839 #if defined(QUALIFIER_STICKY) 00840 case QUALIFIER_STICKY: 00841 #endif 00842 #if defined(QUALIFIER_VARSIZE) 00843 case QUALIFIER_VARSIZE: 00844 #endif 00845 #if defined(QUALIFIER_PARAM) 00846 case QUALIFIER_PARAM: 00847 #endif 00848 #if defined(QUALIFIER_FIXED_SIZE) 00849 case QUALIFIER_FIXED_SIZE: 00850 #endif 00851 #if defined(QUALIFIER_ROUNDING_UPPER) 00852 case QUALIFIER_ROUNDING_UPPER: 00853 #endif 00854 return TRUE; 00855 default: 00856 return FALSE; 00857 } 00858 } 00859 00860 /************************************************************************* 00861 * TrioSetLocale 00862 */ 00863 #if defined(USE_LOCALE) 00864 TRIO_PRIVATE void 00865 TrioSetLocale(TRIO_NOARGS) 00866 { 00867 internalLocaleValues = (struct lconv *)localeconv(); 00868 if (internalLocaleValues) 00869 { 00870 if ((internalLocaleValues->decimal_point) && 00871 (internalLocaleValues->decimal_point[0] != NIL)) 00872 { 00873 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point); 00874 if (internalDecimalPointLength == 1) 00875 { 00876 internalDecimalPoint = internalLocaleValues->decimal_point[0]; 00877 } 00878 else 00879 { 00880 internalDecimalPoint = NIL; 00881 trio_copy_max(internalDecimalPointString, 00882 sizeof(internalDecimalPointString), 00883 internalLocaleValues->decimal_point); 00884 } 00885 } 00886 if ((internalLocaleValues->thousands_sep) && 00887 (internalLocaleValues->thousands_sep[0] != NIL)) 00888 { 00889 trio_copy_max(internalThousandSeparator, 00890 sizeof(internalThousandSeparator), 00891 internalLocaleValues->thousands_sep); 00892 internalThousandSeparatorLength = trio_length(internalThousandSeparator); 00893 } 00894 if ((internalLocaleValues->grouping) && 00895 (internalLocaleValues->grouping[0] != NIL)) 00896 { 00897 trio_copy_max(internalGrouping, 00898 sizeof(internalGrouping), 00899 internalLocaleValues->grouping); 00900 } 00901 } 00902 } 00903 #endif /* defined(USE_LOCALE) */ 00904 00905 TRIO_PRIVATE int 00906 TrioCalcThousandSeparatorLength 00907 TRIO_ARGS1((digits), 00908 int digits) 00909 { 00910 #if TRIO_EXTENSION 00911 int count = 0; 00912 int step = NO_GROUPING; 00913 char *groupingPointer = internalGrouping; 00914 00915 while (digits > 0) 00916 { 00917 if (*groupingPointer == CHAR_MAX) 00918 { 00919 /* Disable grouping */ 00920 break; /* while */ 00921 } 00922 else if (*groupingPointer == 0) 00923 { 00924 /* Repeat last group */ 00925 if (step == NO_GROUPING) 00926 { 00927 /* Error in locale */ 00928 break; /* while */ 00929 } 00930 } 00931 else 00932 { 00933 step = *groupingPointer++; 00934 } 00935 if (digits > step) 00936 count += internalThousandSeparatorLength; 00937 digits -= step; 00938 } 00939 return count; 00940 #else 00941 return 0; 00942 #endif 00943 } 00944 00945 TRIO_PRIVATE BOOLEAN_T 00946 TrioFollowedBySeparator 00947 TRIO_ARGS1((position), 00948 int position) 00949 { 00950 #if TRIO_EXTENSION 00951 int step = 0; 00952 char *groupingPointer = internalGrouping; 00953 00954 position--; 00955 if (position == 0) 00956 return FALSE; 00957 while (position > 0) 00958 { 00959 if (*groupingPointer == CHAR_MAX) 00960 { 00961 /* Disable grouping */ 00962 break; /* while */ 00963 } 00964 else if (*groupingPointer != 0) 00965 { 00966 step = *groupingPointer++; 00967 } 00968 if (step == 0) 00969 break; 00970 position -= step; 00971 } 00972 return (position == 0); 00973 #else 00974 return FALSE; 00975 #endif 00976 } 00977 00978 /************************************************************************* 00979 * TrioGetPosition 00980 * 00981 * Get the %n$ position. 00982 */ 00983 TRIO_PRIVATE int 00984 TrioGetPosition 00985 TRIO_ARGS2((format, indexPointer), 00986 TRIO_CONST char *format, 00987 int *indexPointer) 00988 { 00989 #if TRIO_UNIX98 00990 char *tmpformat; 00991 int number = 0; 00992 int index = *indexPointer; 00993 00994 number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL); 00995 index = (int)(tmpformat - format); 00996 if ((number != 0) && (QUALIFIER_POSITION == format[index++])) 00997 { 00998 *indexPointer = index; 00999 /* 01000 * number is decreased by 1, because n$ starts from 1, whereas 01001 * the array it is indexing starts from 0. 01002 */ 01003 return number - 1; 01004 } 01005 #endif 01006 return NO_POSITION; 01007 } 01008 01009 #if TRIO_EXTENSION 01010 /************************************************************************* 01011 * TrioFindNamespace 01012 * 01013 * Find registered user-defined specifier. 01014 * The prev argument is used for optimization only. 01015 */ 01016 TRIO_PRIVATE trio_userdef_t * 01017 TrioFindNamespace 01018 TRIO_ARGS2((name, prev), 01019 TRIO_CONST char *name, 01020 trio_userdef_t **prev) 01021 { 01022 trio_userdef_t *def; 01023 01024 if (internalEnterCriticalRegion) 01025 (void)internalEnterCriticalRegion(NULL); 01026 01027 for (def = internalUserDef; def; def = def->next) 01028 { 01029 /* Case-sensitive string comparison */ 01030 if (trio_equal_case(def->name, name)) 01031 break; 01032 01033 if (prev) 01034 *prev = def; 01035 } 01036 01037 if (internalLeaveCriticalRegion) 01038 (void)internalLeaveCriticalRegion(NULL); 01039 01040 return def; 01041 } 01042 #endif 01043 01044 /************************************************************************* 01045 * TrioPower 01046 * 01047 * Description: 01048 * Calculate pow(base, exponent), where number and exponent are integers. 01049 */ 01050 TRIO_PRIVATE trio_long_double_t 01051 TrioPower 01052 TRIO_ARGS2((number, exponent), 01053 int number, 01054 int exponent) 01055 { 01056 trio_long_double_t result; 01057 01058 if (number == 10) 01059 { 01060 switch (exponent) 01061 { 01062 /* Speed up calculation of common cases */ 01063 case 0: 01064 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1); 01065 break; 01066 case 1: 01067 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0); 01068 break; 01069 case 2: 01070 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1); 01071 break; 01072 case 3: 01073 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2); 01074 break; 01075 case 4: 01076 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3); 01077 break; 01078 case 5: 01079 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4); 01080 break; 01081 case 6: 01082 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5); 01083 break; 01084 case 7: 01085 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6); 01086 break; 01087 case 8: 01088 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7); 01089 break; 01090 case 9: 01091 result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8); 01092 break; 01093 default: 01094 result = powl((trio_long_double_t)number, 01095 (trio_long_double_t)exponent); 01096 break; 01097 } 01098 } 01099 else 01100 { 01101 return powl((trio_long_double_t)number, (trio_long_double_t)exponent); 01102 } 01103 return result; 01104 } 01105 01106 /************************************************************************* 01107 * TrioLogarithm 01108 */ 01109 TRIO_PRIVATE double 01110 TrioLogarithm 01111 TRIO_ARGS2((number, base), 01112 double number, 01113 int base) 01114 { 01115 double result; 01116 01117 if (number <= 0.0) 01118 { 01119 /* xlC crashes on log(0) */ 01120 result = (number == 0.0) ? trio_ninf() : trio_nan(); 01121 } 01122 else 01123 { 01124 if (base == 10) 01125 { 01126 result = log10(number); 01127 } 01128 else 01129 { 01130 result = log10(number) / log10((double)base); 01131 } 01132 } 01133 return result; 01134 } 01135 01136 /************************************************************************* 01137 * TrioLogarithmBase 01138 */ 01139 TRIO_PRIVATE double 01140 TrioLogarithmBase 01141 TRIO_ARGS1((base), 01142 int base) 01143 { 01144 switch (base) 01145 { 01146 case BASE_BINARY : return 1.0; 01147 case BASE_OCTAL : return 3.0; 01148 case BASE_DECIMAL: return 3.321928094887362345; 01149 case BASE_HEX : return 4.0; 01150 default : return TrioLogarithm((double)base, 2); 01151 } 01152 } 01153 01154 /************************************************************************* 01155 * TrioParse 01156 * 01157 * Description: 01158 * Parse the format string 01159 */ 01160 TRIO_PRIVATE int 01161 TrioParse 01162 TRIO_ARGS5((type, format, parameters, arglist, argarray), 01163 int type, 01164 TRIO_CONST char *format, 01165 trio_parameter_t *parameters, 01166 va_list *arglist, 01167 trio_pointer_t *argarray) 01168 { 01169 /* Count the number of times a parameter is referenced */ 01170 unsigned short usedEntries[MAX_PARAMETERS]; 01171 /* Parameter counters */ 01172 int parameterPosition; 01173 int currentParam; 01174 int maxParam = -1; 01175 /* Utility variables */ 01176 trio_flags_t flags; 01177 int width; 01178 int precision; 01179 int varsize; 01180 int base; 01181 int index; /* Index into formatting string */ 01182 int dots; /* Count number of dots in modifier part */ 01183 BOOLEAN_T positional; /* Does the specifier have a positional? */ 01184 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */ 01185 /* 01186 * indices specifies the order in which the parameters must be 01187 * read from the va_args (this is necessary to handle positionals) 01188 */ 01189 int indices[MAX_PARAMETERS]; 01190 int pos = 0; 01191 /* Various variables */ 01192 char ch; 01193 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 01194 int charlen; 01195 #endif 01196 int save_errno; 01197 int i = -1; 01198 int num; 01199 char *tmpformat; 01200 01201 /* One and only one of arglist and argarray must be used */ 01202 assert((arglist != NULL) ^ (argarray != NULL)); 01203 01204 /* 01205 * The 'parameters' array is not initialized, but we need to 01206 * know which entries we have used. 01207 */ 01208 memset(usedEntries, 0, sizeof(usedEntries)); 01209 01210 save_errno = errno; 01211 index = 0; 01212 parameterPosition = 0; 01213 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 01214 (void)mblen(NULL, 0); 01215 #endif 01216 01217 while (format[index]) 01218 { 01219 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 01220 if (! isascii(format[index])) 01221 { 01222 /* 01223 * Multibyte characters cannot be legal specifiers or 01224 * modifiers, so we skip over them. 01225 */ 01226 charlen = mblen(&format[index], MB_LEN_MAX); 01227 index += (charlen > 0) ? charlen : 1; 01228 continue; /* while */ 01229 } 01230 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ 01231 if (CHAR_IDENTIFIER == format[index++]) 01232 { 01233 if (CHAR_IDENTIFIER == format[index]) 01234 { 01235 index++; 01236 continue; /* while */ 01237 } 01238 01239 flags = FLAGS_NEW; 01240 dots = 0; 01241 currentParam = TrioGetPosition(format, &index); 01242 positional = (NO_POSITION != currentParam); 01243 if (!positional) 01244 { 01245 /* We have no positional, get the next counter */ 01246 currentParam = parameterPosition; 01247 } 01248 if(currentParam >= MAX_PARAMETERS) 01249 { 01250 /* Bail out completely to make the error more obvious */ 01251 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index); 01252 } 01253 01254 if (currentParam > maxParam) 01255 maxParam = currentParam; 01256 01257 /* Default values */ 01258 width = NO_WIDTH; 01259 precision = NO_PRECISION; 01260 base = NO_BASE; 01261 varsize = NO_SIZE; 01262 01263 while (TrioIsQualifier(format[index])) 01264 { 01265 ch = format[index++]; 01266 01267 switch (ch) 01268 { 01269 case QUALIFIER_SPACE: 01270 flags |= FLAGS_SPACE; 01271 break; 01272 01273 case QUALIFIER_PLUS: 01274 flags |= FLAGS_SHOWSIGN; 01275 break; 01276 01277 case QUALIFIER_MINUS: 01278 flags |= FLAGS_LEFTADJUST; 01279 flags &= ~FLAGS_NILPADDING; 01280 break; 01281 01282 case QUALIFIER_ALTERNATIVE: 01283 flags |= FLAGS_ALTERNATIVE; 01284 break; 01285 01286 case QUALIFIER_DOT: 01287 if (dots == 0) /* Precision */ 01288 { 01289 dots++; 01290 01291 /* Skip if no precision */ 01292 if (QUALIFIER_DOT == format[index]) 01293 break; 01294 01295 /* After the first dot we have the precision */ 01296 flags |= FLAGS_PRECISION; 01297 if ((QUALIFIER_STAR == format[index]) 01298 #if defined(QUALIFIER_PARAM) 01299 || (QUALIFIER_PARAM == format[index]) 01300 #endif 01301 ) 01302 { 01303 index++; 01304 flags |= FLAGS_PRECISION_PARAMETER; 01305 01306 precision = TrioGetPosition(format, &index); 01307 if (precision == NO_POSITION) 01308 { 01309 parameterPosition++; 01310 if (positional) 01311 precision = parameterPosition; 01312 else 01313 { 01314 precision = currentParam; 01315 currentParam = precision + 1; 01316 } 01317 } 01318 else 01319 { 01320 if (! positional) 01321 currentParam = precision + 1; 01322 if (width > maxParam) 01323 maxParam = precision; 01324 } 01325 if (currentParam > maxParam) 01326 maxParam = currentParam; 01327 } 01328 else 01329 { 01330 precision = trio_to_long(&format[index], 01331 &tmpformat, 01332 BASE_DECIMAL); 01333 index = (int)(tmpformat - format); 01334 } 01335 } 01336 else if (dots == 1) /* Base */ 01337 { 01338 dots++; 01339 01340 /* After the second dot we have the base */ 01341 flags |= FLAGS_BASE; 01342 if ((QUALIFIER_STAR == format[index]) 01343 #if defined(QUALIFIER_PARAM) 01344 || (QUALIFIER_PARAM == format[index]) 01345 #endif 01346 ) 01347 { 01348 index++; 01349 flags |= FLAGS_BASE_PARAMETER; 01350 base = TrioGetPosition(format, &index); 01351 if (base == NO_POSITION) 01352 { 01353 parameterPosition++; 01354 if (positional) 01355 base = parameterPosition; 01356 else 01357 { 01358 base = currentParam; 01359 currentParam = base + 1; 01360 } 01361 } 01362 else 01363 { 01364 if (! positional) 01365 currentParam = base + 1; 01366 if (base > maxParam) 01367 maxParam = base; 01368 } 01369 if (currentParam > maxParam) 01370 maxParam = currentParam; 01371 } 01372 else 01373 { 01374 base = trio_to_long(&format[index], 01375 &tmpformat, 01376 BASE_DECIMAL); 01377 if (base > MAX_BASE) 01378 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01379 index = (int)(tmpformat - format); 01380 } 01381 } 01382 else 01383 { 01384 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01385 } 01386 break; /* QUALIFIER_DOT */ 01387 01388 #if defined(QUALIFIER_PARAM) 01389 case QUALIFIER_PARAM: 01390 type = TYPE_PRINT; 01391 /* FALLTHROUGH */ 01392 #endif 01393 case QUALIFIER_STAR: 01394 /* This has different meanings for print and scan */ 01395 if (TYPE_PRINT == type) 01396 { 01397 /* Read with from parameter */ 01398 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER); 01399 width = TrioGetPosition(format, &index); 01400 if (width == NO_POSITION) 01401 { 01402 parameterPosition++; 01403 if (positional) 01404 width = parameterPosition; 01405 else 01406 { 01407 width = currentParam; 01408 currentParam = width + 1; 01409 } 01410 } 01411 else 01412 { 01413 if (! positional) 01414 currentParam = width + 1; 01415 if (width > maxParam) 01416 maxParam = width; 01417 } 01418 if (currentParam > maxParam) 01419 maxParam = currentParam; 01420 } 01421 else 01422 { 01423 /* Scan, but do not store result */ 01424 flags |= FLAGS_IGNORE; 01425 } 01426 01427 break; /* QUALIFIER_STAR */ 01428 01429 case '0': 01430 if (! (flags & FLAGS_LEFTADJUST)) 01431 flags |= FLAGS_NILPADDING; 01432 /* FALLTHROUGH */ 01433 case '1': case '2': case '3': case '4': 01434 case '5': case '6': case '7': case '8': case '9': 01435 flags |= FLAGS_WIDTH; 01436 /* &format[index - 1] is used to "rewind" the read 01437 * character from format 01438 */ 01439 width = trio_to_long(&format[index - 1], 01440 &tmpformat, 01441 BASE_DECIMAL); 01442 index = (int)(tmpformat - format); 01443 break; 01444 01445 case QUALIFIER_SHORT: 01446 if (flags & FLAGS_SHORTSHORT) 01447 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01448 else if (flags & FLAGS_SHORT) 01449 flags |= FLAGS_SHORTSHORT; 01450 else 01451 flags |= FLAGS_SHORT; 01452 break; 01453 01454 case QUALIFIER_LONG: 01455 if (flags & FLAGS_QUAD) 01456 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01457 else if (flags & FLAGS_LONG) 01458 flags |= FLAGS_QUAD; 01459 else 01460 flags |= FLAGS_LONG; 01461 break; 01462 01463 case QUALIFIER_LONG_UPPER: 01464 flags |= FLAGS_LONGDOUBLE; 01465 break; 01466 01467 #if defined(QUALIFIER_SIZE_T) 01468 case QUALIFIER_SIZE_T: 01469 flags |= FLAGS_SIZE_T; 01470 /* Modify flags for later truncation of number */ 01471 if (sizeof(size_t) == sizeof(trio_ulonglong_t)) 01472 flags |= FLAGS_QUAD; 01473 else if (sizeof(size_t) == sizeof(long)) 01474 flags |= FLAGS_LONG; 01475 break; 01476 #endif 01477 01478 #if defined(QUALIFIER_PTRDIFF_T) 01479 case QUALIFIER_PTRDIFF_T: 01480 flags |= FLAGS_PTRDIFF_T; 01481 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t)) 01482 flags |= FLAGS_QUAD; 01483 else if (sizeof(ptrdiff_t) == sizeof(long)) 01484 flags |= FLAGS_LONG; 01485 break; 01486 #endif 01487 01488 #if defined(QUALIFIER_INTMAX_T) 01489 case QUALIFIER_INTMAX_T: 01490 flags |= FLAGS_INTMAX_T; 01491 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t)) 01492 flags |= FLAGS_QUAD; 01493 else if (sizeof(trio_intmax_t) == sizeof(long)) 01494 flags |= FLAGS_LONG; 01495 break; 01496 #endif 01497 01498 #if defined(QUALIFIER_QUAD) 01499 case QUALIFIER_QUAD: 01500 flags |= FLAGS_QUAD; 01501 break; 01502 #endif 01503 01504 #if defined(QUALIFIER_FIXED_SIZE) 01505 case QUALIFIER_FIXED_SIZE: 01506 if (flags & FLAGS_FIXED_SIZE) 01507 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01508 01509 if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE | 01510 FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER)) 01511 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01512 01513 if ((format[index] == '6') && 01514 (format[index + 1] == '4')) 01515 { 01516 varsize = sizeof(trio_int64_t); 01517 index += 2; 01518 } 01519 else if ((format[index] == '3') && 01520 (format[index + 1] == '2')) 01521 { 01522 varsize = sizeof(trio_int32_t); 01523 index += 2; 01524 } 01525 else if ((format[index] == '1') && 01526 (format[index + 1] == '6')) 01527 { 01528 varsize = sizeof(trio_int16_t); 01529 index += 2; 01530 } 01531 else if (format[index] == '8') 01532 { 01533 varsize = sizeof(trio_int8_t); 01534 index++; 01535 } 01536 else 01537 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01538 01539 flags |= FLAGS_FIXED_SIZE; 01540 break; 01541 #endif 01542 01543 #if defined(QUALIFIER_WIDECHAR) 01544 case QUALIFIER_WIDECHAR: 01545 flags |= FLAGS_WIDECHAR; 01546 break; 01547 #endif 01548 01549 #if defined(QUALIFIER_SIZE_T_UPPER) 01550 case QUALIFIER_SIZE_T_UPPER: 01551 break; 01552 #endif 01553 01554 #if defined(QUALIFIER_QUOTE) 01555 case QUALIFIER_QUOTE: 01556 flags |= FLAGS_QUOTE; 01557 break; 01558 #endif 01559 01560 #if defined(QUALIFIER_STICKY) 01561 case QUALIFIER_STICKY: 01562 flags |= FLAGS_STICKY; 01563 gotSticky = TRUE; 01564 break; 01565 #endif 01566 01567 #if defined(QUALIFIER_VARSIZE) 01568 case QUALIFIER_VARSIZE: 01569 flags |= FLAGS_VARSIZE_PARAMETER; 01570 parameterPosition++; 01571 if (positional) 01572 varsize = parameterPosition; 01573 else 01574 { 01575 varsize = currentParam; 01576 currentParam = varsize + 1; 01577 } 01578 if (currentParam > maxParam) 01579 maxParam = currentParam; 01580 break; 01581 #endif 01582 01583 #if defined(QUALIFIER_ROUNDING_UPPER) 01584 case QUALIFIER_ROUNDING_UPPER: 01585 flags |= FLAGS_ROUNDING; 01586 break; 01587 #endif 01588 01589 default: 01590 /* Bail out completely to make the error more obvious */ 01591 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01592 } 01593 } /* while qualifier */ 01594 01595 /* 01596 * Parameters only need the type and value. The value is 01597 * read later. 01598 */ 01599 if (flags & FLAGS_WIDTH_PARAMETER) 01600 { 01601 usedEntries[width] += 1; 01602 parameters[pos].type = FORMAT_PARAMETER; 01603 parameters[pos].flags = 0; 01604 indices[width] = pos; 01605 width = pos++; 01606 } 01607 if (flags & FLAGS_PRECISION_PARAMETER) 01608 { 01609 usedEntries[precision] += 1; 01610 parameters[pos].type = FORMAT_PARAMETER; 01611 parameters[pos].flags = 0; 01612 indices[precision] = pos; 01613 precision = pos++; 01614 } 01615 if (flags & FLAGS_BASE_PARAMETER) 01616 { 01617 usedEntries[base] += 1; 01618 parameters[pos].type = FORMAT_PARAMETER; 01619 parameters[pos].flags = 0; 01620 indices[base] = pos; 01621 base = pos++; 01622 } 01623 if (flags & FLAGS_VARSIZE_PARAMETER) 01624 { 01625 usedEntries[varsize] += 1; 01626 parameters[pos].type = FORMAT_PARAMETER; 01627 parameters[pos].flags = 0; 01628 indices[varsize] = pos; 01629 varsize = pos++; 01630 } 01631 01632 indices[currentParam] = pos; 01633 01634 switch (format[index++]) 01635 { 01636 #if defined(SPECIFIER_CHAR_UPPER) 01637 case SPECIFIER_CHAR_UPPER: 01638 flags |= FLAGS_WIDECHAR; 01639 /* FALLTHROUGH */ 01640 #endif 01641 case SPECIFIER_CHAR: 01642 if (flags & FLAGS_LONG) 01643 flags |= FLAGS_WIDECHAR; 01644 else if (flags & FLAGS_SHORT) 01645 flags &= ~FLAGS_WIDECHAR; 01646 parameters[pos].type = FORMAT_CHAR; 01647 break; 01648 01649 #if defined(SPECIFIER_STRING_UPPER) 01650 case SPECIFIER_STRING_UPPER: 01651 flags |= FLAGS_WIDECHAR; 01652 /* FALLTHROUGH */ 01653 #endif 01654 case SPECIFIER_STRING: 01655 if (flags & FLAGS_LONG) 01656 flags |= FLAGS_WIDECHAR; 01657 else if (flags & FLAGS_SHORT) 01658 flags &= ~FLAGS_WIDECHAR; 01659 parameters[pos].type = FORMAT_STRING; 01660 break; 01661 01662 case SPECIFIER_GROUP: 01663 if (TYPE_SCAN == type) 01664 { 01665 int depth = 1; 01666 parameters[pos].type = FORMAT_GROUP; 01667 if (format[index] == QUALIFIER_CIRCUMFLEX) 01668 index++; 01669 if (format[index] == SPECIFIER_UNGROUP) 01670 index++; 01671 if (format[index] == QUALIFIER_MINUS) 01672 index++; 01673 /* Skip nested brackets */ 01674 while (format[index] != NIL) 01675 { 01676 if (format[index] == SPECIFIER_GROUP) 01677 { 01678 depth++; 01679 } 01680 else if (format[index] == SPECIFIER_UNGROUP) 01681 { 01682 if (--depth <= 0) 01683 { 01684 index++; 01685 break; 01686 } 01687 } 01688 index++; 01689 } 01690 } 01691 break; 01692 01693 case SPECIFIER_INTEGER: 01694 parameters[pos].type = FORMAT_INT; 01695 break; 01696 01697 case SPECIFIER_UNSIGNED: 01698 flags |= FLAGS_UNSIGNED; 01699 parameters[pos].type = FORMAT_INT; 01700 break; 01701 01702 case SPECIFIER_DECIMAL: 01703 /* Disable base modifier */ 01704 flags &= ~FLAGS_BASE_PARAMETER; 01705 base = BASE_DECIMAL; 01706 parameters[pos].type = FORMAT_INT; 01707 break; 01708 01709 case SPECIFIER_OCTAL: 01710 flags |= FLAGS_UNSIGNED; 01711 flags &= ~FLAGS_BASE_PARAMETER; 01712 base = BASE_OCTAL; 01713 parameters[pos].type = FORMAT_INT; 01714 break; 01715 01716 #if defined(SPECIFIER_BINARY) 01717 case SPECIFIER_BINARY_UPPER: 01718 flags |= FLAGS_UPPER; 01719 /* FALLTHROUGH */ 01720 case SPECIFIER_BINARY: 01721 flags |= FLAGS_NILPADDING; 01722 flags &= ~FLAGS_BASE_PARAMETER; 01723 base = BASE_BINARY; 01724 parameters[pos].type = FORMAT_INT; 01725 break; 01726 #endif 01727 01728 case SPECIFIER_HEX_UPPER: 01729 flags |= FLAGS_UPPER; 01730 /* FALLTHROUGH */ 01731 case SPECIFIER_HEX: 01732 flags |= FLAGS_UNSIGNED; 01733 flags &= ~FLAGS_BASE_PARAMETER; 01734 base = BASE_HEX; 01735 parameters[pos].type = FORMAT_INT; 01736 break; 01737 01738 case SPECIFIER_FLOAT_E_UPPER: 01739 flags |= FLAGS_UPPER; 01740 /* FALLTHROUGH */ 01741 case SPECIFIER_FLOAT_E: 01742 flags |= FLAGS_FLOAT_E; 01743 parameters[pos].type = FORMAT_DOUBLE; 01744 break; 01745 01746 case SPECIFIER_FLOAT_G_UPPER: 01747 flags |= FLAGS_UPPER; 01748 /* FALLTHROUGH */ 01749 case SPECIFIER_FLOAT_G: 01750 flags |= FLAGS_FLOAT_G; 01751 parameters[pos].type = FORMAT_DOUBLE; 01752 break; 01753 01754 case SPECIFIER_FLOAT_F_UPPER: 01755 flags |= FLAGS_UPPER; 01756 /* FALLTHROUGH */ 01757 case SPECIFIER_FLOAT_F: 01758 parameters[pos].type = FORMAT_DOUBLE; 01759 break; 01760 01761 case SPECIFIER_POINTER: 01762 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t)) 01763 flags |= FLAGS_QUAD; 01764 else if (sizeof(trio_pointer_t) == sizeof(long)) 01765 flags |= FLAGS_LONG; 01766 parameters[pos].type = FORMAT_POINTER; 01767 break; 01768 01769 case SPECIFIER_COUNT: 01770 parameters[pos].type = FORMAT_COUNT; 01771 break; 01772 01773 #if defined(SPECIFIER_HEXFLOAT) 01774 # if defined(SPECIFIER_HEXFLOAT_UPPER) 01775 case SPECIFIER_HEXFLOAT_UPPER: 01776 flags |= FLAGS_UPPER; 01777 /* FALLTHROUGH */ 01778 # endif 01779 case SPECIFIER_HEXFLOAT: 01780 base = BASE_HEX; 01781 parameters[pos].type = FORMAT_DOUBLE; 01782 break; 01783 #endif 01784 01785 #if defined(FORMAT_ERRNO) 01786 case SPECIFIER_ERRNO: 01787 parameters[pos].type = FORMAT_ERRNO; 01788 break; 01789 #endif 01790 01791 #if defined(SPECIFIER_USER_DEFINED_BEGIN) 01792 case SPECIFIER_USER_DEFINED_BEGIN: 01793 { 01794 unsigned int max; 01795 int without_namespace = TRUE; 01796 01797 parameters[pos].type = FORMAT_USER_DEFINED; 01798 parameters[pos].user_name[0] = NIL; 01799 tmpformat = (char *)&format[index]; 01800 01801 while ((ch = format[index])) 01802 { 01803 index++; 01804 if (ch == SPECIFIER_USER_DEFINED_END) 01805 { 01806 if (without_namespace) 01807 { 01808 /* We must get the handle first */ 01809 parameters[pos].type = FORMAT_PARAMETER; 01810 parameters[pos].indexAfterSpecifier = index; 01811 parameters[pos].flags = FLAGS_USER_DEFINED; 01812 /* Adjust parameters for insertion of new one */ 01813 pos++; 01814 usedEntries[currentParam] += 1; 01815 parameters[pos].type = FORMAT_USER_DEFINED; 01816 currentParam++; 01817 indices[currentParam] = pos; 01818 if (currentParam > maxParam) 01819 maxParam = currentParam; 01820 } 01821 /* Copy the user data */ 01822 max = (unsigned int)(&format[index] - tmpformat); 01823 if (max > MAX_USER_DATA) 01824 max = MAX_USER_DATA; 01825 trio_copy_max(parameters[pos].user_data, 01826 max, 01827 tmpformat); 01828 break; /* while */ 01829 } 01830 if (ch == SPECIFIER_USER_DEFINED_SEPARATOR) 01831 { 01832 without_namespace = FALSE; 01833 /* Copy the namespace for later looking-up */ 01834 max = (int)(&format[index] - tmpformat); 01835 if (max > MAX_USER_NAME) 01836 max = MAX_USER_NAME; 01837 trio_copy_max(parameters[pos].user_name, 01838 max, 01839 tmpformat); 01840 tmpformat = (char *)&format[index]; 01841 } 01842 } 01843 if (ch != SPECIFIER_USER_DEFINED_END) 01844 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01845 } 01846 break; 01847 #endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */ 01848 01849 default: 01850 /* Bail out completely to make the error more obvious */ 01851 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 01852 } 01853 01854 /* Count the number of times this entry has been used */ 01855 usedEntries[currentParam] += 1; 01856 01857 /* Find last sticky parameters */ 01858 if (gotSticky && !(flags & FLAGS_STICKY)) 01859 { 01860 for (i = pos - 1; i >= 0; i--) 01861 { 01862 if (parameters[i].type == FORMAT_PARAMETER) 01863 continue; 01864 if ((parameters[i].flags & FLAGS_STICKY) && 01865 (parameters[i].type == parameters[pos].type)) 01866 { 01867 /* Do not overwrite current qualifiers */ 01868 flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY); 01869 if (width == NO_WIDTH) 01870 width = parameters[i].width; 01871 if (precision == NO_PRECISION) 01872 precision = parameters[i].precision; 01873 if (base == NO_BASE) 01874 base = parameters[i].base; 01875 break; 01876 } 01877 } 01878 } 01879 01880 parameters[pos].indexAfterSpecifier = index; 01881 parameters[pos].flags = flags; 01882 parameters[pos].width = width; 01883 parameters[pos].precision = precision; 01884 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base; 01885 parameters[pos].varsize = varsize; 01886 pos++; 01887 01888 if (! positional) 01889 parameterPosition++; 01890 01891 } /* if identifier */ 01892 01893 } /* while format characters left */ 01894 01895 for (num = 0; num <= maxParam; num++) 01896 { 01897 if (usedEntries[num] != 1) 01898 { 01899 if (usedEntries[num] == 0) /* gap detected */ 01900 return TRIO_ERROR_RETURN(TRIO_EGAP, num); 01901 else /* double references detected */ 01902 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num); 01903 } 01904 01905 i = indices[num]; 01906 01907 /* 01908 * FORMAT_PARAMETERS are only present if they must be read, 01909 * so it makes no sense to check the ignore flag (besides, 01910 * the flags variable is not set for that particular type) 01911 */ 01912 if ((parameters[i].type != FORMAT_PARAMETER) && 01913 (parameters[i].flags & FLAGS_IGNORE)) 01914 continue; /* for all arguments */ 01915 01916 /* 01917 * The stack arguments are read according to ANSI C89 01918 * default argument promotions: 01919 * 01920 * char = int 01921 * short = int 01922 * unsigned char = unsigned int 01923 * unsigned short = unsigned int 01924 * float = double 01925 * 01926 * In addition to the ANSI C89 these types are read (the 01927 * default argument promotions of C99 has not been 01928 * considered yet) 01929 * 01930 * long long 01931 * long double 01932 * size_t 01933 * ptrdiff_t 01934 * intmax_t 01935 */ 01936 switch (parameters[i].type) 01937 { 01938 case FORMAT_GROUP: 01939 case FORMAT_STRING: 01940 #if TRIO_WIDECHAR 01941 if (flags & FLAGS_WIDECHAR) 01942 { 01943 parameters[i].data.wstring = (argarray == NULL) 01944 ? va_arg(*arglist, trio_wchar_t *) 01945 : (trio_wchar_t *)(argarray[num]); 01946 } 01947 else 01948 #endif 01949 { 01950 parameters[i].data.string = (argarray == NULL) 01951 ? va_arg(*arglist, char *) 01952 : (char *)(argarray[num]); 01953 } 01954 break; 01955 01956 #if defined(FORMAT_USER_DEFINED) 01957 case FORMAT_USER_DEFINED: 01958 #endif 01959 case FORMAT_POINTER: 01960 case FORMAT_COUNT: 01961 case FORMAT_UNKNOWN: 01962 parameters[i].data.pointer = (argarray == NULL) 01963 ? va_arg(*arglist, trio_pointer_t ) 01964 : argarray[num]; 01965 break; 01966 01967 case FORMAT_CHAR: 01968 case FORMAT_INT: 01969 if (TYPE_SCAN == type) 01970 { 01971 if (argarray == NULL) 01972 parameters[i].data.pointer = 01973 (trio_pointer_t)va_arg(*arglist, trio_pointer_t); 01974 else 01975 { 01976 if (parameters[i].type == FORMAT_CHAR) 01977 parameters[i].data.pointer = 01978 (trio_pointer_t)((char *)argarray[num]); 01979 else if (parameters[i].flags & FLAGS_SHORT) 01980 parameters[i].data.pointer = 01981 (trio_pointer_t)((short *)argarray[num]); 01982 else 01983 parameters[i].data.pointer = 01984 (trio_pointer_t)((int *)argarray[num]); 01985 } 01986 } 01987 else 01988 { 01989 #if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE) 01990 if (parameters[i].flags 01991 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE)) 01992 { 01993 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER) 01994 { 01995 /* 01996 * Variable sizes are mapped onto the fixed sizes, in 01997 * accordance with integer promotion. 01998 * 01999 * Please note that this may not be portable, as we 02000 * only guess the size, not the layout of the numbers. 02001 * For example, if int is little-endian, and long is 02002 * big-endian, then this will fail. 02003 */ 02004 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned; 02005 } 02006 else 02007 { 02008 /* Used for the I<bits> modifiers */ 02009 varsize = parameters[i].varsize; 02010 } 02011 parameters[i].flags &= ~FLAGS_ALL_VARSIZES; 02012 02013 if (varsize <= (int)sizeof(int)) 02014 ; 02015 else if (varsize <= (int)sizeof(long)) 02016 parameters[i].flags |= FLAGS_LONG; 02017 #if defined(QUALIFIER_INTMAX_T) 02018 else if (varsize <= (int)sizeof(trio_longlong_t)) 02019 parameters[i].flags |= FLAGS_QUAD; 02020 else 02021 parameters[i].flags |= FLAGS_INTMAX_T; 02022 #else 02023 else 02024 parameters[i].flags |= FLAGS_QUAD; 02025 #endif 02026 } 02027 #endif /* defined(QUALIFIER_VARSIZE) */ 02028 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) 02029 if (parameters[i].flags & FLAGS_SIZE_T) 02030 parameters[i].data.number.as_unsigned = (argarray == NULL) 02031 ? (trio_uintmax_t)va_arg(*arglist, size_t) 02032 : (trio_uintmax_t)(*((size_t *)argarray[num])); 02033 else 02034 #endif 02035 #if defined(QUALIFIER_PTRDIFF_T) 02036 if (parameters[i].flags & FLAGS_PTRDIFF_T) 02037 parameters[i].data.number.as_unsigned = (argarray == NULL) 02038 ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t) 02039 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num])); 02040 else 02041 #endif 02042 #if defined(QUALIFIER_INTMAX_T) 02043 if (parameters[i].flags & FLAGS_INTMAX_T) 02044 parameters[i].data.number.as_unsigned = (argarray == NULL) 02045 ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t) 02046 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num])); 02047 else 02048 #endif 02049 if (parameters[i].flags & FLAGS_QUAD) 02050 parameters[i].data.number.as_unsigned = (argarray == NULL) 02051 ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t) 02052 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num])); 02053 else if (parameters[i].flags & FLAGS_LONG) 02054 parameters[i].data.number.as_unsigned = (argarray == NULL) 02055 ? (trio_uintmax_t)va_arg(*arglist, long) 02056 : (trio_uintmax_t)(*((long *)argarray[num])); 02057 else 02058 { 02059 if (argarray == NULL) 02060 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int); 02061 else 02062 { 02063 if (parameters[i].type == FORMAT_CHAR) 02064 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num])); 02065 else if (parameters[i].flags & FLAGS_SHORT) 02066 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num])); 02067 else 02068 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num])); 02069 } 02070 } 02071 } 02072 break; 02073 02074 case FORMAT_PARAMETER: 02075 /* 02076 * The parameter for the user-defined specifier is a pointer, 02077 * whereas the rest (width, precision, base) uses an integer. 02078 */ 02079 if (parameters[i].flags & FLAGS_USER_DEFINED) 02080 parameters[i].data.pointer = (argarray == NULL) 02081 ? va_arg(*arglist, trio_pointer_t ) 02082 : argarray[num]; 02083 else 02084 parameters[i].data.number.as_unsigned = (argarray == NULL) 02085 ? (trio_uintmax_t)va_arg(*arglist, int) 02086 : (trio_uintmax_t)(*((int *)argarray[num])); 02087 break; 02088 02089 case FORMAT_DOUBLE: 02090 if (TYPE_SCAN == type) 02091 { 02092 if (parameters[i].flags & FLAGS_LONGDOUBLE) 02093 parameters[i].data.longdoublePointer = (argarray == NULL) 02094 ? va_arg(*arglist, trio_long_double_t *) 02095 : (trio_long_double_t *)argarray[num]; 02096 else 02097 { 02098 if (parameters[i].flags & FLAGS_LONG) 02099 parameters[i].data.doublePointer = (argarray == NULL) 02100 ? va_arg(*arglist, double *) 02101 : (double *)argarray[num]; 02102 else 02103 parameters[i].data.doublePointer = (argarray == NULL) 02104 ? (double *)va_arg(*arglist, float *) 02105 : (double *)((float *)argarray[num]); 02106 } 02107 } 02108 else 02109 { 02110 if (parameters[i].flags & FLAGS_LONGDOUBLE) 02111 parameters[i].data.longdoubleNumber = (argarray == NULL) 02112 ? va_arg(*arglist, trio_long_double_t) 02113 : (trio_long_double_t)(*((trio_long_double_t *)argarray[num])); 02114 else 02115 { 02116 if (argarray == NULL) 02117 parameters[i].data.longdoubleNumber = 02118 (trio_long_double_t)va_arg(*arglist, double); 02119 else 02120 { 02121 if (parameters[i].flags & FLAGS_SHORT) 02122 parameters[i].data.longdoubleNumber = 02123 (trio_long_double_t)(*((float *)argarray[num])); 02124 else 02125 parameters[i].data.longdoubleNumber = 02126 (trio_long_double_t)(*((double *)argarray[num])); 02127 } 02128 } 02129 } 02130 break; 02131 02132 #if defined(FORMAT_ERRNO) 02133 case FORMAT_ERRNO: 02134 parameters[i].data.errorNumber = save_errno; 02135 break; 02136 #endif 02137 02138 default: 02139 break; 02140 } 02141 } /* for all specifiers */ 02142 return num; 02143 } 02144 02145 02146 /************************************************************************* 02147 * 02148 * FORMATTING 02149 * 02150 ************************************************************************/ 02151 02152 02153 /************************************************************************* 02154 * TrioWriteNumber 02155 * 02156 * Description: 02157 * Output a number. 02158 * The complexity of this function is a result of the complexity 02159 * of the dependencies of the flags. 02160 */ 02161 TRIO_PRIVATE void 02162 TrioWriteNumber 02163 TRIO_ARGS6((self, number, flags, width, precision, base), 02164 trio_class_t *self, 02165 trio_uintmax_t number, 02166 trio_flags_t flags, 02167 int width, 02168 int precision, 02169 int base) 02170 { 02171 BOOLEAN_T isNegative; 02172 BOOLEAN_T isNumberZero; 02173 BOOLEAN_T isPrecisionZero; 02174 BOOLEAN_T ignoreNumber; 02175 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1]; 02176 char *bufferend; 02177 char *pointer; 02178 TRIO_CONST char *digits; 02179 int i; 02180 int length; 02181 char *p; 02182 int count; 02183 02184 assert(VALID(self)); 02185 assert(VALID(self->OutStream)); 02186 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); 02187 02188 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; 02189 if (base == NO_BASE) 02190 base = BASE_DECIMAL; 02191 02192 isNumberZero = (number == 0); 02193 isPrecisionZero = (precision == 0); 02194 ignoreNumber = (isNumberZero 02195 && isPrecisionZero 02196 && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL))); 02197 02198 if (flags & FLAGS_UNSIGNED) 02199 { 02200 isNegative = FALSE; 02201 flags &= ~FLAGS_SHOWSIGN; 02202 } 02203 else 02204 { 02205 isNegative = ((trio_intmax_t)number < 0); 02206 if (isNegative) 02207 number = -((trio_intmax_t)number); 02208 } 02209 02210 if (flags & FLAGS_QUAD) 02211 number &= (trio_ulonglong_t)-1; 02212 else if (flags & FLAGS_LONG) 02213 number &= (unsigned long)-1; 02214 else 02215 number &= (unsigned int)-1; 02216 02217 /* Build number */ 02218 pointer = bufferend = &buffer[sizeof(buffer) - 1]; 02219 *pointer-- = NIL; 02220 for (i = 1; i < (int)sizeof(buffer); i++) 02221 { 02222 *pointer-- = digits[number % base]; 02223 number /= base; 02224 if (number == 0) 02225 break; 02226 02227 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1)) 02228 { 02229 /* 02230 * We are building the number from the least significant 02231 * to the most significant digit, so we have to copy the 02232 * thousand separator backwards 02233 */ 02234 length = internalThousandSeparatorLength; 02235 if (((int)(pointer - buffer) - length) > 0) 02236 { 02237 p = &internalThousandSeparator[length - 1]; 02238 while (length-- > 0) 02239 *pointer-- = *p--; 02240 } 02241 } 02242 } 02243 02244 if (! ignoreNumber) 02245 { 02246 /* Adjust width */ 02247 width -= (bufferend - pointer) - 1; 02248 } 02249 02250 /* Adjust precision */ 02251 if (NO_PRECISION != precision) 02252 { 02253 precision -= (bufferend - pointer) - 1; 02254 if (precision < 0) 02255 precision = 0; 02256 flags |= FLAGS_NILPADDING; 02257 } 02258 02259 /* Calculate padding */ 02260 count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION))) 02261 ? precision 02262 : 0; 02263 02264 /* Adjust width further */ 02265 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) 02266 width--; 02267 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) 02268 { 02269 switch (base) 02270 { 02271 case BASE_BINARY: 02272 case BASE_HEX: 02273 width -= 2; 02274 break; 02275 case BASE_OCTAL: 02276 if (!(flags & FLAGS_NILPADDING) || (count == 0)) 02277 width--; 02278 break; 02279 default: 02280 break; 02281 } 02282 } 02283 02284 /* Output prefixes spaces if needed */ 02285 if (! ((flags & FLAGS_LEFTADJUST) || 02286 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION)))) 02287 { 02288 while (width-- > count) 02289 self->OutStream(self, CHAR_ADJUST); 02290 } 02291 02292 /* width has been adjusted for signs and alternatives */ 02293 if (isNegative) 02294 self->OutStream(self, '-'); 02295 else if (flags & FLAGS_SHOWSIGN) 02296 self->OutStream(self, '+'); 02297 else if (flags & FLAGS_SPACE) 02298 self->OutStream(self, ' '); 02299 02300 /* Prefix is not written when the value is zero */ 02301 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) 02302 { 02303 switch (base) 02304 { 02305 case BASE_BINARY: 02306 self->OutStream(self, '0'); 02307 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b'); 02308 break; 02309 02310 case BASE_OCTAL: 02311 if (!(flags & FLAGS_NILPADDING) || (count == 0)) 02312 self->OutStream(self, '0'); 02313 break; 02314 02315 case BASE_HEX: 02316 self->OutStream(self, '0'); 02317 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); 02318 break; 02319 02320 default: 02321 break; 02322 } /* switch base */ 02323 } 02324 02325 /* Output prefixed zero padding if needed */ 02326 if (flags & FLAGS_NILPADDING) 02327 { 02328 if (precision == NO_PRECISION) 02329 precision = width; 02330 while (precision-- > 0) 02331 { 02332 self->OutStream(self, '0'); 02333 width--; 02334 } 02335 } 02336 02337 if (! ignoreNumber) 02338 { 02339 /* Output the number itself */ 02340 while (*(++pointer)) 02341 { 02342 self->OutStream(self, *pointer); 02343 } 02344 } 02345 02346 /* Output trailing spaces if needed */ 02347 if (flags & FLAGS_LEFTADJUST) 02348 { 02349 while (width-- > 0) 02350 self->OutStream(self, CHAR_ADJUST); 02351 } 02352 } 02353 02354 /************************************************************************* 02355 * TrioWriteStringCharacter 02356 * 02357 * Description: 02358 * Output a single character of a string 02359 */ 02360 TRIO_PRIVATE void 02361 TrioWriteStringCharacter 02362 TRIO_ARGS3((self, ch, flags), 02363 trio_class_t *self, 02364 int ch, 02365 trio_flags_t flags) 02366 { 02367 if (flags & FLAGS_ALTERNATIVE) 02368 { 02369 if (! isprint(ch)) 02370 { 02371 /* 02372 * Non-printable characters are converted to C escapes or 02373 * \number, if no C escape exists. 02374 */ 02375 self->OutStream(self, CHAR_BACKSLASH); 02376 switch (ch) 02377 { 02378 case '\007': self->OutStream(self, 'a'); break; 02379 case '\b': self->OutStream(self, 'b'); break; 02380 case '\f': self->OutStream(self, 'f'); break; 02381 case '\n': self->OutStream(self, 'n'); break; 02382 case '\r': self->OutStream(self, 'r'); break; 02383 case '\t': self->OutStream(self, 't'); break; 02384 case '\v': self->OutStream(self, 'v'); break; 02385 case '\\': self->OutStream(self, '\\'); break; 02386 default: 02387 self->OutStream(self, 'x'); 02388 TrioWriteNumber(self, (trio_uintmax_t)ch, 02389 FLAGS_UNSIGNED | FLAGS_NILPADDING, 02390 2, 2, BASE_HEX); 02391 break; 02392 } 02393 } 02394 else if (ch == CHAR_BACKSLASH) 02395 { 02396 self->OutStream(self, CHAR_BACKSLASH); 02397 self->OutStream(self, CHAR_BACKSLASH); 02398 } 02399 else 02400 { 02401 self->OutStream(self, ch); 02402 } 02403 } 02404 else 02405 { 02406 self->OutStream(self, ch); 02407 } 02408 } 02409 02410 /************************************************************************* 02411 * TrioWriteString 02412 * 02413 * Description: 02414 * Output a string 02415 */ 02416 TRIO_PRIVATE void 02417 TrioWriteString 02418 TRIO_ARGS5((self, string, flags, width, precision), 02419 trio_class_t *self, 02420 TRIO_CONST char *string, 02421 trio_flags_t flags, 02422 int width, 02423 int precision) 02424 { 02425 int length; 02426 int ch; 02427 02428 assert(VALID(self)); 02429 assert(VALID(self->OutStream)); 02430 02431 if (string == NULL) 02432 { 02433 string = internalNullString; 02434 length = sizeof(internalNullString) - 1; 02435 /* Disable quoting for the null pointer */ 02436 flags &= (~FLAGS_QUOTE); 02437 width = 0; 02438 } 02439 else 02440 { 02441 length = trio_length(string); 02442 } 02443 if ((NO_PRECISION != precision) && 02444 (precision < length)) 02445 { 02446 length = precision; 02447 } 02448 width -= length; 02449 02450 if (flags & FLAGS_QUOTE) 02451 self->OutStream(self, CHAR_QUOTE); 02452 02453 if (! (flags & FLAGS_LEFTADJUST)) 02454 { 02455 while (width-- > 0) 02456 self->OutStream(self, CHAR_ADJUST); 02457 } 02458 02459 while (length-- > 0) 02460 { 02461 /* The ctype parameters must be an unsigned char (or EOF) */ 02462 ch = (int)((unsigned char)(*string++)); 02463 TrioWriteStringCharacter(self, ch, flags); 02464 } 02465 02466 if (flags & FLAGS_LEFTADJUST) 02467 { 02468 while (width-- > 0) 02469 self->OutStream(self, CHAR_ADJUST); 02470 } 02471 if (flags & FLAGS_QUOTE) 02472 self->OutStream(self, CHAR_QUOTE); 02473 } 02474 02475 /************************************************************************* 02476 * TrioWriteWideStringCharacter 02477 * 02478 * Description: 02479 * Output a wide string as a multi-byte sequence 02480 */ 02481 #if TRIO_WIDECHAR 02482 TRIO_PRIVATE int 02483 TrioWriteWideStringCharacter 02484 TRIO_ARGS4((self, wch, flags, width), 02485 trio_class_t *self, 02486 trio_wchar_t wch, 02487 trio_flags_t flags, 02488 int width) 02489 { 02490 int size; 02491 int i; 02492 int ch; 02493 char *string; 02494 char buffer[MB_LEN_MAX + 1]; 02495 02496 if (width == NO_WIDTH) 02497 width = sizeof(buffer); 02498 02499 size = wctomb(buffer, wch); 02500 if ((size <= 0) || (size > width) || (buffer[0] == NIL)) 02501 return 0; 02502 02503 string = buffer; 02504 i = size; 02505 while ((width >= i) && (width-- > 0) && (i-- > 0)) 02506 { 02507 /* The ctype parameters must be an unsigned char (or EOF) */ 02508 ch = (int)((unsigned char)(*string++)); 02509 TrioWriteStringCharacter(self, ch, flags); 02510 } 02511 return size; 02512 } 02513 #endif /* TRIO_WIDECHAR */ 02514 02515 /************************************************************************* 02516 * TrioWriteWideString 02517 * 02518 * Description: 02519 * Output a wide character string as a multi-byte string 02520 */ 02521 #if TRIO_WIDECHAR 02522 TRIO_PRIVATE void 02523 TrioWriteWideString 02524 TRIO_ARGS5((self, wstring, flags, width, precision), 02525 trio_class_t *self, 02526 TRIO_CONST trio_wchar_t *wstring, 02527 trio_flags_t flags, 02528 int width, 02529 int precision) 02530 { 02531 int length; 02532 int size; 02533 02534 assert(VALID(self)); 02535 assert(VALID(self->OutStream)); 02536 02537 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 02538 (void)mblen(NULL, 0); 02539 #endif 02540 02541 if (wstring == NULL) 02542 { 02543 TrioWriteString(self, NULL, flags, width, precision); 02544 return; 02545 } 02546 02547 if (NO_PRECISION == precision) 02548 { 02549 length = INT_MAX; 02550 } 02551 else 02552 { 02553 length = precision; 02554 width -= length; 02555 } 02556 02557 if (flags & FLAGS_QUOTE) 02558 self->OutStream(self, CHAR_QUOTE); 02559 02560 if (! (flags & FLAGS_LEFTADJUST)) 02561 { 02562 while (width-- > 0) 02563 self->OutStream(self, CHAR_ADJUST); 02564 } 02565 02566 while (length > 0) 02567 { 02568 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length); 02569 if (size == 0) 02570 break; /* while */ 02571 length -= size; 02572 } 02573 02574 if (flags & FLAGS_LEFTADJUST) 02575 { 02576 while (width-- > 0) 02577 self->OutStream(self, CHAR_ADJUST); 02578 } 02579 if (flags & FLAGS_QUOTE) 02580 self->OutStream(self, CHAR_QUOTE); 02581 } 02582 #endif /* TRIO_WIDECHAR */ 02583 02584 /************************************************************************* 02585 * TrioWriteDouble 02586 * 02587 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm 02588 * 02589 * "5.2.4.2.2 paragraph #4 02590 * 02591 * The accuracy [...] is implementation defined, as is the accuracy 02592 * of the conversion between floating-point internal representations 02593 * and string representations performed by the libray routine in 02594 * <stdio.h>" 02595 */ 02596 /* FIXME: handle all instances of constant long-double number (L) 02597 * and *l() math functions. 02598 */ 02599 TRIO_PRIVATE void 02600 TrioWriteDouble 02601 TRIO_ARGS6((self, number, flags, width, precision, base), 02602 trio_class_t *self, 02603 trio_long_double_t number, 02604 trio_flags_t flags, 02605 int width, 02606 int precision, 02607 int base) 02608 { 02609 trio_long_double_t integerNumber; 02610 trio_long_double_t fractionNumber; 02611 trio_long_double_t workNumber; 02612 int integerDigits; 02613 int fractionDigits; 02614 int exponentDigits; 02615 int baseDigits; 02616 int integerThreshold; 02617 int fractionThreshold; 02618 int expectedWidth; 02619 int exponent = 0; 02620 unsigned int uExponent = 0; 02621 int exponentBase; 02622 trio_long_double_t dblBase; 02623 trio_long_double_t dblIntegerBase; 02624 trio_long_double_t dblFractionBase; 02625 trio_long_double_t integerAdjust; 02626 trio_long_double_t fractionAdjust; 02627 BOOLEAN_T isNegative; 02628 BOOLEAN_T isExponentNegative = FALSE; 02629 BOOLEAN_T requireTwoDigitExponent; 02630 BOOLEAN_T isHex; 02631 TRIO_CONST char *digits; 02632 char *groupingPointer; 02633 int i; 02634 int index; 02635 BOOLEAN_T hasOnlyZeroes; 02636 int zeroes = 0; 02637 register int trailingZeroes; 02638 BOOLEAN_T keepTrailingZeroes; 02639 BOOLEAN_T keepDecimalPoint; 02640 trio_long_double_t epsilon; 02641 02642 assert(VALID(self)); 02643 assert(VALID(self->OutStream)); 02644 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); 02645 02646 /* Determine sign and look for special quantities */ 02647 switch (trio_fpclassify_and_signbit(number, &isNegative)) 02648 { 02649 case TRIO_FP_NAN: 02650 TrioWriteString(self, 02651 (flags & FLAGS_UPPER) 02652 ? NAN_UPPER 02653 : NAN_LOWER, 02654 flags, width, precision); 02655 return; 02656 02657 case TRIO_FP_INFINITE: 02658 if (isNegative) 02659 { 02660 /* Negative infinity */ 02661 TrioWriteString(self, 02662 (flags & FLAGS_UPPER) 02663 ? "-" INFINITE_UPPER 02664 : "-" INFINITE_LOWER, 02665 flags, width, precision); 02666 return; 02667 } 02668 else 02669 { 02670 /* Positive infinity */ 02671 TrioWriteString(self, 02672 (flags & FLAGS_UPPER) 02673 ? INFINITE_UPPER 02674 : INFINITE_LOWER, 02675 flags, width, precision); 02676 return; 02677 } 02678 02679 default: 02680 /* Finitude */ 02681 break; 02682 } 02683 02684 /* Normal numbers */ 02685 if (flags & FLAGS_LONGDOUBLE) 02686 { 02687 baseDigits = (base == 10) 02688 ? LDBL_DIG 02689 : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base)); 02690 epsilon = LDBL_EPSILON; 02691 } 02692 else if (flags & FLAGS_SHORT) 02693 { 02694 baseDigits = (base == BASE_DECIMAL) 02695 ? FLT_DIG 02696 : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base)); 02697 epsilon = FLT_EPSILON; 02698 } 02699 else 02700 { 02701 baseDigits = (base == BASE_DECIMAL) 02702 ? DBL_DIG 02703 : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base)); 02704 epsilon = DBL_EPSILON; 02705 } 02706 02707 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; 02708 isHex = (base == BASE_HEX); 02709 if (base == NO_BASE) 02710 base = BASE_DECIMAL; 02711 dblBase = (trio_long_double_t)base; 02712 keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) || 02713 ( (flags & FLAGS_FLOAT_G) && 02714 !(flags & FLAGS_ALTERNATIVE) ) ); 02715 02716 if (flags & FLAGS_ROUNDING) 02717 precision = baseDigits; 02718 02719 if (precision == NO_PRECISION) 02720 { 02721 if (isHex) 02722 { 02723 keepTrailingZeroes = FALSE; 02724 precision = FLT_MANT_DIG; 02725 } 02726 else 02727 { 02728 precision = FLT_DIG; 02729 } 02730 } 02731 02732 if (isNegative) 02733 number = -number; 02734 02735 if (isHex) 02736 flags |= FLAGS_FLOAT_E; 02737 02738 if (flags & FLAGS_FLOAT_G) 02739 { 02740 if (precision == 0) 02741 precision = 1; 02742 02743 if ((number < 1.0E-4) || (number > powl(base, 02744 (trio_long_double_t)precision))) 02745 { 02746 /* Use scientific notation */ 02747 flags |= FLAGS_FLOAT_E; 02748 } 02749 else if (number < 1.0) 02750 { 02751 /* 02752 * Use normal notation. If the integer part of the number is 02753 * zero, then adjust the precision to include leading fractional 02754 * zeros. 02755 */ 02756 workNumber = TrioLogarithm(number, base); 02757 workNumber = TRIO_FABS(workNumber); 02758 if (workNumber - floorl(workNumber) < 0.001) 02759 workNumber--; 02760 zeroes = (int)floorl(workNumber); 02761 } 02762 } 02763 02764 if (flags & FLAGS_FLOAT_E) 02765 { 02766 /* Scale the number */ 02767 workNumber = TrioLogarithm(number, base); 02768 if (trio_isinf(workNumber) == -1) 02769 { 02770 exponent = 0; 02771 /* Undo setting */ 02772 if (flags & FLAGS_FLOAT_G) 02773 flags &= ~FLAGS_FLOAT_E; 02774 } 02775 else 02776 { 02777 exponent = (int)floorl(workNumber); 02778 number /= powl(dblBase, (trio_long_double_t)exponent); 02779 isExponentNegative = (exponent < 0); 02780 uExponent = (isExponentNegative) ? -exponent : exponent; 02781 if (isHex) 02782 uExponent *= 4; /* log16(2) */ 02783 /* No thousand separators */ 02784 flags &= ~FLAGS_QUOTE; 02785 } 02786 } 02787 02788 integerNumber = floorl(number); 02789 fractionNumber = number - integerNumber; 02790 02791 /* 02792 * Truncated number. 02793 * 02794 * Precision is number of significant digits for FLOAT_G 02795 * and number of fractional digits for others. 02796 */ 02797 integerDigits = (integerNumber > epsilon) 02798 ? 1 + (int)TrioLogarithm(integerNumber, base) 02799 : 1; 02800 fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0)) 02801 ? precision - integerDigits 02802 : zeroes + precision; 02803 02804 dblFractionBase = TrioPower(base, fractionDigits); 02805 02806 workNumber = number + 0.5 / dblFractionBase; 02807 if (floorl(number) != floorl(workNumber)) 02808 { 02809 if (flags & FLAGS_FLOAT_E) 02810 { 02811 /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */ 02812 exponent++; 02813 isExponentNegative = (exponent < 0); 02814 uExponent = (isExponentNegative) ? -exponent : exponent; 02815 if (isHex) 02816 uExponent *= 4; /* log16(2) */ 02817 workNumber = (number + 0.5 / dblFractionBase) / dblBase; 02818 integerNumber = floorl(workNumber); 02819 fractionNumber = workNumber - integerNumber; 02820 } 02821 else 02822 { 02823 /* Adjust if number was rounded up one digit (ie. 99 to 100) */ 02824 integerNumber = floorl(number + 0.5); 02825 fractionNumber = 0.0; 02826 integerDigits = (integerNumber > epsilon) 02827 ? 1 + (int)TrioLogarithm(integerNumber, base) 02828 : 1; 02829 } 02830 } 02831 02832 /* Estimate accuracy */ 02833 integerAdjust = fractionAdjust = 0.5; 02834 if (flags & FLAGS_ROUNDING) 02835 { 02836 if (integerDigits > baseDigits) 02837 { 02838 integerThreshold = baseDigits; 02839 fractionDigits = 0; 02840 dblFractionBase = 1.0; 02841 fractionThreshold = 0; 02842 precision = 0; /* Disable decimal-point */ 02843 integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1); 02844 fractionAdjust = 0.0; 02845 } 02846 else 02847 { 02848 integerThreshold = integerDigits; 02849 fractionThreshold = fractionDigits - integerThreshold; 02850 fractionAdjust = 1.0; 02851 } 02852 } 02853 else 02854 { 02855 integerThreshold = INT_MAX; 02856 fractionThreshold = INT_MAX; 02857 } 02858 02859 /* 02860 * Calculate expected width. 02861 * sign + integer part + thousands separators + decimal point 02862 * + fraction + exponent 02863 */ 02864 fractionAdjust /= dblFractionBase; 02865 hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon); 02866 keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) || 02867 !((precision == 0) || 02868 (!keepTrailingZeroes && hasOnlyZeroes)) ); 02869 if (flags & FLAGS_FLOAT_E) 02870 { 02871 exponentDigits = (uExponent == 0) 02872 ? 1 02873 : (int)ceil(TrioLogarithm((double)(uExponent + 1), 02874 (isHex) ? 10.0 : base)); 02875 } 02876 else 02877 exponentDigits = 0; 02878 requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1)); 02879 02880 expectedWidth = integerDigits + fractionDigits 02881 + (keepDecimalPoint 02882 ? internalDecimalPointLength 02883 : 0) 02884 + ((flags & FLAGS_QUOTE) 02885 ? TrioCalcThousandSeparatorLength(integerDigits) 02886 : 0); 02887 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) 02888 expectedWidth += sizeof("-") - 1; 02889 if (exponentDigits > 0) 02890 expectedWidth += exponentDigits + 02891 ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1); 02892 if (isHex) 02893 expectedWidth += sizeof("0X") - 1; 02894 02895 /* Output prefixing */ 02896 if (flags & FLAGS_NILPADDING) 02897 { 02898 /* Leading zeros must be after sign */ 02899 if (isNegative) 02900 self->OutStream(self, '-'); 02901 else if (flags & FLAGS_SHOWSIGN) 02902 self->OutStream(self, '+'); 02903 else if (flags & FLAGS_SPACE) 02904 self->OutStream(self, ' '); 02905 if (isHex) 02906 { 02907 self->OutStream(self, '0'); 02908 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); 02909 } 02910 if (!(flags & FLAGS_LEFTADJUST)) 02911 { 02912 for (i = expectedWidth; i < width; i++) 02913 { 02914 self->OutStream(self, '0'); 02915 } 02916 } 02917 } 02918 else 02919 { 02920 /* Leading spaces must be before sign */ 02921 if (!(flags & FLAGS_LEFTADJUST)) 02922 { 02923 for (i = expectedWidth; i < width; i++) 02924 { 02925 self->OutStream(self, CHAR_ADJUST); 02926 } 02927 } 02928 if (isNegative) 02929 self->OutStream(self, '-'); 02930 else if (flags & FLAGS_SHOWSIGN) 02931 self->OutStream(self, '+'); 02932 else if (flags & FLAGS_SPACE) 02933 self->OutStream(self, ' '); 02934 if (isHex) 02935 { 02936 self->OutStream(self, '0'); 02937 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); 02938 } 02939 } 02940 02941 /* Output the integer part and thousand separators */ 02942 dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1); 02943 for (i = 0; i < integerDigits; i++) 02944 { 02945 workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase)); 02946 if (i > integerThreshold) 02947 { 02948 /* Beyond accuracy */ 02949 self->OutStream(self, digits[0]); 02950 } 02951 else 02952 { 02953 self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]); 02954 } 02955 dblIntegerBase *= dblBase; 02956 02957 if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE) 02958 && TrioFollowedBySeparator(integerDigits - i)) 02959 { 02960 for (groupingPointer = internalThousandSeparator; 02961 *groupingPointer != NIL; 02962 groupingPointer++) 02963 { 02964 self->OutStream(self, *groupingPointer); 02965 } 02966 } 02967 } 02968 02969 /* Insert decimal point and build the fraction part */ 02970 trailingZeroes = 0; 02971 02972 if (keepDecimalPoint) 02973 { 02974 if (internalDecimalPoint) 02975 { 02976 self->OutStream(self, internalDecimalPoint); 02977 } 02978 else 02979 { 02980 for (i = 0; i < internalDecimalPointLength; i++) 02981 { 02982 self->OutStream(self, internalDecimalPointString[i]); 02983 } 02984 } 02985 } 02986 02987 for (i = 0; i < fractionDigits; i++) 02988 { 02989 if ((integerDigits > integerThreshold) || (i > fractionThreshold)) 02990 { 02991 /* Beyond accuracy */ 02992 trailingZeroes++; 02993 } 02994 else 02995 { 02996 fractionNumber *= dblBase; 02997 fractionAdjust *= dblBase; 02998 workNumber = floorl(fractionNumber + fractionAdjust); 02999 fractionNumber -= workNumber; 03000 index = (int)fmodl(workNumber, dblBase); 03001 if (index == 0) 03002 { 03003 trailingZeroes++; 03004 } 03005 else 03006 { 03007 while (trailingZeroes > 0) 03008 { 03009 /* Not trailing zeroes after all */ 03010 self->OutStream(self, digits[0]); 03011 trailingZeroes--; 03012 } 03013 self->OutStream(self, digits[index]); 03014 } 03015 } 03016 } 03017 03018 if (keepTrailingZeroes) 03019 { 03020 while (trailingZeroes > 0) 03021 { 03022 self->OutStream(self, digits[0]); 03023 trailingZeroes--; 03024 } 03025 } 03026 03027 /* Output exponent */ 03028 if (exponentDigits > 0) 03029 { 03030 self->OutStream(self, 03031 isHex 03032 ? ((flags & FLAGS_UPPER) ? 'P' : 'p') 03033 : ((flags & FLAGS_UPPER) ? 'E' : 'e')); 03034 self->OutStream(self, (isExponentNegative) ? '-' : '+'); 03035 03036 /* The exponent must contain at least two digits */ 03037 if (requireTwoDigitExponent) 03038 self->OutStream(self, '0'); 03039 03040 if (isHex) 03041 base = 10.0; 03042 exponentBase = (int)TrioPower(base, exponentDigits - 1); 03043 for (i = 0; i < exponentDigits; i++) 03044 { 03045 self->OutStream(self, digits[(uExponent / exponentBase) % base]); 03046 exponentBase /= base; 03047 } 03048 } 03049 /* Output trailing spaces */ 03050 if (flags & FLAGS_LEFTADJUST) 03051 { 03052 for (i = expectedWidth; i < width; i++) 03053 { 03054 self->OutStream(self, CHAR_ADJUST); 03055 } 03056 } 03057 } 03058 03059 /************************************************************************* 03060 * TrioFormatProcess 03061 * 03062 * Description: 03063 * This is the main engine for formatting output 03064 */ 03065 TRIO_PRIVATE int 03066 TrioFormatProcess 03067 TRIO_ARGS3((data, format, parameters), 03068 trio_class_t *data, 03069 TRIO_CONST char *format, 03070 trio_parameter_t *parameters) 03071 { 03072 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 03073 int charlen; 03074 #endif 03075 int i; 03076 TRIO_CONST char *string; 03077 trio_pointer_t pointer; 03078 trio_flags_t flags; 03079 int width; 03080 int precision; 03081 int base; 03082 int index; 03083 03084 index = 0; 03085 i = 0; 03086 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 03087 (void)mblen(NULL, 0); 03088 #endif 03089 03090 while (format[index]) 03091 { 03092 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 03093 if (! isascii(format[index])) 03094 { 03095 charlen = mblen(&format[index], MB_LEN_MAX); 03096 /* 03097 * Only valid multibyte characters are handled here. Invalid 03098 * multibyte characters (charlen == -1) are handled as normal 03099 * characters. 03100 */ 03101 if (charlen != -1) 03102 { 03103 while (charlen-- > 0) 03104 { 03105 data->OutStream(data, format[index++]); 03106 } 03107 continue; /* while characters left in formatting string */ 03108 } 03109 } 03110 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ 03111 if (CHAR_IDENTIFIER == format[index]) 03112 { 03113 if (CHAR_IDENTIFIER == format[index + 1]) 03114 { 03115 data->OutStream(data, CHAR_IDENTIFIER); 03116 index += 2; 03117 } 03118 else 03119 { 03120 /* Skip the parameter entries */ 03121 while (parameters[i].type == FORMAT_PARAMETER) 03122 i++; 03123 03124 flags = parameters[i].flags; 03125 03126 /* Find width */ 03127 width = parameters[i].width; 03128 if (flags & FLAGS_WIDTH_PARAMETER) 03129 { 03130 /* Get width from parameter list */ 03131 width = (int)parameters[width].data.number.as_signed; 03132 if (width < 0) 03133 { 03134 /* 03135 * A negative width is the same as the - flag and 03136 * a positive width. 03137 */ 03138 flags |= FLAGS_LEFTADJUST; 03139 flags &= ~FLAGS_NILPADDING; 03140 width = -width; 03141 } 03142 } 03143 03144 /* Find precision */ 03145 if (flags & FLAGS_PRECISION) 03146 { 03147 precision = parameters[i].precision; 03148 if (flags & FLAGS_PRECISION_PARAMETER) 03149 { 03150 /* Get precision from parameter list */ 03151 precision = (int)parameters[precision].data.number.as_signed; 03152 if (precision < 0) 03153 { 03154 /* 03155 * A negative precision is the same as no 03156 * precision 03157 */ 03158 precision = NO_PRECISION; 03159 } 03160 } 03161 } 03162 else 03163 { 03164 precision = NO_PRECISION; 03165 } 03166 03167 /* Find base */ 03168 base = parameters[i].base; 03169 if (flags & FLAGS_BASE_PARAMETER) 03170 { 03171 /* Get base from parameter list */ 03172 base = (int)parameters[base].data.number.as_signed; 03173 } 03174 03175 switch (parameters[i].type) 03176 { 03177 case FORMAT_CHAR: 03178 if (flags & FLAGS_QUOTE) 03179 data->OutStream(data, CHAR_QUOTE); 03180 if (! (flags & FLAGS_LEFTADJUST)) 03181 { 03182 while (--width > 0) 03183 data->OutStream(data, CHAR_ADJUST); 03184 } 03185 #if TRIO_WIDECHAR 03186 if (flags & FLAGS_WIDECHAR) 03187 { 03188 TrioWriteWideStringCharacter(data, 03189 (trio_wchar_t)parameters[i].data.number.as_signed, 03190 flags, 03191 NO_WIDTH); 03192 } 03193 else 03194 #endif 03195 { 03196 TrioWriteStringCharacter(data, 03197 (int)parameters[i].data.number.as_signed, 03198 flags); 03199 } 03200 03201 if (flags & FLAGS_LEFTADJUST) 03202 { 03203 while(--width > 0) 03204 data->OutStream(data, CHAR_ADJUST); 03205 } 03206 if (flags & FLAGS_QUOTE) 03207 data->OutStream(data, CHAR_QUOTE); 03208 03209 break; /* FORMAT_CHAR */ 03210 03211 case FORMAT_INT: 03212 TrioWriteNumber(data, 03213 parameters[i].data.number.as_unsigned, 03214 flags, 03215 width, 03216 precision, 03217 base); 03218 03219 break; /* FORMAT_INT */ 03220 03221 case FORMAT_DOUBLE: 03222 TrioWriteDouble(data, 03223 parameters[i].data.longdoubleNumber, 03224 flags, 03225 width, 03226 precision, 03227 base); 03228 break; /* FORMAT_DOUBLE */ 03229 03230 case FORMAT_STRING: 03231 #if TRIO_WIDECHAR 03232 if (flags & FLAGS_WIDECHAR) 03233 { 03234 TrioWriteWideString(data, 03235 parameters[i].data.wstring, 03236 flags, 03237 width, 03238 precision); 03239 } 03240 else 03241 #endif 03242 { 03243 TrioWriteString(data, 03244 parameters[i].data.string, 03245 flags, 03246 width, 03247 precision); 03248 } 03249 break; /* FORMAT_STRING */ 03250 03251 case FORMAT_POINTER: 03252 { 03253 trio_reference_t reference; 03254 03255 reference.data = data; 03256 reference.parameter = ¶meters[i]; 03257 trio_print_pointer(&reference, parameters[i].data.pointer); 03258 } 03259 break; /* FORMAT_POINTER */ 03260 03261 case FORMAT_COUNT: 03262 pointer = parameters[i].data.pointer; 03263 if (NULL != pointer) 03264 { 03265 /* 03266 * C99 paragraph 7.19.6.1.8 says "the number of 03267 * characters written to the output stream so far by 03268 * this call", which is data->committed 03269 */ 03270 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) 03271 if (flags & FLAGS_SIZE_T) 03272 *(size_t *)pointer = (size_t)data->committed; 03273 else 03274 #endif 03275 #if defined(QUALIFIER_PTRDIFF_T) 03276 if (flags & FLAGS_PTRDIFF_T) 03277 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed; 03278 else 03279 #endif 03280 #if defined(QUALIFIER_INTMAX_T) 03281 if (flags & FLAGS_INTMAX_T) 03282 *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed; 03283 else 03284 #endif 03285 if (flags & FLAGS_QUAD) 03286 { 03287 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed; 03288 } 03289 else if (flags & FLAGS_LONG) 03290 { 03291 *(long int *)pointer = (long int)data->committed; 03292 } 03293 else if (flags & FLAGS_SHORT) 03294 { 03295 *(short int *)pointer = (short int)data->committed; 03296 } 03297 else 03298 { 03299 *(int *)pointer = (int)data->committed; 03300 } 03301 } 03302 break; /* FORMAT_COUNT */ 03303 03304 case FORMAT_PARAMETER: 03305 break; /* FORMAT_PARAMETER */ 03306 03307 #if defined(FORMAT_ERRNO) 03308 case FORMAT_ERRNO: 03309 string = trio_error(parameters[i].data.errorNumber); 03310 if (string) 03311 { 03312 TrioWriteString(data, 03313 string, 03314 flags, 03315 width, 03316 precision); 03317 } 03318 else 03319 { 03320 data->OutStream(data, '#'); 03321 TrioWriteNumber(data, 03322 (trio_uintmax_t)parameters[i].data.errorNumber, 03323 flags, 03324 width, 03325 precision, 03326 BASE_DECIMAL); 03327 } 03328 break; /* FORMAT_ERRNO */ 03329 #endif /* defined(FORMAT_ERRNO) */ 03330 03331 #if defined(FORMAT_USER_DEFINED) 03332 case FORMAT_USER_DEFINED: 03333 { 03334 trio_reference_t reference; 03335 trio_userdef_t *def = NULL; 03336 03337 if (parameters[i].user_name[0] == NIL) 03338 { 03339 /* Use handle */ 03340 if ((i > 0) || 03341 (parameters[i - 1].type == FORMAT_PARAMETER)) 03342 def = (trio_userdef_t *)parameters[i - 1].data.pointer; 03343 } 03344 else 03345 { 03346 /* Look up namespace */ 03347 def = TrioFindNamespace(parameters[i].user_name, NULL); 03348 } 03349 if (def) { 03350 reference.data = data; 03351 reference.parameter = ¶meters[i]; 03352 def->callback(&reference); 03353 } 03354 } 03355 break; 03356 #endif /* defined(FORMAT_USER_DEFINED) */ 03357 03358 default: 03359 break; 03360 } /* switch parameter type */ 03361 03362 /* Prepare for next */ 03363 index = parameters[i].indexAfterSpecifier; 03364 i++; 03365 } 03366 } 03367 else /* not identifier */ 03368 { 03369 data->OutStream(data, format[index++]); 03370 } 03371 } 03372 return data->processed; 03373 } 03374 03375 /************************************************************************* 03376 * TrioFormatRef 03377 */ 03378 TRIO_PRIVATE int 03379 TrioFormatRef 03380 TRIO_ARGS4((reference, format, arglist, argarray), 03381 trio_reference_t *reference, 03382 TRIO_CONST char *format, 03383 va_list *arglist, 03384 trio_pointer_t *argarray) 03385 { 03386 int status; 03387 trio_parameter_t parameters[MAX_PARAMETERS]; 03388 03389 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); 03390 if (status < 0) 03391 return status; 03392 03393 status = TrioFormatProcess(reference->data, format, parameters); 03394 if (reference->data->error != 0) 03395 { 03396 status = reference->data->error; 03397 } 03398 return status; 03399 } 03400 03401 /************************************************************************* 03402 * TrioFormat 03403 */ 03404 TRIO_PRIVATE int 03405 TrioFormat 03406 TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray), 03407 trio_pointer_t destination, 03408 size_t destinationSize, 03409 void (*OutStream) TRIO_PROTO((trio_class_t *, int)), 03410 TRIO_CONST char *format, 03411 va_list *arglist, 03412 trio_pointer_t *argarray) 03413 { 03414 int status; 03415 trio_class_t data; 03416 trio_parameter_t parameters[MAX_PARAMETERS]; 03417 03418 assert(VALID(OutStream)); 03419 assert(VALID(format)); 03420 03421 memset(&data, 0, sizeof(data)); 03422 data.OutStream = OutStream; 03423 data.location = destination; 03424 data.max = destinationSize; 03425 data.error = 0; 03426 03427 #if defined(USE_LOCALE) 03428 if (NULL == internalLocaleValues) 03429 { 03430 TrioSetLocale(); 03431 } 03432 #endif 03433 03434 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); 03435 if (status < 0) 03436 return status; 03437 03438 status = TrioFormatProcess(&data, format, parameters); 03439 if (data.error != 0) 03440 { 03441 status = data.error; 03442 } 03443 return status; 03444 } 03445 03446 /************************************************************************* 03447 * TrioOutStreamFile 03448 */ 03449 TRIO_PRIVATE void 03450 TrioOutStreamFile 03451 TRIO_ARGS2((self, output), 03452 trio_class_t *self, 03453 int output) 03454 { 03455 FILE *file; 03456 03457 assert(VALID(self)); 03458 assert(VALID(self->location)); 03459 03460 file = (FILE *)self->location; 03461 self->processed++; 03462 if (fputc(output, file) == EOF) 03463 { 03464 self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0); 03465 } 03466 else 03467 { 03468 self->committed++; 03469 } 03470 } 03471 03472 /************************************************************************* 03473 * TrioOutStreamFileDescriptor 03474 */ 03475 TRIO_PRIVATE void 03476 TrioOutStreamFileDescriptor 03477 TRIO_ARGS2((self, output), 03478 trio_class_t *self, 03479 int output) 03480 { 03481 int fd; 03482 char ch; 03483 03484 assert(VALID(self)); 03485 03486 fd = *((int *)self->location); 03487 ch = (char)output; 03488 self->processed++; 03489 if (write(fd, &ch, sizeof(char)) == -1) 03490 { 03491 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); 03492 } 03493 else 03494 { 03495 self->committed++; 03496 } 03497 } 03498 03499 /************************************************************************* 03500 * TrioOutStreamCustom 03501 */ 03502 TRIO_PRIVATE void 03503 TrioOutStreamCustom 03504 TRIO_ARGS2((self, output), 03505 trio_class_t *self, 03506 int output) 03507 { 03508 int status; 03509 trio_custom_t *data; 03510 03511 assert(VALID(self)); 03512 assert(VALID(self->location)); 03513 03514 data = (trio_custom_t *)self->location; 03515 if (data->stream.out) 03516 { 03517 status = (data->stream.out)(data->closure, output); 03518 if (status >= 0) 03519 { 03520 self->committed++; 03521 } 03522 else 03523 { 03524 if (self->error == 0) 03525 { 03526 self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status); 03527 } 03528 } 03529 } 03530 self->processed++; 03531 } 03532 03533 /************************************************************************* 03534 * TrioOutStreamString 03535 */ 03536 TRIO_PRIVATE void 03537 TrioOutStreamString 03538 TRIO_ARGS2((self, output), 03539 trio_class_t *self, 03540 int output) 03541 { 03542 char **buffer; 03543 03544 assert(VALID(self)); 03545 assert(VALID(self->location)); 03546 03547 buffer = (char **)self->location; 03548 **buffer = (char)output; 03549 (*buffer)++; 03550 self->processed++; 03551 self->committed++; 03552 } 03553 03554 /************************************************************************* 03555 * TrioOutStreamStringMax 03556 */ 03557 TRIO_PRIVATE void 03558 TrioOutStreamStringMax 03559 TRIO_ARGS2((self, output), 03560 trio_class_t *self, 03561 int output) 03562 { 03563 char **buffer; 03564 03565 assert(VALID(self)); 03566 assert(VALID(self->location)); 03567 03568 buffer = (char **)self->location; 03569 03570 if (self->processed < self->max) 03571 { 03572 **buffer = (char)output; 03573 (*buffer)++; 03574 self->committed++; 03575 } 03576 self->processed++; 03577 } 03578 03579 /************************************************************************* 03580 * TrioOutStreamStringDynamic 03581 */ 03582 TRIO_PRIVATE void 03583 TrioOutStreamStringDynamic 03584 TRIO_ARGS2((self, output), 03585 trio_class_t *self, 03586 int output) 03587 { 03588 assert(VALID(self)); 03589 assert(VALID(self->location)); 03590 03591 if (self->error == 0) 03592 { 03593 trio_xstring_append_char((trio_string_t *)self->location, 03594 (char)output); 03595 self->committed++; 03596 } 03597 /* The processed variable must always be increased */ 03598 self->processed++; 03599 } 03600 03601 /************************************************************************* 03602 * 03603 * Formatted printing functions 03604 * 03605 ************************************************************************/ 03606 03607 #if defined(TRIO_DOCUMENTATION) 03608 # include "doc/doc_printf.h" 03609 #endif 03610 03614 /************************************************************************* 03615 * printf 03616 */ 03617 03625 TRIO_PUBLIC int 03626 trio_printf 03627 TRIO_VARGS2((format, va_alist), 03628 TRIO_CONST char *format, 03629 TRIO_VA_DECL) 03630 { 03631 int status; 03632 va_list args; 03633 03634 assert(VALID(format)); 03635 03636 TRIO_VA_START(args, format); 03637 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL); 03638 TRIO_VA_END(args); 03639 return status; 03640 } 03641 03649 TRIO_PUBLIC int 03650 trio_vprintf 03651 TRIO_ARGS2((format, args), 03652 TRIO_CONST char *format, 03653 va_list args) 03654 { 03655 assert(VALID(format)); 03656 03657 return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL); 03658 } 03659 03667 TRIO_PUBLIC int 03668 trio_printfv 03669 TRIO_ARGS2((format, args), 03670 TRIO_CONST char *format, 03671 trio_pointer_t * args) 03672 { 03673 assert(VALID(format)); 03674 03675 return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args); 03676 } 03677 03678 /************************************************************************* 03679 * fprintf 03680 */ 03681 03690 TRIO_PUBLIC int 03691 trio_fprintf 03692 TRIO_VARGS3((file, format, va_alist), 03693 FILE *file, 03694 TRIO_CONST char *format, 03695 TRIO_VA_DECL) 03696 { 03697 int status; 03698 va_list args; 03699 03700 assert(VALID(file)); 03701 assert(VALID(format)); 03702 03703 TRIO_VA_START(args, format); 03704 status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL); 03705 TRIO_VA_END(args); 03706 return status; 03707 } 03708 03717 TRIO_PUBLIC int 03718 trio_vfprintf 03719 TRIO_ARGS3((file, format, args), 03720 FILE *file, 03721 TRIO_CONST char *format, 03722 va_list args) 03723 { 03724 assert(VALID(file)); 03725 assert(VALID(format)); 03726 03727 return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL); 03728 } 03729 03738 TRIO_PUBLIC int 03739 trio_fprintfv 03740 TRIO_ARGS3((file, format, args), 03741 FILE *file, 03742 TRIO_CONST char *format, 03743 trio_pointer_t * args) 03744 { 03745 assert(VALID(file)); 03746 assert(VALID(format)); 03747 03748 return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args); 03749 } 03750 03751 /************************************************************************* 03752 * dprintf 03753 */ 03754 03763 TRIO_PUBLIC int 03764 trio_dprintf 03765 TRIO_VARGS3((fd, format, va_alist), 03766 int fd, 03767 TRIO_CONST char *format, 03768 TRIO_VA_DECL) 03769 { 03770 int status; 03771 va_list args; 03772 03773 assert(VALID(format)); 03774 03775 TRIO_VA_START(args, format); 03776 status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL); 03777 TRIO_VA_END(args); 03778 return status; 03779 } 03780 03789 TRIO_PUBLIC int 03790 trio_vdprintf 03791 TRIO_ARGS3((fd, format, args), 03792 int fd, 03793 TRIO_CONST char *format, 03794 va_list args) 03795 { 03796 assert(VALID(format)); 03797 03798 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL); 03799 } 03800 03809 TRIO_PUBLIC int 03810 trio_dprintfv 03811 TRIO_ARGS3((fd, format, args), 03812 int fd, 03813 TRIO_CONST char *format, 03814 trio_pointer_t *args) 03815 { 03816 assert(VALID(format)); 03817 03818 return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args); 03819 } 03820 03821 /************************************************************************* 03822 * cprintf 03823 */ 03824 TRIO_PUBLIC int 03825 trio_cprintf 03826 TRIO_VARGS4((stream, closure, format, va_alist), 03827 trio_outstream_t stream, 03828 trio_pointer_t closure, 03829 TRIO_CONST char *format, 03830 TRIO_VA_DECL) 03831 { 03832 int status; 03833 va_list args; 03834 trio_custom_t data; 03835 03836 assert(VALID(stream)); 03837 assert(VALID(format)); 03838 03839 TRIO_VA_START(args, format); 03840 data.stream.out = stream; 03841 data.closure = closure; 03842 status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL); 03843 TRIO_VA_END(args); 03844 return status; 03845 } 03846 03847 TRIO_PUBLIC int 03848 trio_vcprintf 03849 TRIO_ARGS4((stream, closure, format, args), 03850 trio_outstream_t stream, 03851 trio_pointer_t closure, 03852 TRIO_CONST char *format, 03853 va_list args) 03854 { 03855 trio_custom_t data; 03856 03857 assert(VALID(stream)); 03858 assert(VALID(format)); 03859 03860 data.stream.out = stream; 03861 data.closure = closure; 03862 return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL); 03863 } 03864 03865 TRIO_PUBLIC int 03866 trio_cprintfv 03867 TRIO_ARGS4((stream, closure, format, args), 03868 trio_outstream_t stream, 03869 trio_pointer_t closure, 03870 TRIO_CONST char *format, 03871 void **args) 03872 { 03873 trio_custom_t data; 03874 03875 assert(VALID(stream)); 03876 assert(VALID(format)); 03877 03878 data.stream.out = stream; 03879 data.closure = closure; 03880 return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args); 03881 } 03882 03883 /************************************************************************* 03884 * sprintf 03885 */ 03886 03895 TRIO_PUBLIC int 03896 trio_sprintf 03897 TRIO_VARGS3((buffer, format, va_alist), 03898 char *buffer, 03899 TRIO_CONST char *format, 03900 TRIO_VA_DECL) 03901 { 03902 int status; 03903 va_list args; 03904 03905 assert(VALID(buffer)); 03906 assert(VALID(format)); 03907 03908 TRIO_VA_START(args, format); 03909 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL); 03910 *buffer = NIL; /* Terminate with NIL character */ 03911 TRIO_VA_END(args); 03912 return status; 03913 } 03914 03923 TRIO_PUBLIC int 03924 trio_vsprintf 03925 TRIO_ARGS3((buffer, format, args), 03926 char *buffer, 03927 TRIO_CONST char *format, 03928 va_list args) 03929 { 03930 int status; 03931 03932 assert(VALID(buffer)); 03933 assert(VALID(format)); 03934 03935 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL); 03936 *buffer = NIL; 03937 return status; 03938 } 03939 03948 TRIO_PUBLIC int 03949 trio_sprintfv 03950 TRIO_ARGS3((buffer, format, args), 03951 char *buffer, 03952 TRIO_CONST char *format, 03953 trio_pointer_t *args) 03954 { 03955 int status; 03956 03957 assert(VALID(buffer)); 03958 assert(VALID(format)); 03959 03960 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args); 03961 *buffer = NIL; 03962 return status; 03963 } 03964 03965 /************************************************************************* 03966 * snprintf 03967 */ 03968 03978 TRIO_PUBLIC int 03979 trio_snprintf 03980 TRIO_VARGS4((buffer, max, format, va_alist), 03981 char *buffer, 03982 size_t max, 03983 TRIO_CONST char *format, 03984 TRIO_VA_DECL) 03985 { 03986 int status; 03987 va_list args; 03988 03989 assert(VALID(buffer)); 03990 assert(VALID(format)); 03991 03992 TRIO_VA_START(args, format); 03993 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, 03994 TrioOutStreamStringMax, format, &args, NULL); 03995 if (max > 0) 03996 *buffer = NIL; 03997 TRIO_VA_END(args); 03998 return status; 03999 } 04000 04010 TRIO_PUBLIC int 04011 trio_vsnprintf 04012 TRIO_ARGS4((buffer, max, format, args), 04013 char *buffer, 04014 size_t max, 04015 TRIO_CONST char *format, 04016 va_list args) 04017 { 04018 int status; 04019 04020 assert(VALID(buffer)); 04021 assert(VALID(format)); 04022 04023 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, 04024 TrioOutStreamStringMax, format, &args, NULL); 04025 if (max > 0) 04026 *buffer = NIL; 04027 return status; 04028 } 04029 04039 TRIO_PUBLIC int 04040 trio_snprintfv 04041 TRIO_ARGS4((buffer, max, format, args), 04042 char *buffer, 04043 size_t max, 04044 TRIO_CONST char *format, 04045 trio_pointer_t *args) 04046 { 04047 int status; 04048 04049 assert(VALID(buffer)); 04050 assert(VALID(format)); 04051 04052 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, 04053 TrioOutStreamStringMax, format, NULL, args); 04054 if (max > 0) 04055 *buffer = NIL; 04056 return status; 04057 } 04058 04059 /************************************************************************* 04060 * snprintfcat 04061 * Appends the new string to the buffer string overwriting the '\0' 04062 * character at the end of buffer. 04063 */ 04064 TRIO_PUBLIC int 04065 trio_snprintfcat 04066 TRIO_VARGS4((buffer, max, format, va_alist), 04067 char *buffer, 04068 size_t max, 04069 TRIO_CONST char *format, 04070 TRIO_VA_DECL) 04071 { 04072 int status; 04073 va_list args; 04074 size_t buf_len; 04075 04076 TRIO_VA_START(args, format); 04077 04078 assert(VALID(buffer)); 04079 assert(VALID(format)); 04080 04081 buf_len = trio_length(buffer); 04082 buffer = &buffer[buf_len]; 04083 04084 status = TrioFormat(&buffer, max - 1 - buf_len, 04085 TrioOutStreamStringMax, format, &args, NULL); 04086 TRIO_VA_END(args); 04087 *buffer = NIL; 04088 return status; 04089 } 04090 04091 TRIO_PUBLIC int 04092 trio_vsnprintfcat 04093 TRIO_ARGS4((buffer, max, format, args), 04094 char *buffer, 04095 size_t max, 04096 TRIO_CONST char *format, 04097 va_list args) 04098 { 04099 int status; 04100 size_t buf_len; 04101 04102 assert(VALID(buffer)); 04103 assert(VALID(format)); 04104 04105 buf_len = trio_length(buffer); 04106 buffer = &buffer[buf_len]; 04107 status = TrioFormat(&buffer, max - 1 - buf_len, 04108 TrioOutStreamStringMax, format, &args, NULL); 04109 *buffer = NIL; 04110 return status; 04111 } 04112 04113 /************************************************************************* 04114 * trio_aprintf 04115 */ 04116 04117 /* Deprecated */ 04118 TRIO_PUBLIC char * 04119 trio_aprintf 04120 TRIO_VARGS2((format, va_alist), 04121 TRIO_CONST char *format, 04122 TRIO_VA_DECL) 04123 { 04124 va_list args; 04125 trio_string_t *info; 04126 char *result = NULL; 04127 04128 assert(VALID(format)); 04129 04130 info = trio_xstring_duplicate(""); 04131 if (info) 04132 { 04133 TRIO_VA_START(args, format); 04134 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, 04135 format, &args, NULL); 04136 TRIO_VA_END(args); 04137 04138 trio_string_terminate(info); 04139 result = trio_string_extract(info); 04140 trio_string_destroy(info); 04141 } 04142 return result; 04143 } 04144 04145 /* Deprecated */ 04146 TRIO_PUBLIC char * 04147 trio_vaprintf 04148 TRIO_ARGS2((format, args), 04149 TRIO_CONST char *format, 04150 va_list args) 04151 { 04152 trio_string_t *info; 04153 char *result = NULL; 04154 04155 assert(VALID(format)); 04156 04157 info = trio_xstring_duplicate(""); 04158 if (info) 04159 { 04160 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, 04161 format, &args, NULL); 04162 trio_string_terminate(info); 04163 result = trio_string_extract(info); 04164 trio_string_destroy(info); 04165 } 04166 return result; 04167 } 04168 04169 TRIO_PUBLIC int 04170 trio_asprintf 04171 TRIO_VARGS3((result, format, va_alist), 04172 char **result, 04173 TRIO_CONST char *format, 04174 TRIO_VA_DECL) 04175 { 04176 va_list args; 04177 int status; 04178 trio_string_t *info; 04179 04180 assert(VALID(format)); 04181 04182 *result = NULL; 04183 04184 info = trio_xstring_duplicate(""); 04185 if (info == NULL) 04186 { 04187 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); 04188 } 04189 else 04190 { 04191 TRIO_VA_START(args, format); 04192 status = TrioFormat(info, 0, TrioOutStreamStringDynamic, 04193 format, &args, NULL); 04194 TRIO_VA_END(args); 04195 if (status >= 0) 04196 { 04197 trio_string_terminate(info); 04198 *result = trio_string_extract(info); 04199 } 04200 trio_string_destroy(info); 04201 } 04202 return status; 04203 } 04204 04205 TRIO_PUBLIC int 04206 trio_vasprintf 04207 TRIO_ARGS3((result, format, args), 04208 char **result, 04209 TRIO_CONST char *format, 04210 va_list args) 04211 { 04212 int status; 04213 trio_string_t *info; 04214 04215 assert(VALID(format)); 04216 04217 *result = NULL; 04218 04219 info = trio_xstring_duplicate(""); 04220 if (info == NULL) 04221 { 04222 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); 04223 } 04224 else 04225 { 04226 status = TrioFormat(info, 0, TrioOutStreamStringDynamic, 04227 format, &args, NULL); 04228 if (status >= 0) 04229 { 04230 trio_string_terminate(info); 04231 *result = trio_string_extract(info); 04232 } 04233 trio_string_destroy(info); 04234 } 04235 return status; 04236 } 04237 04240 /************************************************************************* 04241 * 04242 * CALLBACK 04243 * 04244 ************************************************************************/ 04245 04246 #if defined(TRIO_DOCUMENTATION) 04247 # include "doc/doc_register.h" 04248 #endif 04249 04254 #if TRIO_EXTENSION 04255 04256 /************************************************************************* 04257 * trio_register 04258 */ 04259 04267 TRIO_PUBLIC trio_pointer_t 04268 trio_register 04269 TRIO_ARGS2((callback, name), 04270 trio_callback_t callback, 04271 TRIO_CONST char *name) 04272 { 04273 trio_userdef_t *def; 04274 trio_userdef_t *prev = NULL; 04275 04276 if (callback == NULL) 04277 return NULL; 04278 04279 if (name) 04280 { 04281 /* Handle built-in namespaces */ 04282 if (name[0] == ':') 04283 { 04284 if (trio_equal(name, ":enter")) 04285 { 04286 internalEnterCriticalRegion = callback; 04287 } 04288 else if (trio_equal(name, ":leave")) 04289 { 04290 internalLeaveCriticalRegion = callback; 04291 } 04292 return NULL; 04293 } 04294 04295 /* Bail out if namespace is too long */ 04296 if (trio_length(name) >= MAX_USER_NAME) 04297 return NULL; 04298 04299 /* Bail out if namespace already is registered */ 04300 def = TrioFindNamespace(name, &prev); 04301 if (def) 04302 return NULL; 04303 } 04304 04305 def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t)); 04306 if (def) 04307 { 04308 if (internalEnterCriticalRegion) 04309 (void)internalEnterCriticalRegion(NULL); 04310 04311 if (name) 04312 { 04313 /* Link into internal list */ 04314 if (prev == NULL) 04315 internalUserDef = def; 04316 else 04317 prev->next = def; 04318 } 04319 /* Initialize */ 04320 def->callback = callback; 04321 def->name = (name == NULL) 04322 ? NULL 04323 : trio_duplicate(name); 04324 def->next = NULL; 04325 04326 if (internalLeaveCriticalRegion) 04327 (void)internalLeaveCriticalRegion(NULL); 04328 } 04329 return (trio_pointer_t)def; 04330 } 04331 04337 void 04338 trio_unregister 04339 TRIO_ARGS1((handle), 04340 trio_pointer_t handle) 04341 { 04342 trio_userdef_t *self = (trio_userdef_t *)handle; 04343 trio_userdef_t *def; 04344 trio_userdef_t *prev = NULL; 04345 04346 assert(VALID(self)); 04347 04348 if (self->name) 04349 { 04350 def = TrioFindNamespace(self->name, &prev); 04351 if (def) 04352 { 04353 if (internalEnterCriticalRegion) 04354 (void)internalEnterCriticalRegion(NULL); 04355 04356 if (prev == NULL) 04357 internalUserDef = NULL; 04358 else 04359 prev->next = def->next; 04360 04361 if (internalLeaveCriticalRegion) 04362 (void)internalLeaveCriticalRegion(NULL); 04363 } 04364 trio_destroy(self->name); 04365 } 04366 TRIO_FREE(self); 04367 } 04368 04369 /************************************************************************* 04370 * trio_get_format [public] 04371 */ 04372 TRIO_CONST char * 04373 trio_get_format 04374 TRIO_ARGS1((ref), 04375 trio_pointer_t ref) 04376 { 04377 #if defined(FORMAT_USER_DEFINED) 04378 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); 04379 #endif 04380 04381 return (((trio_reference_t *)ref)->parameter->user_data); 04382 } 04383 04384 /************************************************************************* 04385 * trio_get_argument [public] 04386 */ 04387 trio_pointer_t 04388 trio_get_argument 04389 TRIO_ARGS1((ref), 04390 trio_pointer_t ref) 04391 { 04392 #if defined(FORMAT_USER_DEFINED) 04393 assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); 04394 #endif 04395 04396 return ((trio_reference_t *)ref)->parameter->data.pointer; 04397 } 04398 04399 /************************************************************************* 04400 * trio_get_width / trio_set_width [public] 04401 */ 04402 int 04403 trio_get_width 04404 TRIO_ARGS1((ref), 04405 trio_pointer_t ref) 04406 { 04407 return ((trio_reference_t *)ref)->parameter->width; 04408 } 04409 04410 void 04411 trio_set_width 04412 TRIO_ARGS2((ref, width), 04413 trio_pointer_t ref, 04414 int width) 04415 { 04416 ((trio_reference_t *)ref)->parameter->width = width; 04417 } 04418 04419 /************************************************************************* 04420 * trio_get_precision / trio_set_precision [public] 04421 */ 04422 int 04423 trio_get_precision 04424 TRIO_ARGS1((ref), 04425 trio_pointer_t ref) 04426 { 04427 return (((trio_reference_t *)ref)->parameter->precision); 04428 } 04429 04430 void 04431 trio_set_precision 04432 TRIO_ARGS2((ref, precision), 04433 trio_pointer_t ref, 04434 int precision) 04435 { 04436 ((trio_reference_t *)ref)->parameter->precision = precision; 04437 } 04438 04439 /************************************************************************* 04440 * trio_get_base / trio_set_base [public] 04441 */ 04442 int 04443 trio_get_base 04444 TRIO_ARGS1((ref), 04445 trio_pointer_t ref) 04446 { 04447 return (((trio_reference_t *)ref)->parameter->base); 04448 } 04449 04450 void 04451 trio_set_base 04452 TRIO_ARGS2((ref, base), 04453 trio_pointer_t ref, 04454 int base) 04455 { 04456 ((trio_reference_t *)ref)->parameter->base = base; 04457 } 04458 04459 /************************************************************************* 04460 * trio_get_long / trio_set_long [public] 04461 */ 04462 int 04463 trio_get_long 04464 TRIO_ARGS1((ref), 04465 trio_pointer_t ref) 04466 { 04467 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG) 04468 ? TRUE 04469 : FALSE; 04470 } 04471 04472 void 04473 trio_set_long 04474 TRIO_ARGS2((ref, is_long), 04475 trio_pointer_t ref, 04476 int is_long) 04477 { 04478 if (is_long) 04479 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG; 04480 else 04481 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG; 04482 } 04483 04484 /************************************************************************* 04485 * trio_get_longlong / trio_set_longlong [public] 04486 */ 04487 int 04488 trio_get_longlong 04489 TRIO_ARGS1((ref), 04490 trio_pointer_t ref) 04491 { 04492 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD) 04493 ? TRUE 04494 : FALSE; 04495 } 04496 04497 void 04498 trio_set_longlong 04499 TRIO_ARGS2((ref, is_longlong), 04500 trio_pointer_t ref, 04501 int is_longlong) 04502 { 04503 if (is_longlong) 04504 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD; 04505 else 04506 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD; 04507 } 04508 04509 /************************************************************************* 04510 * trio_get_longdouble / trio_set_longdouble [public] 04511 */ 04512 int 04513 trio_get_longdouble 04514 TRIO_ARGS1((ref), 04515 trio_pointer_t ref) 04516 { 04517 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE) 04518 ? TRUE 04519 : FALSE; 04520 } 04521 04522 void 04523 trio_set_longdouble 04524 TRIO_ARGS2((ref, is_longdouble), 04525 trio_pointer_t ref, 04526 int is_longdouble) 04527 { 04528 if (is_longdouble) 04529 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE; 04530 else 04531 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE; 04532 } 04533 04534 /************************************************************************* 04535 * trio_get_short / trio_set_short [public] 04536 */ 04537 int 04538 trio_get_short 04539 TRIO_ARGS1((ref), 04540 trio_pointer_t ref) 04541 { 04542 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT) 04543 ? TRUE 04544 : FALSE; 04545 } 04546 04547 void 04548 trio_set_short 04549 TRIO_ARGS2((ref, is_short), 04550 trio_pointer_t ref, 04551 int is_short) 04552 { 04553 if (is_short) 04554 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT; 04555 else 04556 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT; 04557 } 04558 04559 /************************************************************************* 04560 * trio_get_shortshort / trio_set_shortshort [public] 04561 */ 04562 int 04563 trio_get_shortshort 04564 TRIO_ARGS1((ref), 04565 trio_pointer_t ref) 04566 { 04567 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT) 04568 ? TRUE 04569 : FALSE; 04570 } 04571 04572 void 04573 trio_set_shortshort 04574 TRIO_ARGS2((ref, is_shortshort), 04575 trio_pointer_t ref, 04576 int is_shortshort) 04577 { 04578 if (is_shortshort) 04579 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT; 04580 else 04581 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT; 04582 } 04583 04584 /************************************************************************* 04585 * trio_get_alternative / trio_set_alternative [public] 04586 */ 04587 int 04588 trio_get_alternative 04589 TRIO_ARGS1((ref), 04590 trio_pointer_t ref) 04591 { 04592 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE) 04593 ? TRUE 04594 : FALSE; 04595 } 04596 04597 void 04598 trio_set_alternative 04599 TRIO_ARGS2((ref, is_alternative), 04600 trio_pointer_t ref, 04601 int is_alternative) 04602 { 04603 if (is_alternative) 04604 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE; 04605 else 04606 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE; 04607 } 04608 04609 /************************************************************************* 04610 * trio_get_alignment / trio_set_alignment [public] 04611 */ 04612 int 04613 trio_get_alignment 04614 TRIO_ARGS1((ref), 04615 trio_pointer_t ref) 04616 { 04617 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST) 04618 ? TRUE 04619 : FALSE; 04620 } 04621 04622 void 04623 trio_set_alignment 04624 TRIO_ARGS2((ref, is_leftaligned), 04625 trio_pointer_t ref, 04626 int is_leftaligned) 04627 { 04628 if (is_leftaligned) 04629 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST; 04630 else 04631 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST; 04632 } 04633 04634 /************************************************************************* 04635 * trio_get_spacing /trio_set_spacing [public] 04636 */ 04637 int 04638 trio_get_spacing 04639 TRIO_ARGS1((ref), 04640 trio_pointer_t ref) 04641 { 04642 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE) 04643 ? TRUE 04644 : FALSE; 04645 } 04646 04647 void 04648 trio_set_spacing 04649 TRIO_ARGS2((ref, is_space), 04650 trio_pointer_t ref, 04651 int is_space) 04652 { 04653 if (is_space) 04654 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE; 04655 else 04656 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE; 04657 } 04658 04659 /************************************************************************* 04660 * trio_get_sign / trio_set_sign [public] 04661 */ 04662 int 04663 trio_get_sign 04664 TRIO_ARGS1((ref), 04665 trio_pointer_t ref) 04666 { 04667 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN) 04668 ? TRUE 04669 : FALSE; 04670 } 04671 04672 void 04673 trio_set_sign 04674 TRIO_ARGS2((ref, is_sign), 04675 trio_pointer_t ref, 04676 int is_sign) 04677 { 04678 if (is_sign) 04679 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN; 04680 else 04681 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN; 04682 } 04683 04684 /************************************************************************* 04685 * trio_get_padding / trio_set_padding [public] 04686 */ 04687 int 04688 trio_get_padding 04689 TRIO_ARGS1((ref), 04690 trio_pointer_t ref) 04691 { 04692 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING) 04693 ? TRUE 04694 : FALSE; 04695 } 04696 04697 void 04698 trio_set_padding 04699 TRIO_ARGS2((ref, is_padding), 04700 trio_pointer_t ref, 04701 int is_padding) 04702 { 04703 if (is_padding) 04704 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING; 04705 else 04706 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING; 04707 } 04708 04709 /************************************************************************* 04710 * trio_get_quote / trio_set_quote [public] 04711 */ 04712 int 04713 trio_get_quote 04714 TRIO_ARGS1((ref), 04715 trio_pointer_t ref) 04716 { 04717 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE) 04718 ? TRUE 04719 : FALSE; 04720 } 04721 04722 void 04723 trio_set_quote 04724 TRIO_ARGS2((ref, is_quote), 04725 trio_pointer_t ref, 04726 int is_quote) 04727 { 04728 if (is_quote) 04729 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE; 04730 else 04731 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE; 04732 } 04733 04734 /************************************************************************* 04735 * trio_get_upper / trio_set_upper [public] 04736 */ 04737 int 04738 trio_get_upper 04739 TRIO_ARGS1((ref), 04740 trio_pointer_t ref) 04741 { 04742 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER) 04743 ? TRUE 04744 : FALSE; 04745 } 04746 04747 void 04748 trio_set_upper 04749 TRIO_ARGS2((ref, is_upper), 04750 trio_pointer_t ref, 04751 int is_upper) 04752 { 04753 if (is_upper) 04754 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER; 04755 else 04756 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER; 04757 } 04758 04759 /************************************************************************* 04760 * trio_get_largest / trio_set_largest [public] 04761 */ 04762 #if TRIO_C99 04763 int 04764 trio_get_largest 04765 TRIO_ARGS1((ref), 04766 trio_pointer_t ref) 04767 { 04768 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T) 04769 ? TRUE 04770 : FALSE; 04771 } 04772 04773 void 04774 trio_set_largest 04775 TRIO_ARGS2((ref, is_largest), 04776 trio_pointer_t ref, 04777 int is_largest) 04778 { 04779 if (is_largest) 04780 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T; 04781 else 04782 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T; 04783 } 04784 #endif 04785 04786 /************************************************************************* 04787 * trio_get_ptrdiff / trio_set_ptrdiff [public] 04788 */ 04789 int 04790 trio_get_ptrdiff 04791 TRIO_ARGS1((ref), 04792 trio_pointer_t ref) 04793 { 04794 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T) 04795 ? TRUE 04796 : FALSE; 04797 } 04798 04799 void 04800 trio_set_ptrdiff 04801 TRIO_ARGS2((ref, is_ptrdiff), 04802 trio_pointer_t ref, 04803 int is_ptrdiff) 04804 { 04805 if (is_ptrdiff) 04806 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T; 04807 else 04808 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T; 04809 } 04810 04811 /************************************************************************* 04812 * trio_get_size / trio_set_size [public] 04813 */ 04814 #if TRIO_C99 04815 int 04816 trio_get_size 04817 TRIO_ARGS1((ref), 04818 trio_pointer_t ref) 04819 { 04820 return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T) 04821 ? TRUE 04822 : FALSE; 04823 } 04824 04825 void 04826 trio_set_size 04827 TRIO_ARGS2((ref, is_size), 04828 trio_pointer_t ref, 04829 int is_size) 04830 { 04831 if (is_size) 04832 ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T; 04833 else 04834 ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T; 04835 } 04836 #endif 04837 04838 /************************************************************************* 04839 * trio_print_int [public] 04840 */ 04841 void 04842 trio_print_int 04843 TRIO_ARGS2((ref, number), 04844 trio_pointer_t ref, 04845 int number) 04846 { 04847 trio_reference_t *self = (trio_reference_t *)ref; 04848 04849 TrioWriteNumber(self->data, 04850 (trio_uintmax_t)number, 04851 self->parameter->flags, 04852 self->parameter->width, 04853 self->parameter->precision, 04854 self->parameter->base); 04855 } 04856 04857 /************************************************************************* 04858 * trio_print_uint [public] 04859 */ 04860 void 04861 trio_print_uint 04862 TRIO_ARGS2((ref, number), 04863 trio_pointer_t ref, 04864 unsigned int number) 04865 { 04866 trio_reference_t *self = (trio_reference_t *)ref; 04867 04868 TrioWriteNumber(self->data, 04869 (trio_uintmax_t)number, 04870 self->parameter->flags | FLAGS_UNSIGNED, 04871 self->parameter->width, 04872 self->parameter->precision, 04873 self->parameter->base); 04874 } 04875 04876 /************************************************************************* 04877 * trio_print_double [public] 04878 */ 04879 void 04880 trio_print_double 04881 TRIO_ARGS2((ref, number), 04882 trio_pointer_t ref, 04883 double number) 04884 { 04885 trio_reference_t *self = (trio_reference_t *)ref; 04886 04887 TrioWriteDouble(self->data, 04888 number, 04889 self->parameter->flags, 04890 self->parameter->width, 04891 self->parameter->precision, 04892 self->parameter->base); 04893 } 04894 04895 /************************************************************************* 04896 * trio_print_string [public] 04897 */ 04898 void 04899 trio_print_string 04900 TRIO_ARGS2((ref, string), 04901 trio_pointer_t ref, 04902 char *string) 04903 { 04904 trio_reference_t *self = (trio_reference_t *)ref; 04905 04906 TrioWriteString(self->data, 04907 string, 04908 self->parameter->flags, 04909 self->parameter->width, 04910 self->parameter->precision); 04911 } 04912 04913 /************************************************************************* 04914 * trio_print_ref [public] 04915 */ 04916 int 04917 trio_print_ref 04918 TRIO_VARGS3((ref, format, va_alist), 04919 trio_pointer_t ref, 04920 TRIO_CONST char *format, 04921 TRIO_VA_DECL) 04922 { 04923 int status; 04924 va_list arglist; 04925 04926 assert(VALID(format)); 04927 04928 TRIO_VA_START(arglist, format); 04929 status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL); 04930 TRIO_VA_END(arglist); 04931 return status; 04932 } 04933 04934 /************************************************************************* 04935 * trio_vprint_ref [public] 04936 */ 04937 int 04938 trio_vprint_ref 04939 TRIO_ARGS3((ref, format, arglist), 04940 trio_pointer_t ref, 04941 TRIO_CONST char *format, 04942 va_list arglist) 04943 { 04944 assert(VALID(format)); 04945 04946 return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL); 04947 } 04948 04949 /************************************************************************* 04950 * trio_printv_ref [public] 04951 */ 04952 int 04953 trio_printv_ref 04954 TRIO_ARGS3((ref, format, argarray), 04955 trio_pointer_t ref, 04956 TRIO_CONST char *format, 04957 trio_pointer_t *argarray) 04958 { 04959 assert(VALID(format)); 04960 04961 return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray); 04962 } 04963 04964 #endif /* TRIO_EXTENSION */ 04965 04966 /************************************************************************* 04967 * trio_print_pointer [public] 04968 */ 04969 void 04970 trio_print_pointer 04971 TRIO_ARGS2((ref, pointer), 04972 trio_pointer_t ref, 04973 trio_pointer_t pointer) 04974 { 04975 trio_reference_t *self = (trio_reference_t *)ref; 04976 trio_flags_t flags; 04977 trio_uintmax_t number; 04978 04979 if (NULL == pointer) 04980 { 04981 TRIO_CONST char *string = internalNullString; 04982 while (*string) 04983 self->data->OutStream(self->data, *string++); 04984 } 04985 else 04986 { 04987 /* 04988 * The subtraction of the null pointer is a workaround 04989 * to avoid a compiler warning. The performance overhead 04990 * is negligible (and likely to be removed by an 04991 * optimizing compiler). The (char *) casting is done 04992 * to please ANSI C++. 04993 */ 04994 number = (trio_uintmax_t)((char *)pointer - (char *)0); 04995 /* Shrink to size of pointer */ 04996 number &= (trio_uintmax_t)-1; 04997 flags = self->parameter->flags; 04998 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | 04999 FLAGS_NILPADDING); 05000 TrioWriteNumber(self->data, 05001 number, 05002 flags, 05003 POINTER_WIDTH, 05004 NO_PRECISION, 05005 BASE_HEX); 05006 } 05007 } 05008 05011 /************************************************************************* 05012 * 05013 * LOCALES 05014 * 05015 ************************************************************************/ 05016 05017 /************************************************************************* 05018 * trio_locale_set_decimal_point 05019 * 05020 * Decimal point can only be one character. The input argument is a 05021 * string to enable multibyte characters. At most MB_LEN_MAX characters 05022 * will be used. 05023 */ 05024 TRIO_PUBLIC void 05025 trio_locale_set_decimal_point 05026 TRIO_ARGS1((decimalPoint), 05027 char *decimalPoint) 05028 { 05029 #if defined(USE_LOCALE) 05030 if (NULL == internalLocaleValues) 05031 { 05032 TrioSetLocale(); 05033 } 05034 #endif 05035 internalDecimalPointLength = trio_length(decimalPoint); 05036 if (internalDecimalPointLength == 1) 05037 { 05038 internalDecimalPoint = *decimalPoint; 05039 } 05040 else 05041 { 05042 internalDecimalPoint = NIL; 05043 trio_copy_max(internalDecimalPointString, 05044 sizeof(internalDecimalPointString), 05045 decimalPoint); 05046 } 05047 } 05048 05049 /************************************************************************* 05050 * trio_locale_set_thousand_separator 05051 * 05052 * See trio_locale_set_decimal_point 05053 */ 05054 TRIO_PUBLIC void 05055 trio_locale_set_thousand_separator 05056 TRIO_ARGS1((thousandSeparator), 05057 char *thousandSeparator) 05058 { 05059 #if defined(USE_LOCALE) 05060 if (NULL == internalLocaleValues) 05061 { 05062 TrioSetLocale(); 05063 } 05064 #endif 05065 trio_copy_max(internalThousandSeparator, 05066 sizeof(internalThousandSeparator), 05067 thousandSeparator); 05068 internalThousandSeparatorLength = trio_length(internalThousandSeparator); 05069 } 05070 05071 /************************************************************************* 05072 * trio_locale_set_grouping 05073 * 05074 * Array of bytes. Reversed order. 05075 * 05076 * CHAR_MAX : No further grouping 05077 * 0 : Repeat last group for the remaining digits (not necessary 05078 * as C strings are zero-terminated) 05079 * n : Set current group to n 05080 * 05081 * Same order as the grouping attribute in LC_NUMERIC. 05082 */ 05083 TRIO_PUBLIC void 05084 trio_locale_set_grouping 05085 TRIO_ARGS1((grouping), 05086 char *grouping) 05087 { 05088 #if defined(USE_LOCALE) 05089 if (NULL == internalLocaleValues) 05090 { 05091 TrioSetLocale(); 05092 } 05093 #endif 05094 trio_copy_max(internalGrouping, 05095 sizeof(internalGrouping), 05096 grouping); 05097 } 05098 05099 05100 /************************************************************************* 05101 * 05102 * SCANNING 05103 * 05104 ************************************************************************/ 05105 05106 /************************************************************************* 05107 * TrioSkipWhitespaces 05108 */ 05109 TRIO_PRIVATE int 05110 TrioSkipWhitespaces 05111 TRIO_ARGS1((self), 05112 trio_class_t *self) 05113 { 05114 int ch; 05115 05116 ch = self->current; 05117 while (isspace(ch)) 05118 { 05119 self->InStream(self, &ch); 05120 } 05121 return ch; 05122 } 05123 05124 /************************************************************************* 05125 * TrioGetCollation 05126 */ 05127 #if TRIO_EXTENSION 05128 TRIO_PRIVATE void 05129 TrioGetCollation(TRIO_NOARGS) 05130 { 05131 int i; 05132 int j; 05133 int k; 05134 char first[2]; 05135 char second[2]; 05136 05137 /* This is computationally expensive */ 05138 first[1] = NIL; 05139 second[1] = NIL; 05140 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05141 { 05142 k = 0; 05143 first[0] = (char)i; 05144 for (j = 0; j < MAX_CHARACTER_CLASS; j++) 05145 { 05146 second[0] = (char)j; 05147 if (trio_equal_locale(first, second)) 05148 internalCollationArray[i][k++] = (char)j; 05149 } 05150 internalCollationArray[i][k] = NIL; 05151 } 05152 } 05153 #endif 05154 05155 /************************************************************************* 05156 * TrioGetCharacterClass 05157 * 05158 * FIXME: 05159 * multibyte 05160 */ 05161 TRIO_PRIVATE int 05162 TrioGetCharacterClass 05163 TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass), 05164 TRIO_CONST char *format, 05165 int *indexPointer, 05166 trio_flags_t *flagsPointer, 05167 int *characterclass) 05168 { 05169 int index = *indexPointer; 05170 int i; 05171 char ch; 05172 char range_begin; 05173 char range_end; 05174 05175 *flagsPointer &= ~FLAGS_EXCLUDE; 05176 05177 if (format[index] == QUALIFIER_CIRCUMFLEX) 05178 { 05179 *flagsPointer |= FLAGS_EXCLUDE; 05180 index++; 05181 } 05182 /* 05183 * If the ungroup character is at the beginning of the scanlist, 05184 * it will be part of the class, and a second ungroup character 05185 * must follow to end the group. 05186 */ 05187 if (format[index] == SPECIFIER_UNGROUP) 05188 { 05189 characterclass[(int)SPECIFIER_UNGROUP]++; 05190 index++; 05191 } 05192 /* 05193 * Minus is used to specify ranges. To include minus in the class, 05194 * it must be at the beginning of the list 05195 */ 05196 if (format[index] == QUALIFIER_MINUS) 05197 { 05198 characterclass[(int)QUALIFIER_MINUS]++; 05199 index++; 05200 } 05201 /* Collect characters */ 05202 for (ch = format[index]; 05203 (ch != SPECIFIER_UNGROUP) && (ch != NIL); 05204 ch = format[++index]) 05205 { 05206 switch (ch) 05207 { 05208 case QUALIFIER_MINUS: /* Scanlist ranges */ 05209 05210 /* 05211 * Both C99 and UNIX98 describes ranges as implementation- 05212 * defined. 05213 * 05214 * We support the following behaviour (although this may 05215 * change as we become wiser) 05216 * - only increasing ranges, ie. [a-b] but not [b-a] 05217 * - transitive ranges, ie. [a-b-c] == [a-c] 05218 * - trailing minus, ie. [a-] is interpreted as an 'a' 05219 * and a '-' 05220 * - duplicates (although we can easily convert these 05221 * into errors) 05222 */ 05223 range_begin = format[index - 1]; 05224 range_end = format[++index]; 05225 if (range_end == SPECIFIER_UNGROUP) 05226 { 05227 /* Trailing minus is included */ 05228 characterclass[(int)ch]++; 05229 ch = range_end; 05230 break; /* for */ 05231 } 05232 if (range_end == NIL) 05233 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 05234 if (range_begin > range_end) 05235 return TRIO_ERROR_RETURN(TRIO_ERANGE, index); 05236 05237 for (i = (int)range_begin; i <= (int)range_end; i++) 05238 characterclass[i]++; 05239 05240 ch = range_end; 05241 break; 05242 05243 #if TRIO_EXTENSION 05244 05245 case SPECIFIER_GROUP: 05246 05247 switch (format[index + 1]) 05248 { 05249 case QUALIFIER_DOT: /* Collating symbol */ 05250 /* 05251 * FIXME: This will be easier to implement when multibyte 05252 * characters have been implemented. Until now, we ignore 05253 * this feature. 05254 */ 05255 for (i = index + 2; ; i++) 05256 { 05257 if (format[i] == NIL) 05258 /* Error in syntax */ 05259 return -1; 05260 else if (format[i] == QUALIFIER_DOT) 05261 break; /* for */ 05262 } 05263 if (format[++i] != SPECIFIER_UNGROUP) 05264 return -1; 05265 05266 index = i; 05267 break; 05268 05269 case QUALIFIER_EQUAL: /* Equivalence class expressions */ 05270 { 05271 unsigned int j; 05272 unsigned int k; 05273 05274 if (internalCollationUnconverted) 05275 { 05276 /* Lazy evaluation of collation array */ 05277 TrioGetCollation(); 05278 internalCollationUnconverted = FALSE; 05279 } 05280 for (i = index + 2; ; i++) 05281 { 05282 if (format[i] == NIL) 05283 /* Error in syntax */ 05284 return -1; 05285 else if (format[i] == QUALIFIER_EQUAL) 05286 break; /* for */ 05287 else 05288 { 05289 /* Mark any equivalent character */ 05290 k = (unsigned int)format[i]; 05291 for (j = 0; internalCollationArray[k][j] != NIL; j++) 05292 characterclass[(int)internalCollationArray[k][j]]++; 05293 } 05294 } 05295 if (format[++i] != SPECIFIER_UNGROUP) 05296 return -1; 05297 05298 index = i; 05299 } 05300 break; 05301 05302 case QUALIFIER_COLON: /* Character class expressions */ 05303 05304 if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1, 05305 &format[index])) 05306 { 05307 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05308 if (isalnum(i)) 05309 characterclass[i]++; 05310 index += sizeof(CLASS_ALNUM) - 1; 05311 } 05312 else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1, 05313 &format[index])) 05314 { 05315 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05316 if (isalpha(i)) 05317 characterclass[i]++; 05318 index += sizeof(CLASS_ALPHA) - 1; 05319 } 05320 else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1, 05321 &format[index])) 05322 { 05323 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05324 if (iscntrl(i)) 05325 characterclass[i]++; 05326 index += sizeof(CLASS_CNTRL) - 1; 05327 } 05328 else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1, 05329 &format[index])) 05330 { 05331 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05332 if (isdigit(i)) 05333 characterclass[i]++; 05334 index += sizeof(CLASS_DIGIT) - 1; 05335 } 05336 else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1, 05337 &format[index])) 05338 { 05339 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05340 if (isgraph(i)) 05341 characterclass[i]++; 05342 index += sizeof(CLASS_GRAPH) - 1; 05343 } 05344 else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1, 05345 &format[index])) 05346 { 05347 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05348 if (islower(i)) 05349 characterclass[i]++; 05350 index += sizeof(CLASS_LOWER) - 1; 05351 } 05352 else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1, 05353 &format[index])) 05354 { 05355 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05356 if (isprint(i)) 05357 characterclass[i]++; 05358 index += sizeof(CLASS_PRINT) - 1; 05359 } 05360 else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1, 05361 &format[index])) 05362 { 05363 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05364 if (ispunct(i)) 05365 characterclass[i]++; 05366 index += sizeof(CLASS_PUNCT) - 1; 05367 } 05368 else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1, 05369 &format[index])) 05370 { 05371 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05372 if (isspace(i)) 05373 characterclass[i]++; 05374 index += sizeof(CLASS_SPACE) - 1; 05375 } 05376 else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1, 05377 &format[index])) 05378 { 05379 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05380 if (isupper(i)) 05381 characterclass[i]++; 05382 index += sizeof(CLASS_UPPER) - 1; 05383 } 05384 else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1, 05385 &format[index])) 05386 { 05387 for (i = 0; i < MAX_CHARACTER_CLASS; i++) 05388 if (isxdigit(i)) 05389 characterclass[i]++; 05390 index += sizeof(CLASS_XDIGIT) - 1; 05391 } 05392 else 05393 { 05394 characterclass[(int)ch]++; 05395 } 05396 break; 05397 05398 default: 05399 characterclass[(int)ch]++; 05400 break; 05401 } 05402 break; 05403 05404 #endif /* TRIO_EXTENSION */ 05405 05406 default: 05407 characterclass[(int)ch]++; 05408 break; 05409 } 05410 } 05411 return 0; 05412 } 05413 05414 /************************************************************************* 05415 * TrioReadNumber 05416 * 05417 * We implement our own number conversion in preference of strtol and 05418 * strtoul, because we must handle 'long long' and thousand separators. 05419 */ 05420 TRIO_PRIVATE BOOLEAN_T 05421 TrioReadNumber 05422 TRIO_ARGS5((self, target, flags, width, base), 05423 trio_class_t *self, 05424 trio_uintmax_t *target, 05425 trio_flags_t flags, 05426 int width, 05427 int base) 05428 { 05429 trio_uintmax_t number = 0; 05430 int digit; 05431 int count; 05432 BOOLEAN_T isNegative = FALSE; 05433 BOOLEAN_T gotNumber = FALSE; 05434 int j; 05435 05436 assert(VALID(self)); 05437 assert(VALID(self->InStream)); 05438 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE)); 05439 05440 if (internalDigitsUnconverted) 05441 { 05442 /* Lazy evaluation of digits array */ 05443 memset(internalDigitArray, -1, sizeof(internalDigitArray)); 05444 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++) 05445 { 05446 internalDigitArray[(int)internalDigitsLower[j]] = j; 05447 internalDigitArray[(int)internalDigitsUpper[j]] = j; 05448 } 05449 internalDigitsUnconverted = FALSE; 05450 } 05451 05452 TrioSkipWhitespaces(self); 05453 05454 if (!(flags & FLAGS_UNSIGNED)) 05455 { 05456 /* Leading sign */ 05457 if (self->current == '+') 05458 { 05459 self->InStream(self, NULL); 05460 } 05461 else if (self->current == '-') 05462 { 05463 self->InStream(self, NULL); 05464 isNegative = TRUE; 05465 } 05466 } 05467 05468 count = self->processed; 05469 05470 if (flags & FLAGS_ALTERNATIVE) 05471 { 05472 switch (base) 05473 { 05474 case NO_BASE: 05475 case BASE_OCTAL: 05476 case BASE_HEX: 05477 case BASE_BINARY: 05478 if (self->current == '0') 05479 { 05480 self->InStream(self, NULL); 05481 if (self->current) 05482 { 05483 if ((base == BASE_HEX) && 05484 (trio_to_upper(self->current) == 'X')) 05485 { 05486 self->InStream(self, NULL); 05487 } 05488 else if ((base == BASE_BINARY) && 05489 (trio_to_upper(self->current) == 'B')) 05490 { 05491 self->InStream(self, NULL); 05492 } 05493 } 05494 } 05495 else 05496 return FALSE; 05497 break; 05498 default: 05499 break; 05500 } 05501 } 05502 05503 while (((width == NO_WIDTH) || (self->processed - count < width)) && 05504 (! ((self->current == EOF) || isspace(self->current)))) 05505 { 05506 if (isascii(self->current)) 05507 { 05508 digit = internalDigitArray[self->current]; 05509 /* Abort if digit is not allowed in the specified base */ 05510 if ((digit == -1) || (digit >= base)) 05511 break; 05512 } 05513 else if (flags & FLAGS_QUOTE) 05514 { 05515 /* Compare with thousands separator */ 05516 for (j = 0; internalThousandSeparator[j] && self->current; j++) 05517 { 05518 if (internalThousandSeparator[j] != self->current) 05519 break; 05520 05521 self->InStream(self, NULL); 05522 } 05523 if (internalThousandSeparator[j]) 05524 break; /* Mismatch */ 05525 else 05526 continue; /* Match */ 05527 } 05528 else 05529 break; 05530 05531 number *= base; 05532 number += digit; 05533 gotNumber = TRUE; /* we need at least one digit */ 05534 05535 self->InStream(self, NULL); 05536 } 05537 05538 /* Was anything read at all? */ 05539 if (!gotNumber) 05540 return FALSE; 05541 05542 if (target) 05543 *target = (isNegative) ? -((trio_intmax_t)number) : number; 05544 return TRUE; 05545 } 05546 05547 /************************************************************************* 05548 * TrioReadChar 05549 */ 05550 TRIO_PRIVATE int 05551 TrioReadChar 05552 TRIO_ARGS4((self, target, flags, width), 05553 trio_class_t *self, 05554 char *target, 05555 trio_flags_t flags, 05556 int width) 05557 { 05558 int i; 05559 char ch; 05560 trio_uintmax_t number; 05561 05562 assert(VALID(self)); 05563 assert(VALID(self->InStream)); 05564 05565 for (i = 0; 05566 (self->current != EOF) && (i < width); 05567 i++) 05568 { 05569 ch = (char)self->current; 05570 self->InStream(self, NULL); 05571 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH)) 05572 { 05573 switch (self->current) 05574 { 05575 case '\\': ch = '\\'; break; 05576 case 'a': ch = '\007'; break; 05577 case 'b': ch = '\b'; break; 05578 case 'f': ch = '\f'; break; 05579 case 'n': ch = '\n'; break; 05580 case 'r': ch = '\r'; break; 05581 case 't': ch = '\t'; break; 05582 case 'v': ch = '\v'; break; 05583 default: 05584 if (isdigit(self->current)) 05585 { 05586 /* Read octal number */ 05587 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL)) 05588 return 0; 05589 ch = (char)number; 05590 } 05591 else if (trio_to_upper(self->current) == 'X') 05592 { 05593 /* Read hexadecimal number */ 05594 self->InStream(self, NULL); 05595 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX)) 05596 return 0; 05597 ch = (char)number; 05598 } 05599 else 05600 { 05601 ch = (char)self->current; 05602 } 05603 break; 05604 } 05605 } 05606 05607 if (target) 05608 target[i] = ch; 05609 } 05610 return i + 1; 05611 } 05612 05613 /************************************************************************* 05614 * TrioReadString 05615 */ 05616 TRIO_PRIVATE BOOLEAN_T 05617 TrioReadString 05618 TRIO_ARGS4((self, target, flags, width), 05619 trio_class_t *self, 05620 char *target, 05621 trio_flags_t flags, 05622 int width) 05623 { 05624 int i; 05625 05626 assert(VALID(self)); 05627 assert(VALID(self->InStream)); 05628 05629 TrioSkipWhitespaces(self); 05630 05631 /* 05632 * Continue until end of string is reached, a whitespace is encountered, 05633 * or width is exceeded 05634 */ 05635 for (i = 0; 05636 ((width == NO_WIDTH) || (i < width)) && 05637 (! ((self->current == EOF) || isspace(self->current))); 05638 i++) 05639 { 05640 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0) 05641 break; /* for */ 05642 } 05643 if (target) 05644 target[i] = NIL; 05645 return TRUE; 05646 } 05647 05648 /************************************************************************* 05649 * TrioReadWideChar 05650 */ 05651 #if TRIO_WIDECHAR 05652 TRIO_PRIVATE int 05653 TrioReadWideChar 05654 TRIO_ARGS4((self, target, flags, width), 05655 trio_class_t *self, 05656 trio_wchar_t *target, 05657 trio_flags_t flags, 05658 int width) 05659 { 05660 int i; 05661 int j; 05662 int size; 05663 int amount = 0; 05664 trio_wchar_t wch; 05665 char buffer[MB_LEN_MAX + 1]; 05666 05667 assert(VALID(self)); 05668 assert(VALID(self->InStream)); 05669 05670 for (i = 0; 05671 (self->current != EOF) && (i < width); 05672 i++) 05673 { 05674 if (isascii(self->current)) 05675 { 05676 if (TrioReadChar(self, buffer, flags, 1) == 0) 05677 return 0; 05678 buffer[1] = NIL; 05679 } 05680 else 05681 { 05682 /* 05683 * Collect a multibyte character, by enlarging buffer until 05684 * it contains a fully legal multibyte character, or the 05685 * buffer is full. 05686 */ 05687 j = 0; 05688 do 05689 { 05690 buffer[j++] = (char)self->current; 05691 buffer[j] = NIL; 05692 self->InStream(self, NULL); 05693 } 05694 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j)); 05695 } 05696 if (target) 05697 { 05698 size = mbtowc(&wch, buffer, sizeof(buffer)); 05699 if (size > 0) 05700 target[i] = wch; 05701 } 05702 amount += size; 05703 self->InStream(self, NULL); 05704 } 05705 return amount; 05706 } 05707 #endif /* TRIO_WIDECHAR */ 05708 05709 /************************************************************************* 05710 * TrioReadWideString 05711 */ 05712 #if TRIO_WIDECHAR 05713 TRIO_PRIVATE BOOLEAN_T 05714 TrioReadWideString 05715 TRIO_ARGS4((self, target, flags, width), 05716 trio_class_t *self, 05717 trio_wchar_t *target, 05718 trio_flags_t flags, 05719 int width) 05720 { 05721 int i; 05722 int size; 05723 05724 assert(VALID(self)); 05725 assert(VALID(self->InStream)); 05726 05727 TrioSkipWhitespaces(self); 05728 05729 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 05730 (void)mblen(NULL, 0); 05731 #endif 05732 05733 /* 05734 * Continue until end of string is reached, a whitespace is encountered, 05735 * or width is exceeded 05736 */ 05737 for (i = 0; 05738 ((width == NO_WIDTH) || (i < width)) && 05739 (! ((self->current == EOF) || isspace(self->current))); 05740 ) 05741 { 05742 size = TrioReadWideChar(self, &target[i], flags, 1); 05743 if (size == 0) 05744 break; /* for */ 05745 05746 i += size; 05747 } 05748 if (target) 05749 target[i] = WCONST('\0'); 05750 return TRUE; 05751 } 05752 #endif /* TRIO_WIDECHAR */ 05753 05754 /************************************************************************* 05755 * TrioReadGroup 05756 * 05757 * FIXME: characterclass does not work with multibyte characters 05758 */ 05759 TRIO_PRIVATE BOOLEAN_T 05760 TrioReadGroup 05761 TRIO_ARGS5((self, target, characterclass, flags, width), 05762 trio_class_t *self, 05763 char *target, 05764 int *characterclass, 05765 trio_flags_t flags, 05766 int width) 05767 { 05768 int ch; 05769 int i; 05770 05771 assert(VALID(self)); 05772 assert(VALID(self->InStream)); 05773 05774 ch = self->current; 05775 for (i = 0; 05776 ((width == NO_WIDTH) || (i < width)) && 05777 (! ((ch == EOF) || 05778 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0)))); 05779 i++) 05780 { 05781 if (target) 05782 target[i] = (char)ch; 05783 self->InStream(self, &ch); 05784 } 05785 05786 if (target) 05787 target[i] = NIL; 05788 return TRUE; 05789 } 05790 05791 /************************************************************************* 05792 * TrioReadDouble 05793 * 05794 * FIXME: 05795 * add long double 05796 * handle base 05797 */ 05798 TRIO_PRIVATE BOOLEAN_T 05799 TrioReadDouble 05800 TRIO_ARGS4((self, target, flags, width), 05801 trio_class_t *self, 05802 trio_pointer_t target, 05803 trio_flags_t flags, 05804 int width) 05805 { 05806 int ch; 05807 char doubleString[512]; 05808 int index = 0; 05809 int start; 05810 int j; 05811 BOOLEAN_T isHex = FALSE; 05812 05813 doubleString[0] = 0; 05814 05815 if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1)) 05816 width = sizeof(doubleString) - 1; 05817 05818 TrioSkipWhitespaces(self); 05819 05820 /* 05821 * Read entire double number from stream. trio_to_double requires 05822 * a string as input, but InStream can be anything, so we have to 05823 * collect all characters. 05824 */ 05825 ch = self->current; 05826 if ((ch == '+') || (ch == '-')) 05827 { 05828 doubleString[index++] = (char)ch; 05829 self->InStream(self, &ch); 05830 width--; 05831 } 05832 05833 start = index; 05834 switch (ch) 05835 { 05836 case 'n': 05837 case 'N': 05838 /* Not-a-number */ 05839 if (index != 0) 05840 break; 05841 /* FALLTHROUGH */ 05842 case 'i': 05843 case 'I': 05844 /* Infinity */ 05845 while (isalpha(ch) && (index - start < width)) 05846 { 05847 doubleString[index++] = (char)ch; 05848 self->InStream(self, &ch); 05849 } 05850 doubleString[index] = NIL; 05851 05852 /* Case insensitive string comparison */ 05853 if (trio_equal(&doubleString[start], INFINITE_UPPER) || 05854 trio_equal(&doubleString[start], LONG_INFINITE_UPPER)) 05855 { 05856 if (flags & FLAGS_LONGDOUBLE) 05857 { 05858 if ((start == 1) && (doubleString[0] == '-')) 05859 { 05860 *((trio_long_double_t *)target) = trio_ninf(); 05861 } 05862 else 05863 { 05864 *((trio_long_double_t *)target) = trio_pinf(); 05865 } 05866 } 05867 else 05868 { 05869 if ((start == 1) && (doubleString[0] == '-')) 05870 { 05871 *((double *)target) = trio_ninf(); 05872 } 05873 else 05874 { 05875 *((double *)target) = trio_pinf(); 05876 } 05877 } 05878 return TRUE; 05879 } 05880 if (trio_equal(doubleString, NAN_UPPER)) 05881 { 05882 /* NaN must not have a preceeding + nor - */ 05883 if (flags & FLAGS_LONGDOUBLE) 05884 { 05885 *((trio_long_double_t *)target) = trio_nan(); 05886 } 05887 else 05888 { 05889 *((double *)target) = trio_nan(); 05890 } 05891 return TRUE; 05892 } 05893 return FALSE; 05894 05895 case '0': 05896 doubleString[index++] = (char)ch; 05897 self->InStream(self, &ch); 05898 if (trio_to_upper(ch) == 'X') 05899 { 05900 isHex = TRUE; 05901 doubleString[index++] = (char)ch; 05902 self->InStream(self, &ch); 05903 } 05904 break; 05905 05906 default: 05907 break; 05908 } 05909 05910 while ((ch != EOF) && (index - start < width)) 05911 { 05912 /* Integer part */ 05913 if (isHex ? isxdigit(ch) : isdigit(ch)) 05914 { 05915 doubleString[index++] = (char)ch; 05916 self->InStream(self, &ch); 05917 } 05918 else if (flags & FLAGS_QUOTE) 05919 { 05920 /* Compare with thousands separator */ 05921 for (j = 0; internalThousandSeparator[j] && self->current; j++) 05922 { 05923 if (internalThousandSeparator[j] != self->current) 05924 break; 05925 05926 self->InStream(self, &ch); 05927 } 05928 if (internalThousandSeparator[j]) 05929 break; /* Mismatch */ 05930 else 05931 continue; /* Match */ 05932 } 05933 else 05934 break; /* while */ 05935 } 05936 if (ch == '.') 05937 { 05938 /* Decimal part */ 05939 doubleString[index++] = (char)ch; 05940 self->InStream(self, &ch); 05941 while ((isHex ? isxdigit(ch) : isdigit(ch)) && 05942 (index - start < width)) 05943 { 05944 doubleString[index++] = (char)ch; 05945 self->InStream(self, &ch); 05946 } 05947 if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E')) 05948 { 05949 /* Exponent */ 05950 doubleString[index++] = (char)ch; 05951 self->InStream(self, &ch); 05952 if ((ch == '+') || (ch == '-')) 05953 { 05954 doubleString[index++] = (char)ch; 05955 self->InStream(self, &ch); 05956 } 05957 while (isdigit(ch) && (index - start < width)) 05958 { 05959 doubleString[index++] = (char)ch; 05960 self->InStream(self, &ch); 05961 } 05962 } 05963 } 05964 05965 if ((index == start) || (*doubleString == NIL)) 05966 return FALSE; 05967 05968 doubleString[index] = 0; 05969 05970 if (flags & FLAGS_LONGDOUBLE) 05971 { 05972 *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL); 05973 } 05974 else 05975 { 05976 *((double *)target) = trio_to_double(doubleString, NULL); 05977 } 05978 return TRUE; 05979 } 05980 05981 /************************************************************************* 05982 * TrioReadPointer 05983 */ 05984 TRIO_PRIVATE BOOLEAN_T 05985 TrioReadPointer 05986 TRIO_ARGS3((self, target, flags), 05987 trio_class_t *self, 05988 trio_pointer_t *target, 05989 trio_flags_t flags) 05990 { 05991 trio_uintmax_t number; 05992 char buffer[sizeof(internalNullString)]; 05993 05994 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING); 05995 05996 if (TrioReadNumber(self, 05997 &number, 05998 flags, 05999 POINTER_WIDTH, 06000 BASE_HEX)) 06001 { 06002 /* 06003 * The strange assignment of number is a workaround for a compiler 06004 * warning 06005 */ 06006 if (target) 06007 *target = (char *)0 + number; 06008 return TRUE; 06009 } 06010 else if (TrioReadString(self, 06011 (flags & FLAGS_IGNORE) 06012 ? NULL 06013 : buffer, 06014 0, 06015 sizeof(internalNullString) - 1)) 06016 { 06017 if (trio_equal_case(buffer, internalNullString)) 06018 { 06019 if (target) 06020 *target = NULL; 06021 return TRUE; 06022 } 06023 } 06024 return FALSE; 06025 } 06026 06027 /************************************************************************* 06028 * TrioScanProcess 06029 */ 06030 TRIO_PRIVATE int 06031 TrioScanProcess 06032 TRIO_ARGS3((data, format, parameters), 06033 trio_class_t *data, 06034 TRIO_CONST char *format, 06035 trio_parameter_t *parameters) 06036 { 06037 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 06038 int charlen; 06039 int cnt; 06040 #endif 06041 int assignment; 06042 int ch; 06043 int index; /* Index of format string */ 06044 int i; /* Index of current parameter */ 06045 trio_flags_t flags; 06046 int width; 06047 int base; 06048 trio_pointer_t pointer; 06049 06050 assignment = 0; 06051 i = 0; 06052 index = 0; 06053 data->InStream(data, &ch); 06054 06055 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 06056 (void)mblen(NULL, 0); 06057 #endif 06058 06059 while (format[index]) 06060 { 06061 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) 06062 if (! isascii(format[index])) 06063 { 06064 charlen = mblen(&format[index], MB_LEN_MAX); 06065 if (charlen != -1) 06066 { 06067 /* Compare multibyte characters in format string */ 06068 for (cnt = 0; cnt < charlen - 1; cnt++) 06069 { 06070 if (ch != format[index + cnt]) 06071 { 06072 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 06073 } 06074 data->InStream(data, &ch); 06075 } 06076 continue; /* while characters left in formatting string */ 06077 } 06078 } 06079 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ 06080 06081 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT)) 06082 { 06083 return (assignment > 0) ? assignment : EOF; 06084 } 06085 06086 if (CHAR_IDENTIFIER == format[index]) 06087 { 06088 if (CHAR_IDENTIFIER == format[index + 1]) 06089 { 06090 /* Two % in format matches one % in input stream */ 06091 if (CHAR_IDENTIFIER == ch) 06092 { 06093 data->InStream(data, &ch); 06094 index += 2; 06095 continue; /* while format chars left */ 06096 } 06097 else 06098 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 06099 } 06100 06101 /* Skip the parameter entries */ 06102 while (parameters[i].type == FORMAT_PARAMETER) 06103 i++; 06104 06105 flags = parameters[i].flags; 06106 /* Find width */ 06107 width = parameters[i].width; 06108 if (flags & FLAGS_WIDTH_PARAMETER) 06109 { 06110 /* Get width from parameter list */ 06111 width = (int)parameters[width].data.number.as_signed; 06112 } 06113 /* Find base */ 06114 base = parameters[i].base; 06115 if (flags & FLAGS_BASE_PARAMETER) 06116 { 06117 /* Get base from parameter list */ 06118 base = (int)parameters[base].data.number.as_signed; 06119 } 06120 06121 switch (parameters[i].type) 06122 { 06123 case FORMAT_INT: 06124 { 06125 trio_uintmax_t number; 06126 06127 if (0 == base) 06128 base = BASE_DECIMAL; 06129 06130 if (!TrioReadNumber(data, 06131 &number, 06132 flags, 06133 width, 06134 base)) 06135 return assignment; 06136 06137 if (!(flags & FLAGS_IGNORE)) 06138 { 06139 assignment++; 06140 06141 pointer = parameters[i].data.pointer; 06142 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) 06143 if (flags & FLAGS_SIZE_T) 06144 *(size_t *)pointer = (size_t)number; 06145 else 06146 #endif 06147 #if defined(QUALIFIER_PTRDIFF_T) 06148 if (flags & FLAGS_PTRDIFF_T) 06149 *(ptrdiff_t *)pointer = (ptrdiff_t)number; 06150 else 06151 #endif 06152 #if defined(QUALIFIER_INTMAX_T) 06153 if (flags & FLAGS_INTMAX_T) 06154 *(trio_intmax_t *)pointer = (trio_intmax_t)number; 06155 else 06156 #endif 06157 if (flags & FLAGS_QUAD) 06158 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number; 06159 else if (flags & FLAGS_LONG) 06160 *(long int *)pointer = (long int)number; 06161 else if (flags & FLAGS_SHORT) 06162 *(short int *)pointer = (short int)number; 06163 else 06164 *(int *)pointer = (int)number; 06165 } 06166 } 06167 break; /* FORMAT_INT */ 06168 06169 case FORMAT_STRING: 06170 #if TRIO_WIDECHAR 06171 if (flags & FLAGS_WIDECHAR) 06172 { 06173 if (!TrioReadWideString(data, 06174 (flags & FLAGS_IGNORE) 06175 ? NULL 06176 : parameters[i].data.wstring, 06177 flags, 06178 width)) 06179 return assignment; 06180 } 06181 else 06182 #endif 06183 { 06184 if (!TrioReadString(data, 06185 (flags & FLAGS_IGNORE) 06186 ? NULL 06187 : parameters[i].data.string, 06188 flags, 06189 width)) 06190 return assignment; 06191 } 06192 if (!(flags & FLAGS_IGNORE)) 06193 assignment++; 06194 break; /* FORMAT_STRING */ 06195 06196 case FORMAT_DOUBLE: 06197 { 06198 trio_pointer_t pointer; 06199 06200 if (flags & FLAGS_IGNORE) 06201 { 06202 pointer = NULL; 06203 } 06204 else 06205 { 06206 pointer = (flags & FLAGS_LONGDOUBLE) 06207 ? (trio_pointer_t)parameters[i].data.longdoublePointer 06208 : (trio_pointer_t)parameters[i].data.doublePointer; 06209 } 06210 if (!TrioReadDouble(data, pointer, flags, width)) 06211 { 06212 return assignment; 06213 } 06214 if (!(flags & FLAGS_IGNORE)) 06215 { 06216 assignment++; 06217 } 06218 break; /* FORMAT_DOUBLE */ 06219 } 06220 case FORMAT_GROUP: 06221 { 06222 int characterclass[MAX_CHARACTER_CLASS + 1]; 06223 int rc; 06224 06225 /* Skip over modifiers */ 06226 while (format[index] != SPECIFIER_GROUP) 06227 { 06228 index++; 06229 } 06230 /* Skip over group specifier */ 06231 index++; 06232 06233 memset(characterclass, 0, sizeof(characterclass)); 06234 rc = TrioGetCharacterClass(format, 06235 &index, 06236 &flags, 06237 characterclass); 06238 if (rc < 0) 06239 return rc; 06240 06241 if (!TrioReadGroup(data, 06242 (flags & FLAGS_IGNORE) 06243 ? NULL 06244 : parameters[i].data.string, 06245 characterclass, 06246 flags, 06247 parameters[i].width)) 06248 return assignment; 06249 if (!(flags & FLAGS_IGNORE)) 06250 assignment++; 06251 } 06252 break; /* FORMAT_GROUP */ 06253 06254 case FORMAT_COUNT: 06255 pointer = parameters[i].data.pointer; 06256 if (NULL != pointer) 06257 { 06258 int count = data->committed; 06259 if (ch != EOF) 06260 count--; /* a character is read, but is not consumed yet */ 06261 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) 06262 if (flags & FLAGS_SIZE_T) 06263 *(size_t *)pointer = (size_t)count; 06264 else 06265 #endif 06266 #if defined(QUALIFIER_PTRDIFF_T) 06267 if (flags & FLAGS_PTRDIFF_T) 06268 *(ptrdiff_t *)pointer = (ptrdiff_t)count; 06269 else 06270 #endif 06271 #if defined(QUALIFIER_INTMAX_T) 06272 if (flags & FLAGS_INTMAX_T) 06273 *(trio_intmax_t *)pointer = (trio_intmax_t)count; 06274 else 06275 #endif 06276 if (flags & FLAGS_QUAD) 06277 { 06278 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count; 06279 } 06280 else if (flags & FLAGS_LONG) 06281 { 06282 *(long int *)pointer = (long int)count; 06283 } 06284 else if (flags & FLAGS_SHORT) 06285 { 06286 *(short int *)pointer = (short int)count; 06287 } 06288 else 06289 { 06290 *(int *)pointer = (int)count; 06291 } 06292 } 06293 break; /* FORMAT_COUNT */ 06294 06295 case FORMAT_CHAR: 06296 #if TRIO_WIDECHAR 06297 if (flags & FLAGS_WIDECHAR) 06298 { 06299 if (TrioReadWideChar(data, 06300 (flags & FLAGS_IGNORE) 06301 ? NULL 06302 : parameters[i].data.wstring, 06303 flags, 06304 (width == NO_WIDTH) ? 1 : width) == 0) 06305 return assignment; 06306 } 06307 else 06308 #endif 06309 { 06310 if (TrioReadChar(data, 06311 (flags & FLAGS_IGNORE) 06312 ? NULL 06313 : parameters[i].data.string, 06314 flags, 06315 (width == NO_WIDTH) ? 1 : width) == 0) 06316 return assignment; 06317 } 06318 if (!(flags & FLAGS_IGNORE)) 06319 assignment++; 06320 break; /* FORMAT_CHAR */ 06321 06322 case FORMAT_POINTER: 06323 if (!TrioReadPointer(data, 06324 (flags & FLAGS_IGNORE) 06325 ? NULL 06326 : (trio_pointer_t *)parameters[i].data.pointer, 06327 flags)) 06328 return assignment; 06329 if (!(flags & FLAGS_IGNORE)) 06330 assignment++; 06331 break; /* FORMAT_POINTER */ 06332 06333 case FORMAT_PARAMETER: 06334 break; /* FORMAT_PARAMETER */ 06335 06336 default: 06337 return TRIO_ERROR_RETURN(TRIO_EINVAL, index); 06338 } 06339 ch = data->current; 06340 index = parameters[i].indexAfterSpecifier; 06341 i++; 06342 } 06343 else /* Not an % identifier */ 06344 { 06345 if (isspace((int)format[index])) 06346 { 06347 /* Whitespaces may match any amount of whitespaces */ 06348 ch = TrioSkipWhitespaces(data); 06349 } 06350 else if (ch == format[index]) 06351 { 06352 data->InStream(data, &ch); 06353 } 06354 else 06355 return assignment; 06356 06357 index++; 06358 } 06359 } 06360 return assignment; 06361 } 06362 06363 /************************************************************************* 06364 * TrioScan 06365 */ 06366 TRIO_PRIVATE int 06367 TrioScan 06368 TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray), 06369 trio_pointer_t source, 06370 size_t sourceSize, 06371 void (*InStream) TRIO_PROTO((trio_class_t *, int *)), 06372 TRIO_CONST char *format, 06373 va_list *arglist, 06374 trio_pointer_t *argarray) 06375 { 06376 int status; 06377 trio_parameter_t parameters[MAX_PARAMETERS]; 06378 trio_class_t data; 06379 06380 assert(VALID(InStream)); 06381 assert(VALID(format)); 06382 06383 memset(&data, 0, sizeof(data)); 06384 data.InStream = InStream; 06385 data.location = (trio_pointer_t)source; 06386 data.max = sourceSize; 06387 data.error = 0; 06388 06389 #if defined(USE_LOCALE) 06390 if (NULL == internalLocaleValues) 06391 { 06392 TrioSetLocale(); 06393 } 06394 #endif 06395 06396 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray); 06397 if (status < 0) 06398 return status; 06399 06400 status = TrioScanProcess(&data, format, parameters); 06401 if (data.error != 0) 06402 { 06403 status = data.error; 06404 } 06405 return status; 06406 } 06407 06408 /************************************************************************* 06409 * TrioInStreamFile 06410 */ 06411 TRIO_PRIVATE void 06412 TrioInStreamFile 06413 TRIO_ARGS2((self, intPointer), 06414 trio_class_t *self, 06415 int *intPointer) 06416 { 06417 FILE *file = (FILE *)self->location; 06418 06419 assert(VALID(self)); 06420 assert(VALID(file)); 06421 06422 self->current = fgetc(file); 06423 if (self->current == EOF) 06424 { 06425 self->error = (ferror(file)) 06426 ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0) 06427 : TRIO_ERROR_RETURN(TRIO_EOF, 0); 06428 } 06429 else 06430 { 06431 self->processed++; 06432 self->committed++; 06433 } 06434 06435 if (VALID(intPointer)) 06436 { 06437 *intPointer = self->current; 06438 } 06439 } 06440 06441 /************************************************************************* 06442 * TrioInStreamFileDescriptor 06443 */ 06444 TRIO_PRIVATE void 06445 TrioInStreamFileDescriptor 06446 TRIO_ARGS2((self, intPointer), 06447 trio_class_t *self, 06448 int *intPointer) 06449 { 06450 int fd = *((int *)self->location); 06451 int size; 06452 unsigned char input; 06453 06454 assert(VALID(self)); 06455 06456 size = read(fd, &input, sizeof(char)); 06457 if (size == -1) 06458 { 06459 self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); 06460 self->current = EOF; 06461 } 06462 else 06463 { 06464 self->current = (size == 0) ? EOF : input; 06465 } 06466 if (self->current != EOF) 06467 { 06468 self->committed++; 06469 self->processed++; 06470 } 06471 06472 if (VALID(intPointer)) 06473 { 06474 *intPointer = self->current; 06475 } 06476 } 06477 06478 /************************************************************************* 06479 * TrioInStreamCustom 06480 */ 06481 TRIO_PRIVATE void 06482 TrioInStreamCustom 06483 TRIO_ARGS2((self, intPointer), 06484 trio_class_t *self, 06485 int *intPointer) 06486 { 06487 trio_custom_t *data; 06488 06489 assert(VALID(self)); 06490 assert(VALID(self->location)); 06491 06492 data = (trio_custom_t *)self->location; 06493 06494 self->current = (data->stream.in == NULL) 06495 ? NIL 06496 : (data->stream.in)(data->closure); 06497 06498 if (self->current == NIL) 06499 { 06500 self->current = EOF; 06501 } 06502 else 06503 { 06504 self->processed++; 06505 self->committed++; 06506 } 06507 06508 if (VALID(intPointer)) 06509 { 06510 *intPointer = self->current; 06511 } 06512 } 06513 06514 /************************************************************************* 06515 * TrioInStreamString 06516 */ 06517 TRIO_PRIVATE void 06518 TrioInStreamString 06519 TRIO_ARGS2((self, intPointer), 06520 trio_class_t *self, 06521 int *intPointer) 06522 { 06523 unsigned char **buffer; 06524 06525 assert(VALID(self)); 06526 assert(VALID(self->location)); 06527 06528 buffer = (unsigned char **)self->location; 06529 self->current = (*buffer)[0]; 06530 if (self->current == NIL) 06531 { 06532 self->current = EOF; 06533 } 06534 else 06535 { 06536 (*buffer)++; 06537 self->processed++; 06538 self->committed++; 06539 } 06540 06541 if (VALID(intPointer)) 06542 { 06543 *intPointer = self->current; 06544 } 06545 } 06546 06547 /************************************************************************* 06548 * 06549 * Formatted scanning functions 06550 * 06551 ************************************************************************/ 06552 06553 #if defined(TRIO_DOCUMENTATION) 06554 # include "doc/doc_scanf.h" 06555 #endif 06556 06560 /************************************************************************* 06561 * scanf 06562 */ 06563 06571 TRIO_PUBLIC int 06572 trio_scanf 06573 TRIO_VARGS2((format, va_alist), 06574 TRIO_CONST char *format, 06575 TRIO_VA_DECL) 06576 { 06577 int status; 06578 va_list args; 06579 06580 assert(VALID(format)); 06581 06582 TRIO_VA_START(args, format); 06583 status = TrioScan((trio_pointer_t)stdin, 0, 06584 TrioInStreamFile, 06585 format, &args, NULL); 06586 TRIO_VA_END(args); 06587 return status; 06588 } 06589 06590 TRIO_PUBLIC int 06591 trio_vscanf 06592 TRIO_ARGS2((format, args), 06593 TRIO_CONST char *format, 06594 va_list args) 06595 { 06596 assert(VALID(format)); 06597 06598 return TrioScan((trio_pointer_t)stdin, 0, 06599 TrioInStreamFile, 06600 format, &args, NULL); 06601 } 06602 06603 TRIO_PUBLIC int 06604 trio_scanfv 06605 TRIO_ARGS2((format, args), 06606 TRIO_CONST char *format, 06607 trio_pointer_t *args) 06608 { 06609 assert(VALID(format)); 06610 06611 return TrioScan((trio_pointer_t)stdin, 0, 06612 TrioInStreamFile, 06613 format, NULL, args); 06614 } 06615 06616 /************************************************************************* 06617 * fscanf 06618 */ 06619 TRIO_PUBLIC int 06620 trio_fscanf 06621 TRIO_VARGS3((file, format, va_alist), 06622 FILE *file, 06623 TRIO_CONST char *format, 06624 TRIO_VA_DECL) 06625 { 06626 int status; 06627 va_list args; 06628 06629 assert(VALID(file)); 06630 assert(VALID(format)); 06631 06632 TRIO_VA_START(args, format); 06633 status = TrioScan((trio_pointer_t)file, 0, 06634 TrioInStreamFile, 06635 format, &args, NULL); 06636 TRIO_VA_END(args); 06637 return status; 06638 } 06639 06640 TRIO_PUBLIC int 06641 trio_vfscanf 06642 TRIO_ARGS3((file, format, args), 06643 FILE *file, 06644 TRIO_CONST char *format, 06645 va_list args) 06646 { 06647 assert(VALID(file)); 06648 assert(VALID(format)); 06649 06650 return TrioScan((trio_pointer_t)file, 0, 06651 TrioInStreamFile, 06652 format, &args, NULL); 06653 } 06654 06655 TRIO_PUBLIC int 06656 trio_fscanfv 06657 TRIO_ARGS3((file, format, args), 06658 FILE *file, 06659 TRIO_CONST char *format, 06660 trio_pointer_t *args) 06661 { 06662 assert(VALID(file)); 06663 assert(VALID(format)); 06664 06665 return TrioScan((trio_pointer_t)file, 0, 06666 TrioInStreamFile, 06667 format, NULL, args); 06668 } 06669 06670 /************************************************************************* 06671 * dscanf 06672 */ 06673 TRIO_PUBLIC int 06674 trio_dscanf 06675 TRIO_VARGS3((fd, format, va_alist), 06676 int fd, 06677 TRIO_CONST char *format, 06678 TRIO_VA_DECL) 06679 { 06680 int status; 06681 va_list args; 06682 06683 assert(VALID(format)); 06684 06685 TRIO_VA_START(args, format); 06686 status = TrioScan((trio_pointer_t)&fd, 0, 06687 TrioInStreamFileDescriptor, 06688 format, &args, NULL); 06689 TRIO_VA_END(args); 06690 return status; 06691 } 06692 06693 TRIO_PUBLIC int 06694 trio_vdscanf 06695 TRIO_ARGS3((fd, format, args), 06696 int fd, 06697 TRIO_CONST char *format, 06698 va_list args) 06699 { 06700 assert(VALID(format)); 06701 06702 return TrioScan((trio_pointer_t)&fd, 0, 06703 TrioInStreamFileDescriptor, 06704 format, &args, NULL); 06705 } 06706 06707 TRIO_PUBLIC int 06708 trio_dscanfv 06709 TRIO_ARGS3((fd, format, args), 06710 int fd, 06711 TRIO_CONST char *format, 06712 trio_pointer_t *args) 06713 { 06714 assert(VALID(format)); 06715 06716 return TrioScan((trio_pointer_t)&fd, 0, 06717 TrioInStreamFileDescriptor, 06718 format, NULL, args); 06719 } 06720 06721 /************************************************************************* 06722 * cscanf 06723 */ 06724 TRIO_PUBLIC int 06725 trio_cscanf 06726 TRIO_VARGS4((stream, closure, format, va_alist), 06727 trio_instream_t stream, 06728 trio_pointer_t closure, 06729 TRIO_CONST char *format, 06730 TRIO_VA_DECL) 06731 { 06732 int status; 06733 va_list args; 06734 trio_custom_t data; 06735 06736 assert(VALID(stream)); 06737 assert(VALID(format)); 06738 06739 TRIO_VA_START(args, format); 06740 data.stream.in = stream; 06741 data.closure = closure; 06742 status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL); 06743 TRIO_VA_END(args); 06744 return status; 06745 } 06746 06747 TRIO_PUBLIC int 06748 trio_vcscanf 06749 TRIO_ARGS4((stream, closure, format, args), 06750 trio_instream_t stream, 06751 trio_pointer_t closure, 06752 TRIO_CONST char *format, 06753 va_list args) 06754 { 06755 trio_custom_t data; 06756 06757 assert(VALID(stream)); 06758 assert(VALID(format)); 06759 06760 data.stream.in = stream; 06761 data.closure = closure; 06762 return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL); 06763 } 06764 06765 TRIO_PUBLIC int 06766 trio_cscanfv 06767 TRIO_ARGS4((stream, closure, format, args), 06768 trio_instream_t stream, 06769 trio_pointer_t closure, 06770 TRIO_CONST char *format, 06771 trio_pointer_t *args) 06772 { 06773 trio_custom_t data; 06774 06775 assert(VALID(stream)); 06776 assert(VALID(format)); 06777 06778 data.stream.in = stream; 06779 data.closure = closure; 06780 return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args); 06781 } 06782 06783 /************************************************************************* 06784 * sscanf 06785 */ 06786 TRIO_PUBLIC int 06787 trio_sscanf 06788 TRIO_VARGS3((buffer, format, va_alist), 06789 TRIO_CONST char *buffer, 06790 TRIO_CONST char *format, 06791 TRIO_VA_DECL) 06792 { 06793 int status; 06794 va_list args; 06795 06796 assert(VALID(buffer)); 06797 assert(VALID(format)); 06798 06799 TRIO_VA_START(args, format); 06800 status = TrioScan((trio_pointer_t)&buffer, 0, 06801 TrioInStreamString, 06802 format, &args, NULL); 06803 TRIO_VA_END(args); 06804 return status; 06805 } 06806 06807 TRIO_PUBLIC int 06808 trio_vsscanf 06809 TRIO_ARGS3((buffer, format, args), 06810 TRIO_CONST char *buffer, 06811 TRIO_CONST char *format, 06812 va_list args) 06813 { 06814 assert(VALID(buffer)); 06815 assert(VALID(format)); 06816 06817 return TrioScan((trio_pointer_t)&buffer, 0, 06818 TrioInStreamString, 06819 format, &args, NULL); 06820 } 06821 06822 TRIO_PUBLIC int 06823 trio_sscanfv 06824 TRIO_ARGS3((buffer, format, args), 06825 TRIO_CONST char *buffer, 06826 TRIO_CONST char *format, 06827 trio_pointer_t *args) 06828 { 06829 assert(VALID(buffer)); 06830 assert(VALID(format)); 06831 06832 return TrioScan((trio_pointer_t)&buffer, 0, 06833 TrioInStreamString, 06834 format, NULL, args); 06835 } 06836 06839 /************************************************************************* 06840 * trio_strerror 06841 */ 06842 TRIO_PUBLIC TRIO_CONST char * 06843 trio_strerror 06844 TRIO_ARGS1((errorcode), 06845 int errorcode) 06846 { 06847 /* Textual versions of the error codes */ 06848 switch (TRIO_ERROR_CODE(errorcode)) 06849 { 06850 case TRIO_EOF: 06851 return "End of file"; 06852 case TRIO_EINVAL: 06853 return "Invalid argument"; 06854 case TRIO_ETOOMANY: 06855 return "Too many arguments"; 06856 case TRIO_EDBLREF: 06857 return "Double reference"; 06858 case TRIO_EGAP: 06859 return "Reference gap"; 06860 case TRIO_ENOMEM: 06861 return "Out of memory"; 06862 case TRIO_ERANGE: 06863 return "Invalid range"; 06864 case TRIO_ECUSTOM: 06865 return "Custom error"; 06866 default: 06867 return "Unknown"; 06868 } 06869 } Generated on Sun May 27 2012 04:34:44 for ReactOS by
1.7.6.1
|