ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sun May 27 2012 04:34:44 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.