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