2001-03-27 16:47:33 +04:00
/*************************************************************************
*
* $ Id $
*
* Copyright ( C ) 1998 Bjorn Reese and Daniel Stenberg .
*
* Permission to use , copy , modify , and distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , WITHOUT LIMITATION , THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE . THE AUTHORS AND
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
2001-04-21 20:57:29 +04:00
* A note to trio contributors :
*
2001-03-27 16:47:33 +04:00
* Avoid heap allocation at all costs to ensure that the trio functions
* are async - safe . The exceptions are the printf / fprintf functions , which
* uses fputc , and the asprintf functions and the < alloc > modifier , which
* by design are required to allocate form the heap .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2001-04-21 20:57:29 +04:00
* TODO :
2001-03-27 16:47:33 +04:00
* - Scan is probably too permissive about its modifiers .
* - C escapes in % # [ ] ?
2001-04-21 20:57:29 +04:00
* - C99 support has not been properly tested .
2001-03-27 16:47:33 +04:00
* - Multibyte characters ( done for format parsing , except scan groups )
* - Complex numbers ? ( C99 _Complex )
* - Boolean values ? ( C99 _Bool )
* - C99 NaN ( n - char - sequence ) missing
* - Should we support the GNU % a alloc modifier ? GNU has an ugly hack
* for % a , because C99 used % a for other purposes . If specified as
* % as or % a [ it is interpreted as the alloc modifier , otherwise as
* the C99 hex - float . This means that you cannot scan % as as a hex - float
* immediately followed by an ' s ' .
2001-06-05 16:46:33 +04:00
* - Scanning of collating symbols .
2001-03-27 16:47:33 +04:00
*/
static const char rcsid [ ] = " @(#)$Id$ " ;
2001-06-05 16:46:33 +04:00
/*************************************************************************
* Trio include files
*/
# include "trio.h"
# include "triop.h"
# include "strio.h"
/*
* Encode the error code and the position . This is decoded
* with TRIO_ERROR_CODE and TRIO_ERROR_POSITION .
*/
# if TRIO_ERRORS
# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
# else
# define TRIO_ERROR_RETURN(x,y) (-1)
# endif
/*************************************************************************
* Platform and compiler support detection
*/
# if defined(unix) || defined(__xlC__) || defined(_AIX) || defined(__QNX__)
2001-03-27 16:47:33 +04:00
# define PLATFORM_UNIX
# elif defined(AMIGA) && defined(__GNUC__)
# define PLATFORM_UNIX
2001-06-05 16:46:33 +04:00
# elif defined(WIN32) || defined(_WIN32) || defined(_MSC_VER)
# define PLATFORM_WIN32
# define TRIO_MSVC_5 1100
# endif
# if defined(__STDC__) && defined(__STDC_VERSION__)
# if (__STDC_VERSION__ >= 199409L)
# define TRIO_COMPILER_SUPPORTS_ISO94
# endif
# if (__STDC_VERSION__ >= 199901L)
# define TRIO_COMPILER_SUPPORTS_C99
# endif
# endif
# if defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED)
# define TRIO_COMPILER_SUPPORTS_UNIX98
2001-03-27 16:47:33 +04:00
# endif
2001-06-05 16:46:33 +04:00
# if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
# if !defined(MB_LEN_MAX)
# define MB_LEN_MAX 6
# endif
# endif
2001-03-27 16:47:33 +04:00
/*************************************************************************
2001-06-05 16:46:33 +04:00
* Generic definitions
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
# if !(defined(DEBUG) || defined(NDEBUG))
2001-04-21 20:57:29 +04:00
# define NDEBUG
# endif
# include <assert.h>
2001-03-27 16:47:33 +04:00
# include <ctype.h>
2001-06-05 16:46:33 +04:00
# if !defined(TRIO_COMPILER_SUPPORTS_C99)
# define isblank(x) (((x)==32) || ((x)==9))
# endif
2001-03-27 16:47:33 +04:00
# include <math.h>
# include <limits.h>
# include <float.h>
# include <stdarg.h>
2001-06-05 16:46:33 +04:00
# include <stddef.h>
2001-03-27 16:47:33 +04:00
# include <errno.h>
# ifndef NULL
# define NULL 0
# endif
# define NIL ((char)0)
2001-06-05 16:46:33 +04:00
# ifndef FALSE
# define FALSE (1 == 0)
# define TRUE (! FALSE)
2001-03-27 16:47:33 +04:00
# endif
2001-06-05 16:46:33 +04:00
# define BOOLEAN_T int
2001-03-27 16:47:33 +04:00
/* mincore() can be used for debugging purposes */
# define VALID(x) (NULL != (x))
2001-06-05 16:46:33 +04:00
/* xlC crashes on log10(0) */
# define guarded_log10(x) (((x) == 0.0) ? -HUGE_VAL : log10(x))
# define guarded_log16(x) (guarded_log10(x) / log10(16.0))
/*************************************************************************
* Platform specific definitions
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
# if defined(PLATFORM_UNIX)
# include <unistd.h>
# include <signal.h>
# include <locale.h>
# define USE_LOCALE
# endif /* PLATFORM_UNIX */
# if defined(PLATFORM_WIN32)
# include <io.h>
# define read _read
# define write _write
# endif /* PLATFORM_WIN32 */
# if TRIO_WIDECHAR
# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
# include <wchar.h>
# include <wctype.h>
# else
typedef char wchar_t ;
typedef int wint_t ;
# define WEOF EOF
# define iswalnum(x) isalnum(x)
# define iswalpha(x) isalpha(x)
# define iswblank(x) isblank(x)
# define iswcntrl(x) iscntrl(x)
# define iswdigit(x) isdigit(x)
# define iswgraph(x) isgraph(x)
# define iswlower(x) islower(x)
# define iswprint(x) isprint(x)
# define iswpunct(x) ispunct(x)
# define iswspace(x) isspace(x)
# define iswupper(x) isupper(x)
# define iswxdigit(x) isxdigit(x)
# endif
2001-03-27 16:47:33 +04:00
# endif
2001-06-05 16:46:33 +04:00
2001-03-27 16:47:33 +04:00
/*************************************************************************
2001-06-05 16:46:33 +04:00
* Compiler dependent definitions
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
/* Support for long long */
# ifndef __cplusplus
# if !defined(USE_LONGLONG)
# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
# define USE_LONGLONG
# elif defined(__SUNPRO_C)
# define USE_LONGLONG
# elif defined(_LONG_LONG) || defined(_LONGLONG)
# define USE_LONGLONG
# endif
2001-03-27 16:47:33 +04:00
# endif
# endif
/* The extra long numbers */
# if defined(USE_LONGLONG)
2001-06-05 16:46:33 +04:00
typedef signed long long int trio_longlong_t ;
typedef unsigned long long int trio_ulonglong_t ;
# elif defined(_MSC_VER)
# if (_MSC_VER >= TRIO_MSVC_5)
typedef signed __int64 trio_longlong_t ;
typedef unsigned __int64 trio_ulonglong_t ;
# else
typedef signed long int trio_longlong_t ;
typedef unsigned long int trio_ulonglong_t ;
# endif
# else
typedef signed long int trio_longlong_t ;
typedef unsigned long int trio_ulonglong_t ;
# endif
/* Maximal and fixed integer types */
# if defined(TRIO_COMPILER_SUPPORTS_C99)
# include <stdint.h>
typedef intmax_t trio_intmax_t ;
typedef uintmax_t trio_uintmax_t ;
typedef int8_t trio_int8_t ;
typedef int16_t trio_int16_t ;
typedef int32_t trio_int32_t ;
typedef int64_t trio_int64_t ;
# elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
# include <inttypes.h>
typedef intmax_t trio_intmax_t ;
typedef uintmax_t trio_uintmax_t ;
typedef int8_t trio_int8_t ;
typedef int16_t trio_int16_t ;
typedef int32_t trio_int32_t ;
typedef int64_t trio_int64_t ;
# elif defined(_MSC_VER) && (_MSC_VER >= TRIO_MSVC_5)
typedef trio_longlong_t trio_intmax_t ;
typedef trio_ulonglong_t trio_uintmax_t ;
typedef __int8 trio_int8_t ;
typedef __int16 trio_int16_t ;
typedef __int32 trio_int32_t ;
typedef __int64 trio_int64_t ;
2001-03-27 16:47:33 +04:00
# else
2001-06-05 16:46:33 +04:00
typedef trio_longlong_t trio_intmax_t ;
typedef trio_ulonglong_t trio_uintmax_t ;
# if defined(TRIO_INT8_T)
typedef TRIO_INT8_T trio_int8_t ;
# else
typedef signed char trio_int8_t ;
# endif
# if defined(TRIO_INT16_T)
typedef TRIO_INT16_T trio_int16_t ;
# else
typedef signed short trio_int16_t ;
# endif
# if defined(TRIO_INT32_T)
typedef TRIO_INT32_T trio_int32_t ;
# else
typedef signed int trio_int32_t ;
# endif
# if defined(TRIO_INT64_T)
typedef TRIO_INT64_T trio_int64_t ;
# else
typedef trio_longlong_t trio_int64_t ;
# endif
2001-03-27 16:47:33 +04:00
# endif
2001-06-05 16:46:33 +04:00
/*************************************************************************
* Internal definitions
*/
/* Long double sizes */
# ifdef LDBL_DIG
# define MAX_MANTISSA_DIGITS LDBL_DIG
# define MAX_EXPONENT_DIGITS 4
2001-03-27 16:47:33 +04:00
# else
2001-06-05 16:46:33 +04:00
# define MAX_MANTISSA_DIGITS DBL_DIG
# define MAX_EXPONENT_DIGITS 3
2001-03-27 16:47:33 +04:00
# endif
2001-06-05 16:46:33 +04:00
/* The maximal number of digits is for base 2 */
# define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
2001-03-27 16:47:33 +04:00
/* The width of a pointer. The number of bits in a hex digit is 4 */
# define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
/* Infinite and Not-A-Number for floating-point */
2001-04-21 20:57:29 +04:00
# define INFINITE_LOWER "inf"
# define INFINITE_UPPER "INF"
# define LONG_INFINITE_LOWER "infinite"
# define LONG_INFINITE_UPPER "INFINITE"
# define NAN_LOWER "nan"
# define NAN_UPPER "NAN"
2001-03-27 16:47:33 +04:00
/* Various constants */
enum {
TYPE_PRINT = 1 ,
TYPE_SCAN = 2 ,
/* Flags. Use maximum 32 */
FLAGS_NEW = 0 ,
FLAGS_STICKY = 1 ,
FLAGS_SPACE = 2 * FLAGS_STICKY ,
FLAGS_SHOWSIGN = 2 * FLAGS_SPACE ,
FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN ,
FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST ,
FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE ,
FLAGS_SHORTSHORT = 2 * FLAGS_SHORT ,
FLAGS_LONG = 2 * FLAGS_SHORTSHORT ,
FLAGS_QUAD = 2 * FLAGS_LONG ,
FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD ,
FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE ,
FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T ,
FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T ,
FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T ,
FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING ,
FLAGS_UPPER = 2 * FLAGS_UNSIGNED ,
FLAGS_WIDTH = 2 * FLAGS_UPPER ,
FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH ,
FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER ,
FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION ,
FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER ,
FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE ,
FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER ,
FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E ,
FLAGS_QUOTE = 2 * FLAGS_FLOAT_G ,
FLAGS_WIDECHAR = 2 * FLAGS_QUOTE ,
FLAGS_ALLOC = 2 * FLAGS_WIDECHAR ,
FLAGS_IGNORE = 2 * FLAGS_ALLOC ,
FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE ,
2001-06-05 16:46:33 +04:00
FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER ,
FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER ,
2001-03-27 16:47:33 +04:00
/* Reused flags */
FLAGS_EXCLUDE = FLAGS_SHORT ,
2001-04-21 20:57:29 +04:00
FLAGS_USER_DEFINED = FLAGS_IGNORE ,
2001-03-27 16:47:33 +04:00
/* Compounded flags */
2001-04-21 20:57:29 +04:00
FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T ,
2001-06-05 16:46:33 +04:00
FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT ,
2001-03-27 16:47:33 +04:00
NO_POSITION = - 1 ,
NO_WIDTH = 0 ,
NO_PRECISION = - 1 ,
NO_SIZE = - 1 ,
NO_BASE = - 1 ,
MIN_BASE = 2 ,
MAX_BASE = 36 ,
BASE_BINARY = 2 ,
BASE_OCTAL = 8 ,
BASE_DECIMAL = 10 ,
BASE_HEX = 16 ,
/* Maximal number of allowed parameters */
MAX_PARAMETERS = 64 ,
/* Maximal number of characters in class */
MAX_CHARACTER_CLASS = UCHAR_MAX ,
2001-04-21 20:57:29 +04:00
/* Maximal string lengths for user-defined specifiers */
MAX_USER_NAME = 64 ,
MAX_USER_DATA = 256 ,
2001-03-27 16:47:33 +04:00
/* Maximal length of locale separator strings */
2001-06-05 16:46:33 +04:00
MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX ,
2001-03-27 16:47:33 +04:00
/* Maximal number of integers in grouping */
2001-04-30 21:44:45 +04:00
MAX_LOCALE_GROUPS = 64
2001-03-27 16:47:33 +04:00
} ;
# define NO_GROUPING ((int)CHAR_MAX)
/* Fundamental formatting parameter types */
# define FORMAT_UNKNOWN 0
# define FORMAT_INT 1
# define FORMAT_DOUBLE 2
# define FORMAT_CHAR 3
# define FORMAT_STRING 4
# define FORMAT_POINTER 5
# define FORMAT_COUNT 6
# define FORMAT_PARAMETER 7
# define FORMAT_GROUP 8
2001-06-05 16:46:33 +04:00
# if TRIO_GNU
2001-04-21 20:57:29 +04:00
# define FORMAT_ERRNO 9
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_EXTENSION
2001-04-21 20:57:29 +04:00
# define FORMAT_USER_DEFINED 10
2001-03-27 16:47:33 +04:00
# endif
/* Character constants */
# define CHAR_IDENTIFIER '%'
# define CHAR_BACKSLASH '\\'
# define CHAR_QUOTE '\"'
# define CHAR_ADJUST ' '
/* Character class expressions */
# define CLASS_ALNUM ":alnum:"
# define CLASS_ALPHA ":alpha:"
# define CLASS_CNTRL ":cntrl:"
# define CLASS_DIGIT ":digit:"
# define CLASS_GRAPH ":graph:"
# define CLASS_LOWER ":lower:"
# define CLASS_PRINT ":print:"
# define CLASS_PUNCT ":punct:"
# define CLASS_SPACE ":space:"
# define CLASS_UPPER ":upper:"
# define CLASS_XDIGIT ":xdigit:"
/*
* SPECIFIERS :
*
*
* a Hex - float
* A Hex - float
* c Character
* C Widechar character ( wint_t )
* d Decimal
* e Float
* E Float
* F Float
* F Float
* g Float
* G Float
* i Integer
* m Error message
* n Count
* o Octal
* p Pointer
* s String
2001-06-05 16:46:33 +04:00
* S Widechar string ( wchar_t * )
2001-03-27 16:47:33 +04:00
* u Unsigned
* x Hex
* X Hex
2001-04-21 20:57:29 +04:00
* [ ] Group
* < > User - defined
2001-03-27 16:47:33 +04:00
*
* Reserved :
*
* D Binary Coded Decimal % D ( length , precision ) ( OS / 390 )
*/
# define SPECIFIER_CHAR 'c'
# define SPECIFIER_STRING 's'
# define SPECIFIER_DECIMAL 'd'
# define SPECIFIER_INTEGER 'i'
# define SPECIFIER_UNSIGNED 'u'
# define SPECIFIER_OCTAL 'o'
# define SPECIFIER_HEX 'x'
# define SPECIFIER_HEX_UPPER 'X'
# define SPECIFIER_FLOAT_E 'e'
# define SPECIFIER_FLOAT_E_UPPER 'E'
# define SPECIFIER_FLOAT_F 'f'
# define SPECIFIER_FLOAT_F_UPPER 'F'
# define SPECIFIER_FLOAT_G 'g'
# define SPECIFIER_FLOAT_G_UPPER 'G'
# define SPECIFIER_POINTER 'p'
# define SPECIFIER_GROUP '['
# define SPECIFIER_UNGROUP ']'
# define SPECIFIER_COUNT 'n'
2001-06-05 16:46:33 +04:00
# if TRIO_UNIX98
2001-03-27 16:47:33 +04:00
# define SPECIFIER_CHAR_UPPER 'C'
# define SPECIFIER_STRING_UPPER 'S'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_C99
2001-03-27 16:47:33 +04:00
# define SPECIFIER_HEXFLOAT 'a'
# define SPECIFIER_HEXFLOAT_UPPER 'A'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_GNU
2001-03-27 16:47:33 +04:00
# define SPECIFIER_ERRNO 'm'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_EXTENSION
2001-03-27 16:47:33 +04:00
# define SPECIFIER_BINARY 'b'
# define SPECIFIER_BINARY_UPPER 'B'
2001-04-21 20:57:29 +04:00
# define SPECIFIER_USER_DEFINED_BEGIN '<'
# define SPECIFIER_USER_DEFINED_END '>'
# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
2001-03-27 16:47:33 +04:00
# endif
/*
* QUALIFIERS :
*
*
* Numbers = d , i , o , u , x , X
* Float = a , A , e , E , f , F , g , G
* String = s
* Char = c
*
*
* 9 $ Position
* Use the 9 th parameter . 9 can be any number between 1 and
* the maximal argument
*
* 9 Width
* Set width to 9. 9 can be any number , but must not be postfixed
* by ' $ '
*
* h Short
* Numbers :
* ( unsigned ) short int
*
* hh Short short
* Numbers :
* ( unsigned ) char
*
* l Long
* Numbers :
* ( unsigned ) long int
* String :
* as the S specifier
* Char :
* as the C specifier
*
* ll Long Long
* Numbers :
* ( unsigned ) long long int
*
* L Long Double
* Float
* long double
*
* # Alternative
* Float :
* Decimal - point is always present
* String :
* non - printable characters are handled as \ number
*
* Spacing
*
* + Sign
*
* - Alignment
*
* . Precision
*
* * Parameter
* print : use parameter
* scan : no parameter ( ignore )
*
* q Quad
*
* Z size_t
*
* w Widechar
*
* ' Thousands / quote
* Numbers :
* Integer part grouped in thousands
* Binary numbers :
* Number grouped in nibbles ( 4 bits )
* String :
* Quoted string
*
* j intmax_t
* t prtdiff_t
* z size_t
*
* ! Sticky
* @ Parameter ( for both print and scan )
2001-06-05 16:46:33 +04:00
*
* I n - bit Integer
* Numbers :
* The following options exists
* I8 = 8 - bit integer
* I16 = 16 - bit integer
* I32 = 32 - bit integer
* I64 = 64 - bit integer
2001-03-27 16:47:33 +04:00
*/
# define QUALIFIER_POSITION '$'
# define QUALIFIER_SHORT 'h'
# define QUALIFIER_LONG 'l'
# define QUALIFIER_LONG_UPPER 'L'
# define QUALIFIER_ALTERNATIVE '#'
# define QUALIFIER_SPACE ' '
# define QUALIFIER_PLUS '+'
# define QUALIFIER_MINUS '-'
# define QUALIFIER_DOT '.'
# define QUALIFIER_STAR '*'
# define QUALIFIER_CIRCUMFLEX '^'
2001-06-05 16:46:33 +04:00
# if TRIO_C99
2001-03-27 16:47:33 +04:00
# define QUALIFIER_SIZE_T 'z'
# define QUALIFIER_PTRDIFF_T 't'
# define QUALIFIER_INTMAX_T 'j'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_BSD || TRIO_GNU
2001-03-27 16:47:33 +04:00
# define QUALIFIER_QUAD 'q'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_GNU
2001-03-27 16:47:33 +04:00
# define QUALIFIER_SIZE_T_UPPER 'Z'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_MISC
2001-03-27 16:47:33 +04:00
# define QUALIFIER_WIDECHAR 'w'
# endif
2001-06-05 16:46:33 +04:00
# if TRIO_MICROSOFT
# define QUALIFIER_FIXED_SIZE 'I'
# endif
# if TRIO_EXTENSION
2001-03-27 16:47:33 +04:00
# define QUALIFIER_QUOTE '\''
# define QUALIFIER_STICKY '!'
# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
# define QUALIFIER_PARAM '@' /* Experimental */
# define QUALIFIER_COLON ':' /* For scanlists */
2001-06-05 16:46:33 +04:00
# define QUALIFIER_EQUAL '=' /* For scanlists */
2001-03-27 16:47:33 +04:00
# endif
2001-04-21 20:57:29 +04:00
/*************************************************************************
* Internal structures
*/
/* Parameters */
2001-03-27 16:47:33 +04:00
typedef struct {
int type ;
2001-04-21 20:57:29 +04:00
unsigned long flags ;
2001-03-27 16:47:33 +04:00
int width ;
2001-04-21 20:57:29 +04:00
int precision ;
2001-03-27 16:47:33 +04:00
int base ;
int varsize ;
int indexAfterSpecifier ;
union {
char * string ;
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
wchar_t * wstring ;
# endif
2001-03-27 16:47:33 +04:00
void * pointer ;
union {
2001-06-05 16:46:33 +04:00
trio_uintmax_t as_signed ;
trio_intmax_t as_unsigned ;
2001-03-27 16:47:33 +04:00
} number ;
double doubleNumber ;
double * doublePointer ;
long double longdoubleNumber ;
long double * longdoublePointer ;
int errorNumber ;
} data ;
2001-04-21 20:57:29 +04:00
/* For the user-defined specifier */
char user_name [ MAX_USER_NAME ] ;
char user_data [ MAX_USER_DATA ] ;
2001-03-27 16:47:33 +04:00
} parameter_T ;
2001-04-21 20:57:29 +04:00
/* General trio "class" */
2001-03-27 16:47:33 +04:00
typedef struct _trio_T {
2001-06-05 16:46:33 +04:00
void * location ;
2001-03-27 16:47:33 +04:00
void ( * OutStream ) ( struct _trio_T * , int ) ;
void ( * InStream ) ( struct _trio_T * , int * ) ;
2001-04-21 20:57:29 +04:00
/*
* The number of characters that would have been written / read if
2001-03-27 16:47:33 +04:00
* there had been sufficient space .
*/
2001-04-21 20:57:29 +04:00
int processed ;
/*
* The number of characters that are actually written / read .
2001-03-27 16:47:33 +04:00
* Processed and committed with only differ for the * nprintf
* and * nscanf functions .
*/
2001-04-21 20:57:29 +04:00
int committed ;
int max ;
int current ;
2001-03-27 16:47:33 +04:00
} trio_T ;
2001-04-21 20:57:29 +04:00
/* References (for user-defined callbacks) */
typedef struct _reference_T {
trio_T * data ;
parameter_T * parameter ;
} reference_T ;
/* Registered entries (for user-defined callbacks) */
typedef struct _userdef_T {
struct _userdef_T * next ;
trio_callback_t callback ;
char * name ;
} userdef_T ;
2001-03-27 16:47:33 +04:00
/*************************************************************************
2001-04-21 20:57:29 +04:00
* Internal variables
2001-03-27 16:47:33 +04:00
*/
# if defined(PLATFORM_UNIX)
extern int errno ;
# endif
2001-04-21 20:57:29 +04:00
static const char null [ ] = " (nil) " ;
2001-03-27 16:47:33 +04:00
# if defined(USE_LOCALE)
2001-04-21 20:57:29 +04:00
static struct lconv * internalLocaleValues = NULL ;
2001-03-27 16:47:33 +04:00
# endif
2001-04-21 20:57:29 +04:00
/*
* UNIX98 says " in a locale where the radix character is not defined,
2001-03-27 16:47:33 +04:00
* the radix character defaults to a period ( . ) "
*/
2001-06-05 16:46:33 +04:00
static char internalDecimalPoint [ MAX_LOCALE_SEPARATOR_LENGTH + 1 ] = " . " ;
static char internalThousandSeparator [ MAX_LOCALE_SEPARATOR_LENGTH + 1 ] = " , " ;
2001-04-21 20:57:29 +04:00
static char internalGrouping [ MAX_LOCALE_GROUPS ] = { ( char ) NO_GROUPING } ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
static const char internalDigitsLower [ ] = " 0123456789abcdefghijklmnopqrstuvwxyz " ;
static const char internalDigitsUpper [ ] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " ;
static BOOLEAN_T internalDigitsUnconverted = TRUE ;
static int internalDigitArray [ 128 ] ;
2001-06-05 16:46:33 +04:00
# if TRIO_EXTENSION
static BOOLEAN_T internalCollationUnconverted = TRUE ;
static char internalCollationArray [ MAX_CHARACTER_CLASS ] [ MAX_CHARACTER_CLASS ] ;
# endif
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
static volatile trio_callback_t internalEnterCriticalRegion = NULL ;
static volatile trio_callback_t internalLeaveCriticalRegion = NULL ;
static userdef_T * internalUserDef = NULL ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
/*************************************************************************
* trio_strerror [ public ]
*/
const char * trio_strerror ( int errorcode )
{
/* Textual versions of the error codes */
switch ( TRIO_ERROR_CODE ( errorcode ) )
{
case TRIO_EOF :
return " End of file " ;
case TRIO_EINVAL :
return " Invalid argument " ;
case TRIO_ETOOMANY :
return " Too many arguments " ;
case TRIO_EDBLREF :
return " Double reference " ;
case TRIO_EGAP :
return " Reference gap " ;
case TRIO_ENOMEM :
return " Out of memory " ;
case TRIO_ERANGE :
return " Invalid range " ;
default :
return " Unknown " ;
}
}
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioIsQualifier [ private ]
*
* Description :
* Remember to add all new qualifiers to this function .
* QUALIFIER_POSITION must not be added .
*/
static BOOLEAN_T
TrioIsQualifier ( const char ch )
{
/* QUALIFIER_POSITION is not included */
switch ( ch )
{
case ' 0 ' : case ' 1 ' : case ' 2 ' : case ' 3 ' : case ' 4 ' :
case ' 5 ' : case ' 6 ' : case ' 7 ' : case ' 8 ' : case ' 9 ' :
case QUALIFIER_PLUS :
case QUALIFIER_MINUS :
case QUALIFIER_SPACE :
case QUALIFIER_DOT :
case QUALIFIER_STAR :
case QUALIFIER_ALTERNATIVE :
case QUALIFIER_SHORT :
case QUALIFIER_LONG :
case QUALIFIER_LONG_UPPER :
case QUALIFIER_CIRCUMFLEX :
# if defined(QUALIFIER_SIZE_T)
case QUALIFIER_SIZE_T :
# endif
# if defined(QUALIFIER_PTRDIFF_T)
case QUALIFIER_PTRDIFF_T :
# endif
# if defined(QUALIFIER_INTMAX_T)
case QUALIFIER_INTMAX_T :
# endif
# if defined(QUALIFIER_QUAD)
case QUALIFIER_QUAD :
# endif
# if defined(QUALIFIER_SIZE_T_UPPER)
case QUALIFIER_SIZE_T_UPPER :
# endif
# if defined(QUALIFIER_WIDECHAR)
case QUALIFIER_WIDECHAR :
# endif
# if defined(QUALIFIER_QUOTE)
case QUALIFIER_QUOTE :
# endif
# if defined(QUALIFIER_STICKY)
case QUALIFIER_STICKY :
# endif
# if defined(QUALIFIER_VARSIZE)
case QUALIFIER_VARSIZE :
# endif
# if defined(QUALIFIER_PARAM)
case QUALIFIER_PARAM :
2001-06-05 16:46:33 +04:00
# endif
# if defined(QUALIFIER_FIXED_SIZE)
case QUALIFIER_FIXED_SIZE :
2001-03-27 16:47:33 +04:00
# endif
return TRUE ;
default :
return FALSE ;
}
}
2001-06-05 16:46:33 +04:00
/*************************************************************************
* TrioGenerateNan [ private ]
*
* Calculating NaN portably is difficult . Some compilers will emit
* warnings about divide by zero , and others will simply fail to
* generate a NaN .
*/
2001-06-22 18:41:45 +04:00
static double
TrioDivide ( double dividend , double divisor )
{
return dividend / divisor ;
}
2001-06-05 16:46:33 +04:00
static double
TrioGenerateNaN ( void )
{
# if defined(TRIO_COMPILER_SUPPORTS_C99)
return nan ( NULL ) ;
# elif defined(DBL_QNAN)
return DBL_QNAN ;
# elif defined(PLATFORM_UNIX)
double value ;
void ( * signal_handler ) ( int ) ;
signal_handler = signal ( SIGFPE , SIG_IGN ) ;
2001-06-22 18:41:45 +04:00
value = TrioDivide ( 0.0 , 0.0 ) ;
2001-06-05 16:46:33 +04:00
signal ( SIGFPE , signal_handler ) ;
return value ;
# else
2001-06-22 18:41:45 +04:00
return TrioDivide ( 0.0 , 0.0 ) ;
2001-06-05 16:46:33 +04:00
# endif
}
2001-04-21 20:57:29 +04:00
/*************************************************************************
* TrioIsNan [ private ]
*/
static int
TrioIsNan ( double number )
{
# ifdef isnan
/* C99 defines isnan() as a macro */
return isnan ( number ) ;
# else
double integral , fraction ;
return ( /* NaN is the only number which does not compare to itself */
( number ! = number ) | |
/* Fallback solution if NaN compares to NaN */
( ( number ! = 0.0 ) & &
( fraction = modf ( number , & integral ) ,
integral = = fraction ) ) ) ;
# endif
}
/*************************************************************************
* TrioIsInfinite [ private ]
*/
static int
TrioIsInfinite ( double number )
{
# ifdef isinf
/* C99 defines isinf() as a macro */
return isinf ( number ) ;
# else
return ( ( number = = HUGE_VAL ) ? 1 : ( ( number = = - HUGE_VAL ) ? - 1 : 0 ) ) ;
# endif
}
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioSetLocale [ private ]
*/
2001-04-21 20:57:29 +04:00
# if defined(USE_LOCALE)
2001-03-27 16:47:33 +04:00
static void
2001-04-21 20:57:29 +04:00
TrioSetLocale ( void )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
internalLocaleValues = ( struct lconv * ) localeconv ( ) ;
2001-06-05 16:46:33 +04:00
if ( internalLocaleValues )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
if ( ( internalLocaleValues - > decimal_point ) & &
( internalLocaleValues - > decimal_point [ 0 ] ! = NIL ) )
{
StrCopyMax ( internalDecimalPoint ,
sizeof ( internalDecimalPoint ) ,
internalLocaleValues - > decimal_point ) ;
}
if ( ( internalLocaleValues - > thousands_sep ) & &
( internalLocaleValues - > thousands_sep [ 0 ] ! = NIL ) )
{
StrCopyMax ( internalThousandSeparator ,
sizeof ( internalThousandSeparator ) ,
internalLocaleValues - > thousands_sep ) ;
}
if ( ( internalLocaleValues - > grouping ) & &
( internalLocaleValues - > grouping [ 0 ] ! = NIL ) )
{
StrCopyMax ( internalGrouping ,
sizeof ( internalGrouping ) ,
internalLocaleValues - > grouping ) ;
}
2001-03-27 16:47:33 +04:00
}
}
2001-04-21 20:57:29 +04:00
# endif /* defined(USE_LOCALE) */
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioGetPosition [ private ]
*
* Get the % n $ position .
*/
static int
2001-04-21 20:57:29 +04:00
TrioGetPosition ( const char * format ,
int * indexPointer )
2001-03-27 16:47:33 +04:00
{
char * tmpformat ;
int number = 0 ;
int index = * indexPointer ;
number = ( int ) StrToLong ( & format [ index ] , & tmpformat , BASE_DECIMAL ) ;
index = ( int ) ( tmpformat - format ) ;
if ( ( number ! = 0 ) & & ( QUALIFIER_POSITION = = format [ index + + ] ) )
{
* indexPointer = index ;
2001-04-21 20:57:29 +04:00
/*
* number is decreased by 1 , because n $ starts from 1 , whereas
2001-03-27 16:47:33 +04:00
* the array it is indexing starts from 0.
*/
return number - 1 ;
}
return NO_POSITION ;
}
2001-04-21 20:57:29 +04:00
/*************************************************************************
* TrioFindNamespace [ private ]
*
* Find registered user - defined specifier .
* The prev argument is used for optimisation only .
*/
static userdef_T *
TrioFindNamespace ( const char * name , userdef_T * * prev )
{
userdef_T * def ;
2001-06-05 16:46:33 +04:00
if ( internalEnterCriticalRegion )
( void ) internalEnterCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
for ( def = internalUserDef ; def ; def = def - > next )
{
/* Case-sensitive string comparison */
if ( StrEqualCase ( def - > name , name ) )
2001-06-05 16:46:33 +04:00
break ;
2001-04-21 20:57:29 +04:00
if ( prev )
* prev = def ;
}
2001-06-05 16:46:33 +04:00
if ( internalLeaveCriticalRegion )
( void ) internalLeaveCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
return def ;
}
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioPreprocess [ private ]
*
* Description :
* Parse the format string
*/
static int
TrioPreprocess ( int type ,
const char * format ,
parameter_T * parameters ,
2001-04-21 20:57:29 +04:00
va_list arglist ,
void * * argarray )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
/* Count the number of times a parameter is referenced */
unsigned short usedEntries [ MAX_PARAMETERS ] ;
# endif
/* Parameter counters */
int parameterPosition ;
int currentParam ;
int maxParam = - 1 ;
/* Utility variables */
2001-04-21 20:57:29 +04:00
unsigned long flags ;
2001-03-27 16:47:33 +04:00
int width ;
int precision ;
int varsize ;
int base ;
int index ; /* Index into formatting string */
int dots ; /* Count number of dots in modifier part */
BOOLEAN_T positional ; /* Does the specifier have a positional? */
BOOLEAN_T got_sticky = FALSE ; /* Are there any sticky modifiers at all? */
2001-04-21 20:57:29 +04:00
/*
* indices specifies the order in which the parameters must be
2001-03-27 16:47:33 +04:00
* read from the va_args ( this is necessary to handle positionals )
*/
int indices [ MAX_PARAMETERS ] ;
int pos = 0 ;
/* Various variables */
char ch ;
int charlen ;
int i = - 1 ;
int num ;
char * tmpformat ;
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-04-21 20:57:29 +04:00
/*
* The ' parameters ' array is not initialized , but we need to
2001-03-27 16:47:33 +04:00
* know which entries we have used .
*/
memset ( usedEntries , 0 , sizeof ( usedEntries ) ) ;
# endif
index = 0 ;
parameterPosition = 0 ;
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
mblen ( NULL , 0 ) ;
# endif
while ( format [ index ] )
{
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
if ( ! isascii ( format [ index ] ) )
{
2001-04-21 20:57:29 +04:00
/*
* Multibyte characters cannot be legal specifiers or
2001-03-27 16:47:33 +04:00
* modifiers , so we skip over them .
*/
charlen = mblen ( & format [ index ] , MB_LEN_MAX ) ;
index + = ( charlen > 0 ) ? charlen : 1 ;
continue ; /* while */
}
2001-06-05 16:46:33 +04:00
# endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
2001-03-27 16:47:33 +04:00
if ( CHAR_IDENTIFIER = = format [ index + + ] )
{
if ( CHAR_IDENTIFIER = = format [ index ] )
{
index + + ;
continue ; /* while */
}
flags = FLAGS_NEW ;
dots = 0 ;
currentParam = TrioGetPosition ( format , & index ) ;
positional = ( NO_POSITION ! = currentParam ) ;
if ( ! positional )
{
/* We have no positional, get the next counter */
currentParam = parameterPosition ;
}
if ( currentParam > = MAX_PARAMETERS )
{
/* Bail out completely to make the error more obvious */
return TRIO_ERROR_RETURN ( TRIO_ETOOMANY , index ) ;
}
if ( currentParam > maxParam )
maxParam = currentParam ;
/* Default values */
width = NO_WIDTH ;
precision = NO_PRECISION ;
base = NO_BASE ;
varsize = NO_SIZE ;
2001-04-21 20:57:29 +04:00
while ( TrioIsQualifier ( format [ index ] ) )
2001-03-27 16:47:33 +04:00
{
ch = format [ index + + ] ;
switch ( ch )
{
case QUALIFIER_SPACE :
flags | = FLAGS_SPACE ;
break ;
case QUALIFIER_PLUS :
flags | = FLAGS_SHOWSIGN ;
break ;
case QUALIFIER_MINUS :
flags | = FLAGS_LEFTADJUST ;
flags & = ~ FLAGS_NILPADDING ;
break ;
case QUALIFIER_ALTERNATIVE :
flags | = FLAGS_ALTERNATIVE ;
break ;
case QUALIFIER_DOT :
if ( dots = = 0 ) /* Precision */
{
dots + + ;
/* Skip if no precision */
if ( QUALIFIER_DOT = = format [ index ] )
break ;
/* After the first dot we have the precision */
flags | = FLAGS_PRECISION ;
if ( ( QUALIFIER_STAR = = format [ index ] ) | |
( QUALIFIER_PARAM = = format [ index ] ) )
{
index + + ;
flags | = FLAGS_PRECISION_PARAMETER ;
precision = TrioGetPosition ( format , & index ) ;
if ( precision = = NO_POSITION )
{
parameterPosition + + ;
if ( positional )
precision = parameterPosition ;
else
{
precision = currentParam ;
currentParam = precision + 1 ;
}
}
else
{
if ( ! positional )
currentParam = precision + 1 ;
if ( width > maxParam )
maxParam = precision ;
}
if ( currentParam > maxParam )
maxParam = currentParam ;
}
else
{
precision = StrToLong ( & format [ index ] , & tmpformat , BASE_DECIMAL ) ;
index = ( int ) ( tmpformat - format ) ;
}
}
else if ( dots = = 1 ) /* Base */
{
dots + + ;
/* After the second dot we have the base */
flags | = FLAGS_BASE ;
if ( ( QUALIFIER_STAR = = format [ index ] ) | |
( QUALIFIER_PARAM = = format [ index ] ) )
{
index + + ;
flags | = FLAGS_BASE_PARAMETER ;
base = TrioGetPosition ( format , & index ) ;
if ( base = = NO_POSITION )
{
parameterPosition + + ;
if ( positional )
base = parameterPosition ;
else
{
base = currentParam ;
currentParam = base + 1 ;
}
}
else
{
if ( ! positional )
currentParam = base + 1 ;
if ( base > maxParam )
maxParam = base ;
}
if ( currentParam > maxParam )
maxParam = currentParam ;
}
else
{
base = StrToLong ( & format [ index ] , & tmpformat , BASE_DECIMAL ) ;
if ( base > MAX_BASE )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
index = ( int ) ( tmpformat - format ) ;
}
}
else
{
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
break ; /* QUALIFIER_DOT */
case QUALIFIER_PARAM :
type = TYPE_PRINT ;
/* FALLTHROUGH */
case QUALIFIER_STAR :
/* This has different meanings for print and scan */
if ( TYPE_PRINT = = type )
{
/* Read with from parameter */
flags | = ( FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER ) ;
width = TrioGetPosition ( format , & index ) ;
if ( width = = NO_POSITION )
{
parameterPosition + + ;
if ( positional )
width = parameterPosition ;
else
{
width = currentParam ;
currentParam = width + 1 ;
}
}
else
{
if ( ! positional )
currentParam = width + 1 ;
if ( width > maxParam )
maxParam = width ;
}
if ( currentParam > maxParam )
maxParam = currentParam ;
}
else
{
/* Scan, but do not store result */
flags | = FLAGS_IGNORE ;
}
break ; /* QUALIFIER_STAR */
case ' 0 ' :
if ( ! ( flags & FLAGS_LEFTADJUST ) )
flags | = FLAGS_NILPADDING ;
/* FALLTHROUGH */
case ' 1 ' : case ' 2 ' : case ' 3 ' : case ' 4 ' :
case ' 5 ' : case ' 6 ' : case ' 7 ' : case ' 8 ' : case ' 9 ' :
flags | = FLAGS_WIDTH ;
/* &format[index - 1] is used to "rewind" the read
* character from format
*/
width = StrToLong ( & format [ index - 1 ] , & tmpformat , BASE_DECIMAL ) ;
index = ( int ) ( tmpformat - format ) ;
break ;
case QUALIFIER_SHORT :
if ( flags & FLAGS_SHORTSHORT )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
else if ( flags & FLAGS_SHORT )
flags | = FLAGS_SHORTSHORT ;
else
flags | = FLAGS_SHORT ;
break ;
case QUALIFIER_LONG :
if ( flags & FLAGS_QUAD )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
else if ( flags & FLAGS_LONG )
flags | = FLAGS_QUAD ;
else
flags | = FLAGS_LONG ;
break ;
case QUALIFIER_LONG_UPPER :
flags | = FLAGS_LONGDOUBLE ;
break ;
# if defined(QUALIFIER_SIZE_T)
case QUALIFIER_SIZE_T :
flags | = FLAGS_SIZE_T ;
/* Modify flags for later truncation of number */
2001-06-05 16:46:33 +04:00
if ( sizeof ( size_t ) = = sizeof ( trio_ulonglong_t ) )
2001-03-27 16:47:33 +04:00
flags | = FLAGS_QUAD ;
else if ( sizeof ( size_t ) = = sizeof ( long ) )
flags | = FLAGS_LONG ;
break ;
# endif
# if defined(QUALIFIER_PTRDIFF_T)
case QUALIFIER_PTRDIFF_T :
flags | = FLAGS_PTRDIFF_T ;
2001-06-05 16:46:33 +04:00
if ( sizeof ( ptrdiff_t ) = = sizeof ( trio_ulonglong_t ) )
2001-03-27 16:47:33 +04:00
flags | = FLAGS_QUAD ;
else if ( sizeof ( ptrdiff_t ) = = sizeof ( long ) )
flags | = FLAGS_LONG ;
break ;
# endif
# if defined(QUALIFIER_INTMAX_T)
case QUALIFIER_INTMAX_T :
flags | = FLAGS_INTMAX_T ;
2001-06-05 16:46:33 +04:00
if ( sizeof ( trio_intmax_t ) = = sizeof ( trio_ulonglong_t ) )
2001-03-27 16:47:33 +04:00
flags | = FLAGS_QUAD ;
2001-06-05 16:46:33 +04:00
else if ( sizeof ( trio_intmax_t ) = = sizeof ( long ) )
2001-03-27 16:47:33 +04:00
flags | = FLAGS_LONG ;
break ;
# endif
# if defined(QUALIFIER_QUAD)
case QUALIFIER_QUAD :
flags | = FLAGS_QUAD ;
break ;
# endif
2001-06-05 16:46:33 +04:00
# if defined(QUALIFIER_FIXED_SIZE)
case QUALIFIER_FIXED_SIZE :
if ( flags & FLAGS_FIXED_SIZE )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
if ( flags & ( FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER ) )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
if ( ( format [ index ] = = ' 6 ' ) & &
( format [ index + 1 ] = = ' 4 ' ) )
{
varsize = sizeof ( trio_int64_t ) ;
index + = 2 ;
}
else if ( ( format [ index ] = = ' 3 ' ) & &
( format [ index + 1 ] = = ' 2 ' ) )
{
varsize = sizeof ( trio_int32_t ) ;
index + = 2 ;
}
else if ( ( format [ index ] = = ' 1 ' ) & &
( format [ index + 1 ] = = ' 6 ' ) )
{
varsize = sizeof ( trio_int16_t ) ;
index + = 2 ;
}
else if ( format [ index ] = = ' 8 ' )
{
varsize = sizeof ( trio_int8_t ) ;
index + + ;
}
else
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
flags | = FLAGS_FIXED_SIZE ;
break ;
# endif
2001-03-27 16:47:33 +04:00
# if defined(QUALIFIER_WIDECHAR)
case QUALIFIER_WIDECHAR :
flags | = FLAGS_WIDECHAR ;
break ;
# endif
# if defined(QUALIFIER_SIZE_T_UPPER)
case QUALIFIER_SIZE_T_UPPER :
break ;
# endif
# if defined(QUALIFIER_QUOTE)
case QUALIFIER_QUOTE :
flags | = FLAGS_QUOTE ;
break ;
# endif
# if defined(QUALIFIER_STICKY)
case QUALIFIER_STICKY :
flags | = FLAGS_STICKY ;
got_sticky = TRUE ;
break ;
# endif
# if defined(QUALIFIER_VARSIZE)
case QUALIFIER_VARSIZE :
2001-06-05 16:46:33 +04:00
flags | = FLAGS_VARSIZE_PARAMETER ;
2001-03-27 16:47:33 +04:00
parameterPosition + + ;
if ( positional )
varsize = parameterPosition ;
else
{
varsize = currentParam ;
currentParam = varsize + 1 ;
}
if ( currentParam > maxParam )
maxParam = currentParam ;
break ;
# endif
default :
/* Bail out completely to make the error more obvious */
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
} /* while qualifier */
2001-04-21 20:57:29 +04:00
/*
* Parameters only need the type and value . The value is
2001-03-27 16:47:33 +04:00
* read later .
*/
if ( flags & FLAGS_WIDTH_PARAMETER )
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
usedEntries [ width ] + = 1 ;
# endif
parameters [ pos ] . type = FORMAT_PARAMETER ;
indices [ width ] = pos ;
width = pos + + ;
}
if ( flags & FLAGS_PRECISION_PARAMETER )
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
usedEntries [ precision ] + = 1 ;
# endif
parameters [ pos ] . type = FORMAT_PARAMETER ;
indices [ precision ] = pos ;
precision = pos + + ;
}
if ( flags & FLAGS_BASE_PARAMETER )
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
usedEntries [ base ] + = 1 ;
# endif
parameters [ pos ] . type = FORMAT_PARAMETER ;
indices [ base ] = pos ;
base = pos + + ;
}
2001-06-05 16:46:33 +04:00
if ( flags & FLAGS_VARSIZE_PARAMETER )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
usedEntries [ varsize ] + = 1 ;
# endif
parameters [ pos ] . type = FORMAT_PARAMETER ;
indices [ varsize ] = pos ;
varsize = pos + + ;
}
indices [ currentParam ] = pos ;
switch ( format [ index + + ] )
{
# if defined(SPECIFIER_CHAR_UPPER)
case SPECIFIER_CHAR_UPPER :
2001-06-05 16:46:33 +04:00
flags | = FLAGS_WIDECHAR ;
2001-03-27 16:47:33 +04:00
/* FALLTHROUGH */
# endif
case SPECIFIER_CHAR :
2001-06-05 16:46:33 +04:00
if ( flags & FLAGS_LONG )
flags | = FLAGS_WIDECHAR ;
else if ( flags & FLAGS_SHORT )
flags & = ~ FLAGS_WIDECHAR ;
2001-03-27 16:47:33 +04:00
parameters [ pos ] . type = FORMAT_CHAR ;
break ;
# if defined(SPECIFIER_STRING_UPPER)
case SPECIFIER_STRING_UPPER :
2001-06-05 16:46:33 +04:00
flags | = FLAGS_WIDECHAR ;
2001-03-27 16:47:33 +04:00
/* FALLTHROUGH */
# endif
case SPECIFIER_STRING :
2001-06-05 16:46:33 +04:00
if ( flags & FLAGS_LONG )
flags | = FLAGS_WIDECHAR ;
else if ( flags & FLAGS_SHORT )
flags & = ~ FLAGS_WIDECHAR ;
2001-03-27 16:47:33 +04:00
parameters [ pos ] . type = FORMAT_STRING ;
break ;
case SPECIFIER_GROUP :
if ( TYPE_SCAN = = type )
{
2001-06-05 16:46:33 +04:00
int depth = 1 ;
2001-03-27 16:47:33 +04:00
parameters [ pos ] . type = FORMAT_GROUP ;
2001-06-05 16:46:33 +04:00
if ( format [ index ] = = QUALIFIER_CIRCUMFLEX )
index + + ;
if ( format [ index ] = = SPECIFIER_UNGROUP )
index + + ;
if ( format [ index ] = = QUALIFIER_MINUS )
index + + ;
/* Skip nested brackets */
while ( format [ index ] ! = NIL )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
if ( format [ index ] = = SPECIFIER_GROUP )
{
depth + + ;
}
else if ( format [ index ] = = SPECIFIER_UNGROUP )
{
if ( - - depth < = 0 )
{
index + + ;
break ;
}
}
index + + ;
2001-03-27 16:47:33 +04:00
}
}
break ;
case SPECIFIER_INTEGER :
parameters [ pos ] . type = FORMAT_INT ;
break ;
case SPECIFIER_UNSIGNED :
flags | = FLAGS_UNSIGNED ;
parameters [ pos ] . type = FORMAT_INT ;
break ;
case SPECIFIER_DECIMAL :
/* Disable base modifier */
flags & = ~ FLAGS_BASE_PARAMETER ;
base = BASE_DECIMAL ;
parameters [ pos ] . type = FORMAT_INT ;
break ;
case SPECIFIER_OCTAL :
flags & = ~ FLAGS_BASE_PARAMETER ;
base = BASE_OCTAL ;
parameters [ pos ] . type = FORMAT_INT ;
break ;
# if defined(SPECIFIER_BINARY)
case SPECIFIER_BINARY_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
case SPECIFIER_BINARY :
flags | = FLAGS_NILPADDING ;
flags & = ~ FLAGS_BASE_PARAMETER ;
base = BASE_BINARY ;
parameters [ pos ] . type = FORMAT_INT ;
break ;
# endif
case SPECIFIER_HEX_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
case SPECIFIER_HEX :
flags | = FLAGS_UNSIGNED ;
flags & = ~ FLAGS_BASE_PARAMETER ;
base = BASE_HEX ;
parameters [ pos ] . type = FORMAT_INT ;
break ;
case SPECIFIER_FLOAT_E_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
case SPECIFIER_FLOAT_E :
flags | = FLAGS_FLOAT_E ;
parameters [ pos ] . type = FORMAT_DOUBLE ;
break ;
case SPECIFIER_FLOAT_G_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
case SPECIFIER_FLOAT_G :
flags | = FLAGS_FLOAT_G ;
parameters [ pos ] . type = FORMAT_DOUBLE ;
break ;
case SPECIFIER_FLOAT_F_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
case SPECIFIER_FLOAT_F :
parameters [ pos ] . type = FORMAT_DOUBLE ;
break ;
case SPECIFIER_POINTER :
parameters [ pos ] . type = FORMAT_POINTER ;
break ;
case SPECIFIER_COUNT :
parameters [ pos ] . type = FORMAT_COUNT ;
break ;
# if defined(SPECIFIER_HEXFLOAT)
# if defined(SPECIFIER_HEXFLOAT_UPPER)
case SPECIFIER_HEXFLOAT_UPPER :
flags | = FLAGS_UPPER ;
/* FALLTHROUGH */
# endif
case SPECIFIER_HEXFLOAT :
base = BASE_HEX ;
parameters [ pos ] . type = FORMAT_DOUBLE ;
break ;
# endif
# if defined(FORMAT_ERRNO)
case SPECIFIER_ERRNO :
parameters [ pos ] . type = FORMAT_ERRNO ;
break ;
# endif
2001-04-21 20:57:29 +04:00
# if defined(SPECIFIER_USER_DEFINED_BEGIN)
case SPECIFIER_USER_DEFINED_BEGIN :
{
unsigned int max ;
int without_namespace = TRUE ;
parameters [ pos ] . type = FORMAT_USER_DEFINED ;
parameters [ pos ] . user_name [ 0 ] = NIL ;
tmpformat = ( char * ) & format [ index ] ;
while ( ( ch = format [ index ] ) )
{
index + + ;
if ( ch = = SPECIFIER_USER_DEFINED_END )
{
if ( without_namespace )
{
/* We must get the handle first */
parameters [ pos ] . type = FORMAT_PARAMETER ;
parameters [ pos ] . indexAfterSpecifier = index ;
parameters [ pos ] . flags = FLAGS_USER_DEFINED ;
/* Adjust parameters for insertion of new one */
pos + + ;
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-04-21 20:57:29 +04:00
usedEntries [ currentParam ] + = 1 ;
# endif
parameters [ pos ] . type = FORMAT_USER_DEFINED ;
currentParam + + ;
indices [ currentParam ] = pos ;
if ( currentParam > maxParam )
maxParam = currentParam ;
}
/* Copy the user data */
max = ( unsigned int ) ( & format [ index ] - tmpformat ) ;
if ( max > MAX_USER_DATA )
max = MAX_USER_DATA ;
StrCopyMax ( parameters [ pos ] . user_data ,
max ,
tmpformat ) ;
break ; /* while */
}
if ( ch = = SPECIFIER_USER_DEFINED_SEPARATOR )
{
without_namespace = FALSE ;
/* Copy the namespace for later looking-up */
max = ( int ) ( & format [ index ] - tmpformat ) ;
if ( max > MAX_USER_NAME )
max = MAX_USER_NAME ;
StrCopyMax ( parameters [ pos ] . user_name ,
max ,
tmpformat ) ;
tmpformat = ( char * ) & format [ index ] ;
}
}
if ( ch ! = SPECIFIER_USER_DEFINED_END )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
break ;
# endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
2001-03-27 16:47:33 +04:00
default :
/* Bail out completely to make the error more obvious */
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
/* Count the number of times this entry has been used */
usedEntries [ currentParam ] + = 1 ;
# endif
/* Find last sticky parameters */
if ( got_sticky & & ! ( flags & FLAGS_STICKY ) )
{
for ( i = pos - 1 ; i > = 0 ; i - - )
{
if ( parameters [ i ] . type = = FORMAT_PARAMETER )
continue ;
if ( ( parameters [ i ] . flags & FLAGS_STICKY ) & &
( parameters [ i ] . type = = parameters [ pos ] . type ) )
{
/* Do not overwrite current qualifiers */
2001-04-21 20:57:29 +04:00
flags | = ( parameters [ i ] . flags & ( unsigned long ) ~ FLAGS_STICKY ) ;
2001-03-27 16:47:33 +04:00
if ( width = = NO_WIDTH )
width = parameters [ i ] . width ;
if ( precision = = NO_PRECISION )
precision = parameters [ i ] . precision ;
if ( base = = NO_BASE )
base = parameters [ i ] . base ;
break ;
}
}
}
parameters [ pos ] . indexAfterSpecifier = index ;
parameters [ pos ] . flags = flags ;
parameters [ pos ] . width = width ;
parameters [ pos ] . precision = precision ;
parameters [ pos ] . base = ( base = = NO_BASE ) ? BASE_DECIMAL : base ;
parameters [ pos ] . varsize = varsize ;
pos + + ;
2001-04-21 20:57:29 +04:00
if ( ! positional )
2001-03-27 16:47:33 +04:00
parameterPosition + + ;
} /* if identifier */
} /* while format characters left */
for ( num = 0 ; num < = maxParam ; num + + )
{
2001-06-05 16:46:33 +04:00
# if TRIO_ERRORS
2001-03-27 16:47:33 +04:00
if ( usedEntries [ num ] ! = 1 )
{
if ( usedEntries [ num ] = = 0 ) /* gap detected */
return TRIO_ERROR_RETURN ( TRIO_EGAP , num ) ;
else /* double references detected */
return TRIO_ERROR_RETURN ( TRIO_EDBLREF , num ) ;
}
# endif
i = indices [ num ] ;
2001-04-21 20:57:29 +04:00
/*
* FORMAT_PARAMETERS are only present if they must be read ,
2001-03-27 16:47:33 +04:00
* so it makes no sense to check the ignore flag ( besides ,
* the flags variable is not set for that particular type )
*/
if ( ( parameters [ i ] . type ! = FORMAT_PARAMETER ) & &
( parameters [ i ] . flags & FLAGS_IGNORE ) )
continue ; /* for all arguments */
2001-04-21 20:57:29 +04:00
/*
* The stack arguments are read according to ANSI C89
2001-03-27 16:47:33 +04:00
* default argument promotions :
*
* char = int
* short = int
* unsigned char = unsigned int
* unsigned short = unsigned int
* float = double
*
* In addition to the ANSI C89 these types are read ( the
* default argument promotions of C99 has not been
* considered yet )
*
* long long
* long double
* size_t
* ptrdiff_t
* intmax_t
*/
switch ( parameters [ i ] . type )
{
case FORMAT_GROUP :
case FORMAT_STRING :
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
if ( flags & FLAGS_WIDECHAR )
{
parameters [ i ] . data . wstring = ( argarray = = NULL )
? va_arg ( arglist , wchar_t * )
: ( wchar_t * ) ( argarray [ num ] ) ;
}
else
# endif
{
parameters [ i ] . data . string = ( argarray = = NULL )
? va_arg ( arglist , char * )
: ( char * ) ( argarray [ num ] ) ;
}
2001-03-27 16:47:33 +04:00
break ;
case FORMAT_POINTER :
case FORMAT_COUNT :
2001-04-21 20:57:29 +04:00
case FORMAT_USER_DEFINED :
2001-03-27 16:47:33 +04:00
case FORMAT_UNKNOWN :
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . pointer = ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
? va_arg ( arglist , void * )
: argarray [ num ] ;
2001-03-27 16:47:33 +04:00
break ;
case FORMAT_CHAR :
case FORMAT_INT :
if ( TYPE_SCAN = = type )
{
2001-06-05 16:46:33 +04:00
if ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
parameters [ i ] . data . pointer =
2001-06-05 16:46:33 +04:00
( trio_uintmax_t * ) va_arg ( arglist , void * ) ;
2001-04-21 20:57:29 +04:00
else
{
if ( parameters [ i ] . type = = FORMAT_CHAR )
parameters [ i ] . data . pointer =
2001-06-05 16:46:33 +04:00
( trio_uintmax_t * ) ( ( char * ) argarray [ num ] ) ;
2001-04-21 20:57:29 +04:00
else if ( parameters [ i ] . flags & FLAGS_SHORT )
parameters [ i ] . data . pointer =
2001-06-05 16:46:33 +04:00
( trio_uintmax_t * ) ( ( short * ) argarray [ num ] ) ;
2001-04-21 20:57:29 +04:00
else
parameters [ i ] . data . pointer =
2001-06-05 16:46:33 +04:00
( trio_uintmax_t * ) ( ( int * ) argarray [ num ] ) ;
2001-04-21 20:57:29 +04:00
}
2001-03-27 16:47:33 +04:00
}
else
{
2001-06-05 16:46:33 +04:00
# if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
if ( ( parameters [ i ] . flags & FLAGS_VARSIZE_PARAMETER ) | |
( parameters [ i ] . flags & FLAGS_FIXED_SIZE ) )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
if ( parameters [ i ] . flags & FLAGS_VARSIZE_PARAMETER )
{
/*
* Variable sizes are mapped onto the fixed sizes , in
* accordance with integer promotion .
*
* Please note that this may not be portable , as we
* only guess the size , not the layout of the numbers .
* For example , if int is little - endian , and long is
* big - endian , then this will fail .
*/
varsize = ( int ) parameters [ parameters [ i ] . varsize ] . data . number . as_unsigned ;
}
else
{
/* Used for the I<bits> modifiers */
varsize = parameters [ i ] . varsize ;
}
2001-04-21 20:57:29 +04:00
parameters [ i ] . flags & = ~ FLAGS_ALL_VARSIZES ;
2001-06-05 16:46:33 +04:00
2001-03-27 16:47:33 +04:00
if ( varsize < = ( int ) sizeof ( int ) )
;
else if ( varsize < = ( int ) sizeof ( long ) )
parameters [ i ] . flags | = FLAGS_LONG ;
# if defined(QUALIFIER_INTMAX_T)
2001-06-05 16:46:33 +04:00
else if ( varsize < = ( int ) sizeof ( trio_longlong_t ) )
2001-03-27 16:47:33 +04:00
parameters [ i ] . flags | = FLAGS_QUAD ;
else
parameters [ i ] . flags | = FLAGS_INTMAX_T ;
# else
else
parameters [ i ] . flags | = FLAGS_QUAD ;
# endif
}
2001-04-21 20:57:29 +04:00
# endif /* defined(QUALIFIER_VARSIZE) */
2001-03-27 16:47:33 +04:00
# if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
if ( parameters [ i ] . flags & FLAGS_SIZE_T )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , size_t )
: ( trio_uintmax_t ) ( * ( ( size_t * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else
# endif
# if defined(QUALIFIER_PTRDIFF_T)
if ( parameters [ i ] . flags & FLAGS_PTRDIFF_T )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , ptrdiff_t )
: ( trio_uintmax_t ) ( * ( ( ptrdiff_t * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else
# endif
# if defined(QUALIFIER_INTMAX_T)
if ( parameters [ i ] . flags & FLAGS_INTMAX_T )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , trio_intmax_t )
: ( trio_uintmax_t ) ( * ( ( trio_intmax_t * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else
# endif
if ( parameters [ i ] . flags & FLAGS_QUAD )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , trio_ulonglong_t )
: ( trio_uintmax_t ) ( * ( ( trio_ulonglong_t * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else if ( parameters [ i ] . flags & FLAGS_LONG )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , long )
: ( trio_uintmax_t ) ( * ( ( long * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else
2001-04-21 20:57:29 +04:00
{
2001-06-05 16:46:33 +04:00
if ( argarray = = NULL )
parameters [ i ] . data . number . as_unsigned = ( trio_uintmax_t ) va_arg ( arglist , int ) ;
2001-04-21 20:57:29 +04:00
else
{
if ( parameters [ i ] . type = = FORMAT_CHAR )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( trio_uintmax_t ) ( * ( ( char * ) argarray [ num ] ) ) ;
2001-04-21 20:57:29 +04:00
else if ( parameters [ i ] . flags & FLAGS_SHORT )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( trio_uintmax_t ) ( * ( ( short * ) argarray [ num ] ) ) ;
2001-04-21 20:57:29 +04:00
else
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( trio_uintmax_t ) ( * ( ( int * ) argarray [ num ] ) ) ;
2001-04-21 20:57:29 +04:00
}
}
2001-03-27 16:47:33 +04:00
}
break ;
case FORMAT_PARAMETER :
2001-04-21 20:57:29 +04:00
/*
* The parameter for the user - defined specifier is a pointer ,
* whereas the rest ( width , precision , base ) uses an integer .
*/
if ( parameters [ i ] . flags & FLAGS_USER_DEFINED )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . pointer = ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
? va_arg ( arglist , void * )
: argarray [ num ] ;
else
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . number . as_unsigned = ( argarray = = NULL )
? ( trio_uintmax_t ) va_arg ( arglist , int )
: ( trio_uintmax_t ) ( * ( ( int * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
break ;
case FORMAT_DOUBLE :
if ( TYPE_SCAN = = type )
{
if ( parameters [ i ] . flags & FLAGS_LONG )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . longdoublePointer = ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
? va_arg ( arglist , long double * )
: ( long double * ) ( ( long double * ) argarray [ num ] ) ;
2001-03-27 16:47:33 +04:00
else
2001-04-21 20:57:29 +04:00
{
2001-06-05 16:46:33 +04:00
if ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
parameters [ i ] . data . doublePointer =
va_arg ( arglist , double * ) ;
else
{
if ( parameters [ i ] . flags & FLAGS_SHORT )
parameters [ i ] . data . doublePointer =
( double * ) ( ( float * ) argarray [ num ] ) ;
else
parameters [ i ] . data . doublePointer =
( double * ) ( ( double * ) argarray [ num ] ) ;
}
}
2001-03-27 16:47:33 +04:00
}
else
{
if ( parameters [ i ] . flags & FLAGS_LONG )
2001-06-05 16:46:33 +04:00
parameters [ i ] . data . longdoubleNumber = ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
? va_arg ( arglist , long double )
: ( long double ) ( * ( ( long double * ) argarray [ num ] ) ) ;
2001-03-27 16:47:33 +04:00
else
2001-04-21 20:57:29 +04:00
{
2001-06-05 16:46:33 +04:00
if ( argarray = = NULL )
2001-04-21 20:57:29 +04:00
parameters [ i ] . data . longdoubleNumber = ( long double ) va_arg ( arglist , double ) ;
else
{
if ( parameters [ i ] . flags & FLAGS_SHORT )
parameters [ i ] . data . longdoubleNumber = ( long double ) ( * ( ( float * ) argarray [ num ] ) ) ;
else
parameters [ i ] . data . longdoubleNumber = ( long double ) ( long double ) ( * ( ( double * ) argarray [ num ] ) ) ;
}
}
2001-03-27 16:47:33 +04:00
}
break ;
# if defined(FORMAT_ERRNO)
case FORMAT_ERRNO :
parameters [ i ] . data . errorNumber = errno ;
break ;
# endif
default :
break ;
}
} /* for all specifiers */
return num ;
}
/*************************************************************************
*
2001-04-21 20:57:29 +04:00
* @ FORMATTING
2001-03-27 16:47:33 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*************************************************************************
* TrioWriteNumber [ private ]
*
* Description :
* Output a number .
* The complexity of this function is a result of the complexity
* of the dependencies of the flags .
*/
static void
TrioWriteNumber ( trio_T * self ,
2001-06-05 16:46:33 +04:00
trio_uintmax_t number ,
2001-04-21 20:57:29 +04:00
unsigned long flags ,
2001-03-27 16:47:33 +04:00
int width ,
int precision ,
int base )
{
BOOLEAN_T isNegative ;
2001-06-05 16:46:33 +04:00
char buffer [ MAX_CHARS_IN ( trio_uintmax_t ) * ( 1 + MAX_LOCALE_SEPARATOR_LENGTH ) + 1 ] ;
2001-03-27 16:47:33 +04:00
char * bufferend ;
char * pointer ;
const char * digits ;
int i ;
int length ;
char * p ;
int charsPerThousand ;
int groupingIndex ;
int count ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > OutStream ) ) ;
assert ( ( base > = MIN_BASE & & base < = MAX_BASE ) | | ( base = = NO_BASE ) ) ;
2001-04-21 20:57:29 +04:00
digits = ( flags & FLAGS_UPPER ) ? internalDigitsUpper : internalDigitsLower ;
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
isNegative = ( flags & FLAGS_UNSIGNED )
? FALSE
: ( ( trio_intmax_t ) number < 0 ) ;
if ( isNegative )
2001-03-27 16:47:33 +04:00
number = - number ;
if ( flags & FLAGS_QUAD )
2001-06-05 16:46:33 +04:00
number & = ( trio_ulonglong_t ) - 1 ;
2001-03-27 16:47:33 +04:00
else if ( flags & FLAGS_LONG )
number & = ( unsigned long ) - 1 ;
else
number & = ( unsigned int ) - 1 ;
/* Build number */
pointer = bufferend = & buffer [ sizeof ( buffer ) - 1 ] ;
* pointer - - = NIL ;
2001-04-21 20:57:29 +04:00
charsPerThousand = ( int ) internalGrouping [ 0 ] ;
2001-03-27 16:47:33 +04:00
groupingIndex = 1 ;
for ( i = 1 ; i < ( int ) sizeof ( buffer ) ; i + + )
{
* pointer - - = digits [ number % base ] ;
number / = base ;
if ( number = = 0 )
break ;
if ( ( flags & FLAGS_QUOTE )
& & ( charsPerThousand ! = NO_GROUPING )
& & ( i % charsPerThousand = = 0 ) )
{
/*
* We are building the number from the least significant
* to the most significant digit , so we have to copy the
* thousand separator backwards
*/
2001-04-21 20:57:29 +04:00
length = StrLength ( internalThousandSeparator ) ;
2001-03-27 16:47:33 +04:00
if ( ( ( int ) ( pointer - buffer ) - length ) > 0 )
{
2001-04-21 20:57:29 +04:00
p = & internalThousandSeparator [ length - 1 ] ;
2001-03-27 16:47:33 +04:00
while ( length - - > 0 )
* pointer - - = * p - - ;
}
/* Advance to next grouping number */
2001-04-21 20:57:29 +04:00
switch ( internalGrouping [ groupingIndex ] )
2001-03-27 16:47:33 +04:00
{
case CHAR_MAX : /* Disable grouping */
charsPerThousand = NO_GROUPING ;
break ;
case 0 : /* Repeat last group */
break ;
default :
2001-04-21 20:57:29 +04:00
charsPerThousand = ( int ) internalGrouping [ groupingIndex + + ] ;
2001-03-27 16:47:33 +04:00
break ;
}
}
}
/* Adjust width */
width - = ( bufferend - pointer ) - 1 ;
/* Adjust precision */
if ( NO_PRECISION ! = precision )
{
precision - = ( bufferend - pointer ) - 1 ;
if ( precision < 0 )
precision = 0 ;
flags | = FLAGS_NILPADDING ;
}
/* Adjust width further */
if ( isNegative | | ( flags & FLAGS_SHOWSIGN ) | | ( flags & FLAGS_SPACE ) )
width - - ;
if ( flags & FLAGS_ALTERNATIVE )
{
switch ( base )
{
case BASE_BINARY :
case BASE_HEX :
width - = 2 ;
break ;
case BASE_OCTAL :
width - - ;
break ;
default :
break ;
}
}
/* Output prefixes spaces if needed */
if ( ! ( ( flags & FLAGS_LEFTADJUST ) | |
( ( flags & FLAGS_NILPADDING ) & & ( precision = = NO_PRECISION ) ) ) )
{
count = ( precision = = NO_PRECISION ) ? 0 : precision ;
while ( width - - > count )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
/* width has been adjusted for signs and alternatives */
if ( isNegative )
self - > OutStream ( self , ' - ' ) ;
else if ( flags & FLAGS_SHOWSIGN )
self - > OutStream ( self , ' + ' ) ;
else if ( flags & FLAGS_SPACE )
self - > OutStream ( self , ' ' ) ;
if ( flags & FLAGS_ALTERNATIVE )
{
switch ( base )
{
case BASE_BINARY :
self - > OutStream ( self , ' 0 ' ) ;
self - > OutStream ( self , ( flags & FLAGS_UPPER ) ? ' B ' : ' b ' ) ;
break ;
case BASE_OCTAL :
self - > OutStream ( self , ' 0 ' ) ;
break ;
case BASE_HEX :
self - > OutStream ( self , ' 0 ' ) ;
self - > OutStream ( self , ( flags & FLAGS_UPPER ) ? ' X ' : ' x ' ) ;
break ;
default :
break ;
} /* switch base */
}
/* Output prefixed zero padding if needed */
if ( flags & FLAGS_NILPADDING )
{
if ( precision = = NO_PRECISION )
precision = width ;
while ( precision - - > 0 )
{
self - > OutStream ( self , ' 0 ' ) ;
width - - ;
}
}
/* Output the number itself */
while ( * ( + + pointer ) )
{
self - > OutStream ( self , * pointer ) ;
}
/* Output trailing spaces if needed */
if ( flags & FLAGS_LEFTADJUST )
{
while ( width - - > 0 )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
}
2001-06-05 16:46:33 +04:00
/*************************************************************************
* TrioWriteStringCharacter [ private ]
*
* Description :
* Output a single character of a string
*/
static void
TrioWriteStringCharacter ( trio_T * self ,
int ch ,
unsigned long flags )
{
if ( flags & FLAGS_ALTERNATIVE )
{
if ( ! ( isprint ( ch ) | | isspace ( ch ) ) )
{
/*
* Non - printable characters are converted to C escapes or
* \ number , if no C escape exists .
*/
self - > OutStream ( self , CHAR_BACKSLASH ) ;
switch ( ch )
{
case ' \007 ' : self - > OutStream ( self , ' a ' ) ; break ;
case ' \b ' : self - > OutStream ( self , ' b ' ) ; break ;
case ' \f ' : self - > OutStream ( self , ' f ' ) ; break ;
case ' \n ' : self - > OutStream ( self , ' n ' ) ; break ;
case ' \r ' : self - > OutStream ( self , ' r ' ) ; break ;
case ' \t ' : self - > OutStream ( self , ' t ' ) ; break ;
case ' \v ' : self - > OutStream ( self , ' v ' ) ; break ;
case ' \\ ' : self - > OutStream ( self , ' \\ ' ) ; break ;
default :
self - > OutStream ( self , ' x ' ) ;
TrioWriteNumber ( self , ( trio_intmax_t ) ch ,
FLAGS_UNSIGNED | FLAGS_NILPADDING ,
2 , 2 , BASE_HEX ) ;
break ;
}
}
else if ( ch = = CHAR_BACKSLASH )
{
self - > OutStream ( self , CHAR_BACKSLASH ) ;
self - > OutStream ( self , CHAR_BACKSLASH ) ;
}
else
{
self - > OutStream ( self , ch ) ;
}
}
else
{
self - > OutStream ( self , ch ) ;
}
}
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioWriteString [ private ]
*
* Description :
* Output a string
*/
static void
TrioWriteString ( trio_T * self ,
const char * string ,
2001-04-21 20:57:29 +04:00
unsigned long flags ,
2001-03-27 16:47:33 +04:00
int width ,
int precision )
{
int length ;
int ch ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > OutStream ) ) ;
if ( string = = NULL )
{
string = null ;
length = sizeof ( null ) - 1 ;
/* Disable quoting for the null pointer */
flags & = ( ~ FLAGS_QUOTE ) ;
width = 0 ;
}
else
{
length = StrLength ( string ) ;
}
if ( ( NO_PRECISION ! = precision ) & &
( precision < length ) )
{
length = precision ;
}
width - = length ;
if ( flags & FLAGS_QUOTE )
self - > OutStream ( self , CHAR_QUOTE ) ;
if ( ! ( flags & FLAGS_LEFTADJUST ) )
{
while ( width - - > 0 )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
while ( length - - > 0 )
{
/* The ctype parameters must be an unsigned char (or EOF) */
2001-06-05 16:46:33 +04:00
ch = ( int ) ( ( unsigned char ) ( * string + + ) ) ;
TrioWriteStringCharacter ( self , ch , flags ) ;
2001-03-27 16:47:33 +04:00
}
if ( flags & FLAGS_LEFTADJUST )
{
while ( width - - > 0 )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
if ( flags & FLAGS_QUOTE )
self - > OutStream ( self , CHAR_QUOTE ) ;
}
/*************************************************************************
2001-06-05 16:46:33 +04:00
* TrioWriteWideStringCharacter [ private ]
*
* Description :
* Output a wide string as a multi - byte sequence
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
static int
TrioWriteWideStringCharacter ( trio_T * self ,
wchar_t wch ,
unsigned long flags ,
int width )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
int size ;
2001-03-27 16:47:33 +04:00
int i ;
2001-06-05 16:46:33 +04:00
int ch ;
char * string ;
char buffer [ MB_LEN_MAX + 1 ] ;
2001-04-21 20:57:29 +04:00
2001-06-05 16:46:33 +04:00
if ( width = = NO_WIDTH )
width = sizeof ( buffer ) ;
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
size = wctomb ( buffer , wch ) ;
if ( ( size < = 0 ) | | ( size > width ) | | ( buffer [ 0 ] = = NIL ) )
return 0 ;
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
string = buffer ;
i = size ;
while ( ( width > = i ) & & ( width - - > 0 ) & & ( i - - > 0 ) )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
/* The ctype parameters must be an unsigned char (or EOF) */
ch = ( int ) ( ( unsigned char ) ( * string + + ) ) ;
TrioWriteStringCharacter ( self , ch , flags ) ;
}
return size ;
}
# endif /* TRIO_WIDECHAR */
/*************************************************************************
* TrioWriteString [ private ]
*
* Description :
* Output a wide character string as a multi - byte string
*/
# if TRIO_WIDECHAR
static void
TrioWriteWideString ( trio_T * self ,
const wchar_t * wstring ,
unsigned long flags ,
int width ,
int precision )
{
int length ;
int size ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > OutStream ) ) ;
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
mblen ( NULL , 0 ) ;
# endif
if ( wstring = = NULL )
{
TrioWriteString ( self , NULL , flags , width , precision ) ;
return ;
}
if ( NO_PRECISION = = precision )
{
length = INT_MAX ;
}
else
{
length = precision ;
width - = length ;
}
if ( flags & FLAGS_QUOTE )
self - > OutStream ( self , CHAR_QUOTE ) ;
if ( ! ( flags & FLAGS_LEFTADJUST ) )
{
while ( width - - > 0 )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
while ( length > 0 )
{
size = TrioWriteWideStringCharacter ( self , * wstring + + , flags , length ) ;
if ( size = = 0 )
break ; /* while */
length - = size ;
}
if ( flags & FLAGS_LEFTADJUST )
{
while ( width - - > 0 )
self - > OutStream ( self , CHAR_ADJUST ) ;
}
if ( flags & FLAGS_QUOTE )
self - > OutStream ( self , CHAR_QUOTE ) ;
}
# endif /* TRIO_WIDECHAR */
/*************************************************************************
* TrioWriteDouble [ private ]
*/
static void
TrioWriteDouble ( trio_T * self ,
long double longdoubleNumber ,
unsigned long flags ,
int width ,
int precision ,
int base )
{
int charsPerThousand ;
int length ;
double number ;
double workNumber ;
int integerDigits ;
int fractionDigits ;
int exponentDigits ;
int expectedWidth ;
int exponent ;
unsigned int uExponent = 0 ;
double dblBase ;
BOOLEAN_T isNegative ;
BOOLEAN_T isExponentNegative = FALSE ;
BOOLEAN_T isHex ;
const char * digits ;
char numberBuffer [ MAX_MANTISSA_DIGITS
* ( 1 + MAX_LOCALE_SEPARATOR_LENGTH ) + 1 ] ;
char * numberPointer ;
char exponentBuffer [ MAX_EXPONENT_DIGITS + 1 ] ;
char * exponentPointer = NULL ;
int groupingIndex ;
char * work ;
int i ;
BOOLEAN_T onlyzero ;
int zeroes = 0 ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > OutStream ) ) ;
assert ( base = = BASE_DECIMAL | | base = = BASE_HEX ) ;
number = ( double ) longdoubleNumber ;
/* Look for infinite numbers and non-a-number first */
switch ( TrioIsInfinite ( number ) )
{
case 1 :
/* Positive infinity */
TrioWriteString ( self ,
( flags & FLAGS_UPPER )
? INFINITE_UPPER
: INFINITE_LOWER ,
flags , width , precision ) ;
return ;
2001-03-27 16:47:33 +04:00
case - 1 :
2001-04-21 20:57:29 +04:00
/* Negative infinity */
2001-03-27 16:47:33 +04:00
TrioWriteString ( self ,
( flags & FLAGS_UPPER )
? " - " INFINITE_UPPER
: " - " INFINITE_LOWER ,
flags , width , precision ) ;
return ;
default :
2001-04-21 20:57:29 +04:00
/* Finitude */
2001-03-27 16:47:33 +04:00
break ;
}
2001-04-21 20:57:29 +04:00
if ( TrioIsNan ( number ) )
2001-03-27 16:47:33 +04:00
{
TrioWriteString ( self ,
( flags & FLAGS_UPPER )
? NAN_UPPER
: NAN_LOWER ,
2001-04-21 20:57:29 +04:00
flags , width , precision ) ;
2001-03-27 16:47:33 +04:00
return ;
}
/* Normal numbers */
2001-04-21 20:57:29 +04:00
digits = ( flags & FLAGS_UPPER ) ? internalDigitsUpper : internalDigitsLower ;
2001-03-27 16:47:33 +04:00
isHex = ( base = = BASE_HEX ) ;
dblBase = ( double ) base ;
if ( precision = = NO_PRECISION )
precision = FLT_DIG ;
isNegative = ( number < 0.0 ) ;
if ( isNegative )
number = - number ;
2001-06-05 16:46:33 +04:00
2001-03-27 16:47:33 +04:00
if ( ( flags & FLAGS_FLOAT_G ) | | isHex )
{
if ( precision = = 0 )
precision = 1 ;
2001-06-05 16:46:33 +04:00
if ( ( number < 1.0e-4 ) | | ( number > pow ( 10.0 , ( double ) precision ) ) )
{
/* Use scientific notation */
flags | = FLAGS_FLOAT_E ;
}
else if ( number < 1.0 )
{
/*
* Use normal notation . If the integer part of the number is
* zero , then adjust the precision to include leading fractional
* zeros .
*/
workNumber = fabs ( guarded_log10 ( number ) ) ;
if ( workNumber - floor ( workNumber ) < 0.001 )
workNumber - - ;
zeroes = ( int ) floor ( workNumber ) ;
}
2001-03-27 16:47:33 +04:00
}
if ( flags & FLAGS_FLOAT_E )
{
/* Scale the number */
2001-06-05 16:46:33 +04:00
workNumber = guarded_log10 ( number ) ;
2001-03-27 16:47:33 +04:00
if ( workNumber = = - HUGE_VAL )
{
exponent = 0 ;
/* Undo setting */
if ( flags & FLAGS_FLOAT_G )
flags & = ~ FLAGS_FLOAT_E ;
}
else
{
exponent = ( int ) floor ( workNumber ) ;
number / = pow ( 10.0 , ( double ) exponent ) ;
isExponentNegative = ( exponent < 0 ) ;
uExponent = ( isExponentNegative ) ? - exponent : exponent ;
/* No thousand separators */
flags & = ~ FLAGS_QUOTE ;
}
}
/*
* Truncated number .
*
* precision is number of significant digits for FLOAT_G
* and number of fractional digits for others
*/
2001-04-21 20:57:29 +04:00
integerDigits = ( floor ( number ) > DBL_EPSILON )
2001-06-05 16:46:33 +04:00
? 1 + ( int ) guarded_log10 ( floor ( number ) )
2001-03-27 16:47:33 +04:00
: 1 ;
2001-06-05 16:46:33 +04:00
fractionDigits = ( ( flags & FLAGS_FLOAT_G ) & & ( zeroes = = 0 ) )
2001-03-27 16:47:33 +04:00
? precision - integerDigits
2001-06-05 16:46:33 +04:00
: zeroes + precision ;
number = floor ( 0.5 + number * pow ( dblBase , ( double ) fractionDigits ) ) ;
workNumber = ( isHex
? guarded_log16 ( 0.5 + number )
: guarded_log10 ( 0.5 + number ) ) ;
if ( ( int ) workNumber + 1 > integerDigits + fractionDigits )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
if ( flags & FLAGS_FLOAT_E )
{
/* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
exponent - - ;
uExponent - = ( isExponentNegative ) ? 1 : - 1 ;
number / = dblBase ;
}
else
{
/* Adjust if number was rounded up one digit (ie. 99 to 100) */
integerDigits + + ;
}
2001-03-27 16:47:33 +04:00
}
/* Build the fraction part */
numberPointer = & numberBuffer [ sizeof ( numberBuffer ) - 1 ] ;
* numberPointer = NIL ;
onlyzero = TRUE ;
for ( i = 0 ; i < fractionDigits ; i + + )
{
* ( - - numberPointer ) = digits [ ( int ) fmod ( number , dblBase ) ] ;
number = floor ( number / dblBase ) ;
2001-04-21 20:57:29 +04:00
2001-06-05 16:46:33 +04:00
if ( ( flags & FLAGS_FLOAT_G ) & & ! ( flags & FLAGS_ALTERNATIVE ) )
{
/* Prune trailing zeroes */
if ( numberPointer [ 0 ] ! = digits [ 0 ] )
onlyzero = FALSE ;
else if ( onlyzero & & ( numberPointer [ 0 ] = = digits [ 0 ] ) )
numberPointer + + ;
}
2001-04-21 20:57:29 +04:00
else
onlyzero = FALSE ;
2001-03-27 16:47:33 +04:00
}
/* Insert decimal point */
if ( ( flags & FLAGS_ALTERNATIVE ) | | ( ( fractionDigits > 0 ) & & ! onlyzero ) )
{
2001-04-21 20:57:29 +04:00
i = StrLength ( internalDecimalPoint ) ;
2001-03-27 16:47:33 +04:00
while ( i > 0 )
{
2001-04-21 20:57:29 +04:00
* ( - - numberPointer ) = internalDecimalPoint [ - - i ] ;
2001-03-27 16:47:33 +04:00
}
}
/* Insert the integer part and thousand separators */
2001-04-21 20:57:29 +04:00
charsPerThousand = ( int ) internalGrouping [ 0 ] ;
2001-03-27 16:47:33 +04:00
groupingIndex = 1 ;
for ( i = 1 ; i < integerDigits + 1 ; i + + )
{
* ( - - numberPointer ) = digits [ ( int ) fmod ( number , dblBase ) ] ;
number = floor ( number / dblBase ) ;
if ( number < DBL_EPSILON )
break ;
if ( ( i > 0 )
& & ( ( flags & ( FLAGS_FLOAT_E | FLAGS_QUOTE ) ) = = FLAGS_QUOTE )
& & ( charsPerThousand ! = NO_GROUPING )
& & ( i % charsPerThousand = = 0 ) )
{
/*
* We are building the number from the least significant
* to the most significant digit , so we have to copy the
* thousand separator backwards
*/
2001-04-21 20:57:29 +04:00
length = StrLength ( internalThousandSeparator ) ;
2001-03-27 16:47:33 +04:00
integerDigits + = length ;
if ( ( ( int ) ( numberPointer - numberBuffer ) - length ) > 0 )
{
2001-04-21 20:57:29 +04:00
work = & internalThousandSeparator [ length - 1 ] ;
2001-03-27 16:47:33 +04:00
while ( length - - > 0 )
* ( - - numberPointer ) = * work - - ;
}
/* Advance to next grouping number */
if ( charsPerThousand ! = NO_GROUPING )
{
2001-04-21 20:57:29 +04:00
switch ( internalGrouping [ groupingIndex ] )
2001-03-27 16:47:33 +04:00
{
case CHAR_MAX : /* Disable grouping */
charsPerThousand = NO_GROUPING ;
break ;
case 0 : /* Repeat last group */
break ;
default :
2001-04-21 20:57:29 +04:00
charsPerThousand = ( int ) internalGrouping [ groupingIndex + + ] ;
2001-03-27 16:47:33 +04:00
break ;
}
}
}
}
/* Build the exponent */
exponentDigits = 0 ;
if ( flags & FLAGS_FLOAT_E )
{
exponentPointer = & exponentBuffer [ sizeof ( exponentBuffer ) - 1 ] ;
* exponentPointer - - = NIL ;
do {
* exponentPointer - - = digits [ uExponent % base ] ;
uExponent / = base ;
exponentDigits + + ;
} while ( uExponent ) ;
}
2001-04-21 20:57:29 +04:00
/*
* Calculate expected width .
2001-03-27 16:47:33 +04:00
* sign + integer part + thousands separators + decimal point
* + fraction + exponent
*/
expectedWidth = StrLength ( numberPointer ) ;
if ( isNegative | | ( flags & FLAGS_SHOWSIGN ) )
expectedWidth + = sizeof ( " - " ) - 1 ;
if ( exponentDigits > 0 )
2001-06-05 16:46:33 +04:00
expectedWidth + = exponentDigits +
( ( exponentDigits > 1 ) ? sizeof ( " E+ " ) : sizeof ( " E+0 " ) ) - 1 ;
2001-03-27 16:47:33 +04:00
if ( isHex )
expectedWidth + = sizeof ( " 0X " ) - 1 ;
/* Output prefixing */
if ( flags & FLAGS_NILPADDING )
{
/* Leading zeros must be after sign */
if ( isNegative )
self - > OutStream ( self , ' - ' ) ;
else if ( flags & FLAGS_SHOWSIGN )
self - > OutStream ( self , ' + ' ) ;
if ( isHex )
{
self - > OutStream ( self , ' 0 ' ) ;
self - > OutStream ( self , ( flags & FLAGS_UPPER ) ? ' X ' : ' x ' ) ;
}
if ( ! ( flags & FLAGS_LEFTADJUST ) )
{
for ( i = expectedWidth ; i < width ; i + + )
{
self - > OutStream ( self , ' 0 ' ) ;
}
}
}
else
{
/* Leading spaces must be before sign */
if ( ! ( flags & FLAGS_LEFTADJUST ) )
{
for ( i = expectedWidth ; i < width ; i + + )
{
self - > OutStream ( self , CHAR_ADJUST ) ;
}
}
if ( isNegative )
self - > OutStream ( self , ' - ' ) ;
else if ( flags & FLAGS_SHOWSIGN )
self - > OutStream ( self , ' + ' ) ;
if ( isHex )
{
self - > OutStream ( self , ' 0 ' ) ;
self - > OutStream ( self , ( flags & FLAGS_UPPER ) ? ' X ' : ' x ' ) ;
}
}
/* Output number */
for ( i = 0 ; numberPointer [ i ] ; i + + )
{
self - > OutStream ( self , numberPointer [ i ] ) ;
}
/* Output exponent */
if ( exponentDigits > 0 )
{
self - > OutStream ( self ,
isHex
? ( ( flags & FLAGS_UPPER ) ? ' P ' : ' p ' )
: ( ( flags & FLAGS_UPPER ) ? ' E ' : ' e ' ) ) ;
self - > OutStream ( self , ( isExponentNegative ) ? ' - ' : ' + ' ) ;
2001-06-05 16:46:33 +04:00
/* The exponent must contain at least two digits */
if ( exponentDigits = = 1 )
self - > OutStream ( self , ' 0 ' ) ;
2001-03-27 16:47:33 +04:00
for ( i = 0 ; i < exponentDigits ; i + + )
{
self - > OutStream ( self , exponentPointer [ i + 1 ] ) ;
}
}
/* Output trailing spaces */
if ( flags & FLAGS_LEFTADJUST )
{
for ( i = expectedWidth ; i < width ; i + + )
{
self - > OutStream ( self , CHAR_ADJUST ) ;
}
}
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* TrioFormatProcess [ private ]
2001-03-27 16:47:33 +04:00
*/
static int
2001-04-21 20:57:29 +04:00
TrioFormatProcess ( trio_T * data ,
const char * format ,
parameter_T * parameters )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
int charlen ;
# endif
int i ;
const char * string ;
void * pointer ;
2001-04-21 20:57:29 +04:00
unsigned long flags ;
2001-03-27 16:47:33 +04:00
int width ;
int precision ;
int base ;
int index ;
2001-04-21 20:57:29 +04:00
2001-03-27 16:47:33 +04:00
index = 0 ;
i = 0 ;
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
mblen ( NULL , 0 ) ;
# endif
while ( format [ index ] )
{
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
if ( ! isascii ( format [ index ] ) )
{
charlen = mblen ( & format [ index ] , MB_LEN_MAX ) ;
while ( charlen - - > 0 )
{
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , format [ index + + ] ) ;
2001-03-27 16:47:33 +04:00
}
continue ; /* while */
}
2001-06-05 16:46:33 +04:00
# endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
2001-03-27 16:47:33 +04:00
if ( CHAR_IDENTIFIER = = format [ index ] )
{
if ( CHAR_IDENTIFIER = = format [ index + 1 ] )
{
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , CHAR_IDENTIFIER ) ;
2001-03-27 16:47:33 +04:00
index + = 2 ;
}
else
{
/* Skip the parameter entries */
while ( parameters [ i ] . type = = FORMAT_PARAMETER )
i + + ;
flags = parameters [ i ] . flags ;
/* Find width */
width = parameters [ i ] . width ;
if ( flags & FLAGS_WIDTH_PARAMETER )
{
/* Get width from parameter list */
2001-04-21 20:57:29 +04:00
width = ( int ) parameters [ width ] . data . number . as_signed ;
2001-03-27 16:47:33 +04:00
}
/* Find precision */
if ( flags & FLAGS_PRECISION )
{
precision = parameters [ i ] . precision ;
if ( flags & FLAGS_PRECISION_PARAMETER )
{
/* Get precision from parameter list */
2001-04-21 20:57:29 +04:00
precision = ( int ) parameters [ precision ] . data . number . as_signed ;
2001-03-27 16:47:33 +04:00
}
}
else
{
precision = NO_PRECISION ;
}
/* Find base */
base = parameters [ i ] . base ;
if ( flags & FLAGS_BASE_PARAMETER )
{
/* Get base from parameter list */
2001-04-21 20:57:29 +04:00
base = ( int ) parameters [ base ] . data . number . as_signed ;
2001-03-27 16:47:33 +04:00
}
switch ( parameters [ i ] . type )
{
case FORMAT_CHAR :
if ( flags & FLAGS_QUOTE )
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , CHAR_QUOTE ) ;
2001-03-27 16:47:33 +04:00
if ( ! ( flags & FLAGS_LEFTADJUST ) )
{
while ( - - width > 0 )
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , CHAR_ADJUST ) ;
2001-03-27 16:47:33 +04:00
}
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
if ( flags & FLAGS_WIDECHAR )
{
TrioWriteWideStringCharacter ( data ,
( wchar_t ) parameters [ i ] . data . number . as_signed ,
flags ,
NO_WIDTH ) ;
}
else
# endif
TrioWriteStringCharacter ( data ,
( int ) parameters [ i ] . data . number . as_signed ,
flags ) ;
2001-03-27 16:47:33 +04:00
if ( flags & FLAGS_LEFTADJUST )
{
while ( - - width > 0 )
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , CHAR_ADJUST ) ;
2001-03-27 16:47:33 +04:00
}
if ( flags & FLAGS_QUOTE )
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , CHAR_QUOTE ) ;
2001-03-27 16:47:33 +04:00
break ; /* FORMAT_CHAR */
case FORMAT_INT :
if ( base = = NO_BASE )
base = BASE_DECIMAL ;
TrioWriteNumber ( data ,
2001-04-21 20:57:29 +04:00
parameters [ i ] . data . number . as_signed ,
2001-03-27 16:47:33 +04:00
flags ,
width ,
precision ,
base ) ;
break ; /* FORMAT_INT */
case FORMAT_DOUBLE :
TrioWriteDouble ( data ,
parameters [ i ] . data . longdoubleNumber ,
flags ,
width ,
precision ,
base ) ;
break ; /* FORMAT_DOUBLE */
case FORMAT_STRING :
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
if ( flags & FLAGS_WIDECHAR )
{
TrioWriteWideString ( data ,
parameters [ i ] . data . wstring ,
flags ,
width ,
precision ) ;
}
else
# endif
{
TrioWriteString ( data ,
parameters [ i ] . data . string ,
flags ,
width ,
precision ) ;
}
2001-03-27 16:47:33 +04:00
break ; /* FORMAT_STRING */
case FORMAT_POINTER :
2001-04-21 20:57:29 +04:00
{
reference_T reference ;
reference . data = data ;
reference . parameter = & parameters [ i ] ;
trio_print_pointer ( & reference , parameters [ i ] . data . pointer ) ;
}
2001-03-27 16:47:33 +04:00
break ; /* FORMAT_POINTER */
case FORMAT_COUNT :
pointer = parameters [ i ] . data . pointer ;
if ( NULL ! = pointer )
{
2001-04-21 20:57:29 +04:00
/*
* C99 paragraph 7.19 .6 .1 .8 says " the number of
2001-03-27 16:47:33 +04:00
* characters written to the output stream so far by
* this call " , which is data->committed
*/
# if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
if ( flags & FLAGS_SIZE_T )
* ( size_t * ) pointer = ( size_t ) data - > committed ;
else
# endif
# if defined(QUALIFIER_PTRDIFF_T)
if ( flags & FLAGS_PTRDIFF_T )
* ( ptrdiff_t * ) pointer = ( ptrdiff_t ) data - > committed ;
else
# endif
# if defined(QUALIFIER_INTMAX_T)
if ( flags & FLAGS_INTMAX_T )
2001-06-05 16:46:33 +04:00
* ( trio_intmax_t * ) pointer = ( trio_intmax_t ) data - > committed ;
2001-03-27 16:47:33 +04:00
else
# endif
if ( flags & FLAGS_QUAD )
{
2001-06-05 16:46:33 +04:00
* ( trio_ulonglong_t * ) pointer = ( trio_ulonglong_t ) data - > committed ;
2001-03-27 16:47:33 +04:00
}
else if ( flags & FLAGS_LONG )
{
* ( long int * ) pointer = ( long int ) data - > committed ;
}
else if ( flags & FLAGS_SHORT )
{
* ( short int * ) pointer = ( short int ) data - > committed ;
}
else
{
* ( int * ) pointer = ( int ) data - > committed ;
}
}
break ; /* FORMAT_COUNT */
case FORMAT_PARAMETER :
break ; /* FORMAT_PARAMETER */
# if defined(FORMAT_ERRNO)
case FORMAT_ERRNO :
string = StrError ( parameters [ i ] . data . errorNumber ) ;
if ( string )
{
TrioWriteString ( data ,
string ,
flags ,
width ,
precision ) ;
}
else
{
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , ' # ' ) ;
2001-03-27 16:47:33 +04:00
TrioWriteNumber ( data ,
2001-06-05 16:46:33 +04:00
( trio_intmax_t ) parameters [ i ] . data . errorNumber ,
2001-03-27 16:47:33 +04:00
flags ,
width ,
precision ,
BASE_DECIMAL ) ;
}
break ; /* FORMAT_ERRNO */
2001-04-21 20:57:29 +04:00
# endif /* defined(FORMAT_ERRNO) */
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
# if defined(FORMAT_USER_DEFINED)
case FORMAT_USER_DEFINED :
{
reference_T reference ;
userdef_T * def = NULL ;
if ( parameters [ i ] . user_name [ 0 ] = = NIL )
{
/* Use handle */
if ( ( i > 0 ) | |
( parameters [ i - 1 ] . type = = FORMAT_PARAMETER ) )
def = ( userdef_T * ) parameters [ i - 1 ] . data . pointer ;
}
else
{
/* Look up namespace */
def = TrioFindNamespace ( parameters [ i ] . user_name , NULL ) ;
}
if ( def ) {
reference . data = data ;
reference . parameter = & parameters [ i ] ;
def - > callback ( & reference ) ;
}
}
break ;
# endif /* defined(FORMAT_USER_DEFINED) */
2001-03-27 16:47:33 +04:00
default :
break ;
} /* switch parameter type */
/* Prepare for next */
index = parameters [ i ] . indexAfterSpecifier ;
i + + ;
}
}
else /* not identifier */
{
2001-04-21 20:57:29 +04:00
data - > OutStream ( data , format [ index + + ] ) ;
2001-03-27 16:47:33 +04:00
}
}
return data - > processed ;
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* TrioFormatRef [ private ]
2001-03-27 16:47:33 +04:00
*/
2001-04-21 20:57:29 +04:00
static int
TrioFormatRef ( reference_T * reference ,
const char * format ,
va_list arglist ,
void * * argarray )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
int status ;
parameter_T parameters [ MAX_PARAMETERS ] ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
status = TrioPreprocess ( TYPE_PRINT , format , parameters , arglist , argarray ) ;
if ( status < 0 )
return status ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
return TrioFormatProcess ( reference - > data , format , parameters ) ;
2001-03-27 16:47:33 +04:00
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* TrioFormat [ private ]
*
* Description :
* This is the main engine for formatting output
2001-03-27 16:47:33 +04:00
*/
2001-04-21 20:57:29 +04:00
static int
TrioFormat ( void * destination ,
size_t destinationSize ,
void ( * OutStream ) ( trio_T * , int ) ,
const char * format ,
va_list arglist ,
void * * argarray )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
int status ;
trio_T data ;
parameter_T parameters [ MAX_PARAMETERS ] ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
assert ( VALID ( OutStream ) ) ;
assert ( VALID ( format ) ) ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
memset ( & data , 0 , sizeof ( data ) ) ;
data . OutStream = OutStream ;
data . location = destination ;
data . max = destinationSize ;
# if defined(USE_LOCALE)
if ( NULL = = internalLocaleValues )
{
TrioSetLocale ( ) ;
}
# endif
status = TrioPreprocess ( TYPE_PRINT , format , parameters , arglist , argarray ) ;
if ( status < 0 )
return status ;
return TrioFormatProcess ( & data , format , parameters ) ;
}
/*************************************************************************
* TrioOutStreamFile [ private ]
*/
static void
TrioOutStreamFile ( trio_T * self ,
int output )
{
FILE * file = ( FILE * ) self - > location ;
assert ( VALID ( self ) ) ;
assert ( VALID ( file ) ) ;
self - > processed + + ;
self - > committed + + ;
( void ) fputc ( output , file ) ;
}
/*************************************************************************
* TrioOutStreamFileDescriptor [ private ]
*/
static void
TrioOutStreamFileDescriptor ( trio_T * self ,
int output )
{
int fd = * ( ( int * ) self - > location ) ;
char ch ;
assert ( VALID ( self ) ) ;
ch = ( char ) output ;
2001-03-27 16:47:33 +04:00
( void ) write ( fd , & ch , sizeof ( char ) ) ;
self - > processed + + ;
self - > committed + + ;
}
/*************************************************************************
* TrioOutStreamString [ private ]
*/
static void
2001-04-21 20:57:29 +04:00
TrioOutStreamString ( trio_T * self ,
int output )
2001-03-27 16:47:33 +04:00
{
char * * buffer = ( char * * ) self - > location ;
assert ( VALID ( self ) ) ;
assert ( VALID ( buffer ) ) ;
* * buffer = ( char ) output ;
( * buffer ) + + ;
self - > processed + + ;
self - > committed + + ;
}
/*************************************************************************
* TrioOutStreamStringMax [ private ]
*/
static void
2001-04-21 20:57:29 +04:00
TrioOutStreamStringMax ( trio_T * self ,
int output )
2001-03-27 16:47:33 +04:00
{
char * * buffer ;
assert ( VALID ( self ) ) ;
buffer = ( char * * ) self - > location ;
assert ( VALID ( buffer ) ) ;
if ( self - > processed < self - > max )
{
* * buffer = ( char ) output ;
( * buffer ) + + ;
self - > committed + + ;
}
self - > processed + + ;
}
/*************************************************************************
* TrioOutStreamStringDynamic [ private ]
*/
# define DYNAMIC_START_SIZE 32
struct dynamicBuffer {
char * buffer ;
size_t length ;
size_t allocated ;
} ;
static void
2001-04-21 20:57:29 +04:00
TrioOutStreamStringDynamic ( trio_T * self ,
int output )
2001-03-27 16:47:33 +04:00
{
struct dynamicBuffer * infop ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > location ) ) ;
infop = ( struct dynamicBuffer * ) self - > location ;
if ( infop - > buffer = = NULL )
{
/* Start with a reasonable size */
2001-06-05 16:46:33 +04:00
infop - > buffer = ( char * ) TRIO_MALLOC ( DYNAMIC_START_SIZE ) ;
2001-03-27 16:47:33 +04:00
if ( infop - > buffer = = NULL )
return ; /* fail */
infop - > allocated = DYNAMIC_START_SIZE ;
self - > processed = 0 ;
self - > committed = 0 ;
}
else if ( self - > committed + sizeof ( NIL ) > = infop - > allocated )
{
char * newptr ;
/* Allocate increasing chunks */
2001-06-05 16:46:33 +04:00
newptr = ( char * ) TRIO_REALLOC ( infop - > buffer , infop - > allocated * 2 ) ;
2001-03-27 16:47:33 +04:00
if ( newptr = = NULL )
return ;
infop - > buffer = newptr ;
infop - > allocated * = 2 ;
}
2001-06-05 16:46:33 +04:00
infop - > buffer [ self - > committed ] = ( char ) output ;
2001-03-27 16:47:33 +04:00
self - > committed + + ;
self - > processed + + ;
infop - > length = self - > committed ;
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* printf
*/
int
trio_printf ( const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioFormat ( stdout , 0 , TrioOutStreamFile , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vprintf ( const char * format ,
va_list args )
{
assert ( VALID ( format ) ) ;
return TrioFormat ( stdout , 0 , TrioOutStreamFile , format , args , NULL ) ;
}
int
trio_printfv ( const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioFormat ( stdout , 0 , TrioOutStreamFile , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* fprintf
*/
int
trio_fprintf ( FILE * file ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioFormat ( file , 0 , TrioOutStreamFile , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vfprintf ( FILE * file ,
const char * format ,
va_list args )
{
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
return TrioFormat ( file , 0 , TrioOutStreamFile , format , args , NULL ) ;
}
int
trio_fprintfv ( FILE * file ,
const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioFormat ( file , 0 , TrioOutStreamFile , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* dprintf
*/
int
trio_dprintf ( int fd ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioFormat ( & fd , 0 , TrioOutStreamFileDescriptor , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vdprintf ( int fd ,
const char * format ,
va_list args )
{
assert ( VALID ( format ) ) ;
return TrioFormat ( & fd , 0 , TrioOutStreamFileDescriptor , format , args , NULL ) ;
}
int
trio_dprintfv ( int fd ,
const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioFormat ( & fd , 0 , TrioOutStreamFileDescriptor , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* sprintf
*/
int
trio_sprintf ( char * buffer ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioFormat ( & buffer , 0 , TrioOutStreamString , format , args , NULL ) ;
* buffer = NIL ; /* Terminate with NIL character */
va_end ( args ) ;
return status ;
}
int
trio_vsprintf ( char * buffer ,
const char * format ,
va_list args )
{
int status ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
status = TrioFormat ( & buffer , 0 , TrioOutStreamString , format , args , NULL ) ;
* buffer = NIL ;
return status ;
}
int
trio_sprintfv ( char * buffer ,
const char * format ,
void * * args )
{
int status ;
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
status = TrioFormat ( & buffer , 0 , TrioOutStreamString , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
* buffer = NIL ;
return status ;
}
/*************************************************************************
* snprintf
*/
int
trio_snprintf ( char * buffer ,
size_t bufferSize ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioFormat ( & buffer , bufferSize > 0 ? bufferSize - 1 : 0 ,
TrioOutStreamStringMax , format , args , NULL ) ;
if ( bufferSize > 0 )
* buffer = NIL ;
va_end ( args ) ;
return status ;
}
int
trio_vsnprintf ( char * buffer ,
size_t bufferSize ,
const char * format ,
va_list args )
{
int status ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
status = TrioFormat ( & buffer , bufferSize > 0 ? bufferSize - 1 : 0 ,
TrioOutStreamStringMax , format , args , NULL ) ;
if ( bufferSize > 0 )
* buffer = NIL ;
return status ;
}
int
trio_snprintfv ( char * buffer ,
size_t bufferSize ,
const char * format ,
void * * args )
{
int status ;
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
status = TrioFormat ( & buffer , bufferSize > 0 ? bufferSize - 1 : 0 ,
2001-06-05 16:46:33 +04:00
TrioOutStreamStringMax , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
if ( bufferSize > 0 )
* buffer = NIL ;
return status ;
}
/*************************************************************************
* snprintfcat
* Appends the new string to the buffer string overwriting the ' \0 '
* character at the end of buffer .
*/
int
trio_snprintfcat ( char * buffer ,
size_t bufferSize ,
const char * format ,
. . . )
{
int status ;
va_list args ;
size_t buf_len ;
va_start ( args , format ) ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
buf_len = strlen ( buffer ) ;
buffer = & buffer [ buf_len ] ;
status = TrioFormat ( & buffer , bufferSize - 1 - buf_len ,
TrioOutStreamStringMax , format , args , NULL ) ;
va_end ( args ) ;
* buffer = NIL ;
return status ;
}
int
trio_vsnprintfcat ( char * buffer ,
size_t bufferSize ,
const char * format ,
va_list args )
{
int status ;
size_t buf_len ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
buf_len = strlen ( buffer ) ;
buffer = & buffer [ buf_len ] ;
status = TrioFormat ( & buffer , bufferSize - 1 - buf_len ,
TrioOutStreamStringMax , format , args , NULL ) ;
* buffer = NIL ;
return status ;
}
/*************************************************************************
* trio_aprintf
*/
/* Deprecated */
char *
trio_aprintf ( const char * format ,
. . . )
{
va_list args ;
struct dynamicBuffer info ;
assert ( VALID ( format ) ) ;
info . buffer = NULL ;
info . length = 0 ;
info . allocated = 0 ;
va_start ( args , format ) ;
( void ) TrioFormat ( & info , 0 , TrioOutStreamStringDynamic , format , args , NULL ) ;
va_end ( args ) ;
if ( info . length ) {
info . buffer [ info . length ] = NIL ; /* we terminate this with a zero byte */
return info . buffer ;
}
else
return NULL ;
}
/* Deprecated */
char *
trio_vaprintf ( const char * format ,
va_list args )
{
struct dynamicBuffer info ;
assert ( VALID ( format ) ) ;
info . buffer = NULL ;
info . length = 0 ;
info . allocated = 0 ;
( void ) TrioFormat ( & info , 0 , TrioOutStreamStringDynamic , format , args , NULL ) ;
if ( info . length ) {
info . buffer [ info . length ] = NIL ; /* we terminate this with a zero byte */
return info . buffer ;
}
else
return NULL ;
}
int
trio_asprintf ( char * * result ,
const char * format ,
. . . )
{
va_list args ;
int status ;
struct dynamicBuffer info ;
assert ( VALID ( format ) ) ;
info . buffer = NULL ;
info . length = 0 ;
info . allocated = 0 ;
va_start ( args , format ) ;
status = TrioFormat ( & info , 0 , TrioOutStreamStringDynamic , format , args , NULL ) ;
va_end ( args ) ;
if ( status < 0 ) {
* result = NULL ;
return status ;
}
if ( info . length = = 0 ) {
/*
* If the length is zero , no characters have been written and therefore
* no memory has been allocated , but we must to allocate and return an
* empty string .
*/
2001-06-05 16:46:33 +04:00
info . buffer = ( char * ) TRIO_MALLOC ( sizeof ( char ) ) ;
2001-04-21 20:57:29 +04:00
if ( info . buffer = = NULL ) {
* result = NULL ;
return TRIO_ERROR_RETURN ( TRIO_ENOMEM , 0 ) ;
}
}
info . buffer [ info . length ] = NIL ; /* we terminate this with a zero byte */
* result = info . buffer ;
return status ;
}
int
trio_vasprintf ( char * * result ,
const char * format ,
va_list args )
{
int status ;
struct dynamicBuffer info ;
assert ( VALID ( format ) ) ;
info . buffer = NULL ;
info . length = 0 ;
info . allocated = 0 ;
status = TrioFormat ( & info , 0 , TrioOutStreamStringDynamic , format , args , NULL ) ;
if ( status < 0 ) {
* result = NULL ;
return status ;
}
if ( info . length = = 0 ) {
2001-06-05 16:46:33 +04:00
info . buffer = ( char * ) TRIO_MALLOC ( sizeof ( char ) ) ;
2001-04-21 20:57:29 +04:00
if ( info . buffer = = NULL ) {
* result = NULL ;
return TRIO_ERROR_RETURN ( TRIO_ENOMEM , 0 ) ;
}
}
info . buffer [ info . length ] = NIL ; /* we terminate this with a zero byte */
* result = info . buffer ;
return status ;
}
/*************************************************************************
*
* @ CALLBACK
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*************************************************************************
* trio_register [ public ]
*/
void *
trio_register ( trio_callback_t callback ,
const char * name )
{
userdef_T * def ;
userdef_T * prev = NULL ;
if ( callback = = NULL )
return NULL ;
if ( name )
{
2001-06-05 16:46:33 +04:00
/* Handle built-in namespaces */
if ( name [ 0 ] = = ' : ' )
{
if ( StrEqual ( name , " :enter " ) )
{
internalEnterCriticalRegion = callback ;
}
else if ( StrEqual ( name , " :leave " ) )
{
internalLeaveCriticalRegion = callback ;
}
return NULL ;
}
2001-04-21 20:57:29 +04:00
/* Bail out if namespace is too long */
if ( StrLength ( name ) > = MAX_USER_NAME )
return NULL ;
/* Bail out if namespace already is registered */
def = TrioFindNamespace ( name , & prev ) ;
if ( def )
return NULL ;
}
2001-06-05 16:46:33 +04:00
def = ( userdef_T * ) TRIO_MALLOC ( sizeof ( userdef_T ) ) ;
2001-04-21 20:57:29 +04:00
if ( def )
{
2001-06-05 16:46:33 +04:00
if ( internalEnterCriticalRegion )
( void ) internalEnterCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
if ( name )
{
/* Link into internal list */
if ( prev = = NULL )
internalUserDef = def ;
else
prev - > next = def ;
}
/* Initialize */
def - > callback = callback ;
def - > name = ( name = = NULL )
? NULL
: StrDuplicate ( name ) ;
def - > next = NULL ;
2001-06-05 16:46:33 +04:00
if ( internalLeaveCriticalRegion )
( void ) internalLeaveCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
}
return def ;
}
/*************************************************************************
* trio_unregister [ public ]
*/
void
trio_unregister ( void * handle )
{
userdef_T * self = ( userdef_T * ) handle ;
userdef_T * def ;
userdef_T * prev = NULL ;
assert ( VALID ( self ) ) ;
if ( self - > name )
{
def = TrioFindNamespace ( self - > name , & prev ) ;
if ( def )
{
2001-06-05 16:46:33 +04:00
if ( internalEnterCriticalRegion )
( void ) internalEnterCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
if ( prev = = NULL )
internalUserDef = NULL ;
else
prev - > next = def - > next ;
2001-06-05 16:46:33 +04:00
if ( internalLeaveCriticalRegion )
( void ) internalLeaveCriticalRegion ( NULL ) ;
2001-04-21 20:57:29 +04:00
}
StrFree ( self - > name ) ;
}
2001-06-05 16:46:33 +04:00
TRIO_FREE ( self ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* trio_get_format [ public ]
*/
const char *
trio_get_format ( void * ref )
{
assert ( ( ( reference_T * ) ref ) - > parameter - > type = = FORMAT_USER_DEFINED ) ;
return ( ( ( reference_T * ) ref ) - > parameter - > user_data ) ;
}
/*************************************************************************
* trio_get_argument [ public ]
*/
void *
trio_get_argument ( void * ref )
{
assert ( ( ( reference_T * ) ref ) - > parameter - > type = = FORMAT_USER_DEFINED ) ;
return ( ( reference_T * ) ref ) - > parameter - > data . pointer ;
}
/*************************************************************************
* trio_get_width / trio_set_width [ public ]
*/
int
trio_get_width ( void * ref )
{
return ( ( reference_T * ) ref ) - > parameter - > width ;
}
void
trio_set_width ( void * ref ,
int width )
{
( ( reference_T * ) ref ) - > parameter - > width = width ;
}
/*************************************************************************
* trio_get_precision / trio_set_precision [ public ]
*/
int
trio_get_precision ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > precision ) ;
}
void
trio_set_precision ( void * ref ,
int precision )
{
( ( reference_T * ) ref ) - > parameter - > precision = precision ;
}
/*************************************************************************
* trio_get_base / trio_set_base [ public ]
*/
int
trio_get_base ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > base ) ;
}
void
trio_set_base ( void * ref ,
int base )
{
( ( reference_T * ) ref ) - > parameter - > base = base ;
}
/*************************************************************************
* trio_get_long / trio_set_long [ public ]
*/
int
trio_get_long ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_LONG ) ;
}
void
trio_set_long ( void * ref ,
int is_long )
{
if ( is_long )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_LONG ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_LONG ;
}
/*************************************************************************
* trio_get_longlong / trio_set_longlong [ public ]
*/
int
trio_get_longlong ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_QUAD ) ;
}
void
trio_set_longlong ( void * ref ,
int is_longlong )
{
if ( is_longlong )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_QUAD ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_QUAD ;
}
/*************************************************************************
* trio_get_longdouble / trio_set_longdouble [ public ]
*/
int
trio_get_longdouble ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_LONGDOUBLE ) ;
}
void
trio_set_longdouble ( void * ref ,
int is_longdouble )
{
if ( is_longdouble )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_LONGDOUBLE ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_LONGDOUBLE ;
}
/*************************************************************************
* trio_get_short / trio_set_short [ public ]
*/
int
trio_get_short ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_SHORT ) ;
}
void
trio_set_short ( void * ref ,
int is_short )
{
if ( is_short )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_SHORT ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_SHORT ;
}
/*************************************************************************
* trio_get_shortshort / trio_set_shortshort [ public ]
*/
int
trio_get_shortshort ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_SHORTSHORT ) ;
}
void
trio_set_shortshort ( void * ref ,
int is_shortshort )
{
if ( is_shortshort )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_SHORTSHORT ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_SHORTSHORT ;
}
/*************************************************************************
* trio_get_alternative / trio_set_alternative [ public ]
*/
int
trio_get_alternative ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_ALTERNATIVE ) ;
}
void
trio_set_alternative ( void * ref ,
int is_alternative )
{
if ( is_alternative )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_ALTERNATIVE ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_ALTERNATIVE ;
}
/*************************************************************************
* trio_get_alignment / trio_set_alignment [ public ]
*/
int
trio_get_alignment ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_LEFTADJUST ) ;
}
void
trio_set_alignment ( void * ref ,
int is_leftaligned )
{
if ( is_leftaligned )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_LEFTADJUST ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_LEFTADJUST ;
}
/*************************************************************************
* trio_get_spacing / trio_set_spacing [ public ]
*/
int
trio_get_spacing ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_SPACE ) ;
}
void
trio_set_spacing ( void * ref ,
int is_space )
{
if ( is_space )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_SPACE ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_SPACE ;
}
/*************************************************************************
* trio_get_sign / trio_set_sign [ public ]
*/
int
trio_get_sign ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_SHOWSIGN ) ;
}
void
trio_set_sign ( void * ref ,
int is_sign )
{
if ( is_sign )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_SHOWSIGN ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_SHOWSIGN ;
}
/*************************************************************************
* trio_get_padding / trio_set_padding [ public ]
*/
int
trio_get_padding ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_NILPADDING ) ;
}
void
trio_set_padding ( void * ref ,
int is_padding )
{
if ( is_padding )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_NILPADDING ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_NILPADDING ;
}
/*************************************************************************
* trio_get_quote / trio_set_quote [ public ]
*/
int
trio_get_quote ( void * ref )
{
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_QUOTE ) ;
}
void
trio_set_quote ( void * ref ,
int is_quote )
{
if ( is_quote )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_QUOTE ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_QUOTE ;
}
/*************************************************************************
* trio_get_upper / trio_set_upper [ public ]
2001-03-27 16:47:33 +04:00
*/
int
2001-04-21 20:57:29 +04:00
trio_get_upper ( void * ref )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_UPPER ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
void
trio_set_upper ( void * ref ,
int is_upper )
{
if ( is_upper )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_UPPER ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_UPPER ;
2001-03-27 16:47:33 +04:00
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_get_largest / trio_set_largest [ public ]
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
# if TRIO_C99
2001-03-27 16:47:33 +04:00
int
2001-04-21 20:57:29 +04:00
trio_get_largest ( void * ref )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_INTMAX_T ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
void
trio_set_largest ( void * ref ,
int is_largest )
{
if ( is_largest )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_INTMAX_T ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_INTMAX_T ;
2001-03-27 16:47:33 +04:00
}
# endif
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_get_ptrdiff / trio_set_ptrdiff [ public ]
2001-03-27 16:47:33 +04:00
*/
int
2001-04-21 20:57:29 +04:00
trio_get_ptrdiff ( void * ref )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_PTRDIFF_T ) ;
}
void
trio_set_ptrdiff ( void * ref ,
int is_ptrdiff )
{
if ( is_ptrdiff )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_PTRDIFF_T ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_PTRDIFF_T ;
2001-03-27 16:47:33 +04:00
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_get_size / trio_set_size [ public ]
2001-03-27 16:47:33 +04:00
*/
2001-06-05 16:46:33 +04:00
# if TRIO_C99
2001-03-27 16:47:33 +04:00
int
2001-04-21 20:57:29 +04:00
trio_get_size ( void * ref )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
return ( ( ( reference_T * ) ref ) - > parameter - > flags & FLAGS_SIZE_T ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
void
trio_set_size ( void * ref ,
int is_size )
{
if ( is_size )
( ( reference_T * ) ref ) - > parameter - > flags | = FLAGS_SIZE_T ;
else
( ( reference_T * ) ref ) - > parameter - > flags & = ~ FLAGS_SIZE_T ;
2001-03-27 16:47:33 +04:00
}
# endif
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_print_int [ public ]
2001-03-27 16:47:33 +04:00
*/
2001-04-21 20:57:29 +04:00
void
trio_print_int ( void * ref ,
int number )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
reference_T * self = ( reference_T * ) ref ;
TrioWriteNumber ( self - > data ,
2001-06-05 16:46:33 +04:00
( trio_intmax_t ) number ,
2001-04-21 20:57:29 +04:00
self - > parameter - > flags ,
self - > parameter - > width ,
self - > parameter - > precision ,
self - > parameter - > base ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
/*************************************************************************
* trio_print_uint [ public ]
*/
void
trio_print_uint ( void * ref ,
unsigned int number )
{
reference_T * self = ( reference_T * ) ref ;
TrioWriteNumber ( self - > data ,
2001-06-05 16:46:33 +04:00
( trio_intmax_t ) number ,
2001-04-21 20:57:29 +04:00
self - > parameter - > flags | FLAGS_UNSIGNED ,
self - > parameter - > width ,
self - > parameter - > precision ,
self - > parameter - > base ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
/*************************************************************************
* trio_print_double [ public ]
*/
void
trio_print_double ( void * ref ,
double number )
{
reference_T * self = ( reference_T * ) ref ;
TrioWriteDouble ( self - > data ,
number ,
self - > parameter - > flags ,
self - > parameter - > width ,
self - > parameter - > precision ,
self - > parameter - > base ) ;
}
/*************************************************************************
* trio_print_string [ public ]
*/
void
trio_print_string ( void * ref ,
char * string )
{
reference_T * self = ( reference_T * ) ref ;
TrioWriteString ( self - > data ,
string ,
self - > parameter - > flags ,
self - > parameter - > width ,
self - > parameter - > precision ) ;
}
/*************************************************************************
* trio_print_pointer [ public ]
*/
void
trio_print_pointer ( void * ref ,
void * pointer )
{
reference_T * self = ( reference_T * ) ref ;
unsigned long flags ;
2001-06-05 16:46:33 +04:00
trio_uintmax_t number ;
2001-04-21 20:57:29 +04:00
if ( NULL = = pointer )
{
const char * string = null ;
while ( * string )
self - > data - > OutStream ( self - > data , * string + + ) ;
}
else
{
/*
* The subtraction of the null pointer is a workaround
* to avoid a compiler warning . The performance overhead
* is negligible ( and likely to be removed by an
* optimising compiler ) . The ( char * ) casting is done
* to please ANSI C + + .
*/
2001-06-05 16:46:33 +04:00
number = ( trio_uintmax_t ) ( ( char * ) pointer - ( char * ) 0 ) ;
2001-04-21 20:57:29 +04:00
/* Shrink to size of pointer */
2001-06-05 16:46:33 +04:00
number & = ( trio_uintmax_t ) - 1 ;
2001-04-21 20:57:29 +04:00
flags = self - > parameter - > flags ;
flags | = ( FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
FLAGS_NILPADDING ) ;
TrioWriteNumber ( self - > data ,
2001-06-05 16:46:33 +04:00
( trio_intmax_t ) number ,
2001-04-21 20:57:29 +04:00
flags ,
POINTER_WIDTH ,
NO_PRECISION ,
BASE_HEX ) ;
}
2001-03-27 16:47:33 +04:00
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_print_ref [ public ]
2001-03-27 16:47:33 +04:00
*/
int
2001-04-21 20:57:29 +04:00
trio_print_ref ( void * ref ,
const char * format ,
. . . )
2001-03-27 16:47:33 +04:00
{
int status ;
2001-04-21 20:57:29 +04:00
va_list arglist ;
2001-03-27 16:47:33 +04:00
assert ( VALID ( format ) ) ;
2001-04-21 20:57:29 +04:00
va_start ( arglist , format ) ;
status = TrioFormatRef ( ( reference_T * ) ref , format , arglist , NULL ) ;
va_end ( arglist ) ;
2001-03-27 16:47:33 +04:00
return status ;
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* trio_vprint_ref [ public ]
2001-03-27 16:47:33 +04:00
*/
int
2001-04-21 20:57:29 +04:00
trio_vprint_ref ( void * ref ,
const char * format ,
va_list arglist )
2001-03-27 16:47:33 +04:00
{
assert ( VALID ( format ) ) ;
2001-04-21 20:57:29 +04:00
return TrioFormatRef ( ( reference_T * ) ref , format , arglist , NULL ) ;
}
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
/*************************************************************************
* trio_printv_ref [ public ]
*/
int
trio_printv_ref ( void * ref ,
const char * format ,
void * * argarray )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioFormatRef ( ( reference_T * ) ref , format , dummy , argarray ) ;
2001-03-27 16:47:33 +04:00
}
2001-04-21 20:57:29 +04:00
2001-03-27 16:47:33 +04:00
/*************************************************************************
*
2001-04-21 20:57:29 +04:00
* @ SCANNING
2001-03-27 16:47:33 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*************************************************************************
* TrioSkipWhitespaces [ private ]
*/
static int
TrioSkipWhitespaces ( trio_T * self )
{
int ch ;
ch = self - > current ;
while ( isspace ( ch ) )
{
self - > InStream ( self , & ch ) ;
}
return ch ;
}
2001-06-05 16:46:33 +04:00
/*************************************************************************
* TrioGetCollation [ private ]
*/
# if TRIO_EXTENSION
static void
TrioGetCollation ( )
{
int i ;
int j ;
int k ;
char first [ 2 ] ;
char second [ 2 ] ;
/* This is computational expensive */
first [ 1 ] = NIL ;
second [ 1 ] = NIL ;
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
{
k = 0 ;
first [ 0 ] = ( char ) i ;
for ( j = 0 ; j < MAX_CHARACTER_CLASS ; j + + )
{
second [ 0 ] = ( char ) j ;
if ( StrEqualLocale ( first , second ) )
internalCollationArray [ i ] [ k + + ] = ( char ) j ;
}
internalCollationArray [ i ] [ k ] = NIL ;
}
}
# endif
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioGetCharacterClass [ private ]
*
* FIXME :
* multibyte
*/
static int
TrioGetCharacterClass ( const char * format ,
int * indexPointer ,
2001-06-05 16:46:33 +04:00
unsigned long * flagsPointer ,
2001-03-27 16:47:33 +04:00
int * characterclass )
{
int index = * indexPointer ;
int i ;
char ch ;
char range_begin ;
char range_end ;
* flagsPointer & = ~ FLAGS_EXCLUDE ;
if ( format [ index ] = = QUALIFIER_CIRCUMFLEX )
{
* flagsPointer | = FLAGS_EXCLUDE ;
index + + ;
}
2001-04-21 20:57:29 +04:00
/*
* If the ungroup character is at the beginning of the scanlist ,
2001-03-27 16:47:33 +04:00
* it will be part of the class , and a second ungroup character
* must follow to end the group .
*/
if ( format [ index ] = = SPECIFIER_UNGROUP )
{
characterclass [ ( int ) SPECIFIER_UNGROUP ] + + ;
index + + ;
}
2001-04-21 20:57:29 +04:00
/*
* Minus is used to specify ranges . To include minus in the class ,
2001-03-27 16:47:33 +04:00
* it must be at the beginning of the list
*/
if ( format [ index ] = = QUALIFIER_MINUS )
{
characterclass [ ( int ) QUALIFIER_MINUS ] + + ;
index + + ;
}
/* Collect characters */
for ( ch = format [ index ] ;
2001-06-05 16:46:33 +04:00
( ch ! = SPECIFIER_UNGROUP ) & & ( ch ! = NIL ) ;
2001-03-27 16:47:33 +04:00
ch = format [ + + index ] )
{
switch ( ch )
{
case QUALIFIER_MINUS : /* Scanlist ranges */
2001-04-21 20:57:29 +04:00
/*
* Both C99 and UNIX98 describes ranges as implementation -
2001-03-27 16:47:33 +04:00
* defined .
*
* We support the following behaviour ( although this may
* change as we become wiser )
* - only increasing ranges , ie . [ a - b ] but not [ b - a ]
* - transitive ranges , ie . [ a - b - c ] = = [ a - c ]
* - trailing minus , ie . [ a - ] is interpreted as an ' a '
* and a ' - '
* - duplicates ( although we can easily convert these
* into errors )
*/
range_begin = format [ index - 1 ] ;
range_end = format [ + + index ] ;
if ( range_end = = SPECIFIER_UNGROUP )
{
/* Trailing minus is included */
characterclass [ ( int ) ch ] + + ;
ch = range_end ;
break ; /* for */
}
if ( range_end = = NIL )
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
if ( range_begin > range_end )
return TRIO_ERROR_RETURN ( TRIO_ERANGE , index ) ;
for ( i = ( int ) range_begin ; i < = ( int ) range_end ; i + + )
characterclass [ i ] + + ;
ch = range_end ;
break ;
2001-06-05 16:46:33 +04:00
# if TRIO_EXTENSION
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
case SPECIFIER_GROUP :
2001-03-27 16:47:33 +04:00
2001-06-05 16:46:33 +04:00
switch ( format [ index + 1 ] )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
case QUALIFIER_DOT : /* Collating symbol */
/*
* FIXME : This will be easier to implement when multibyte
* characters have been implemented . Until now , we ignore
* this feature .
*/
for ( i = index + 2 ; ; i + + )
{
if ( format [ i ] = = NIL )
/* Error in syntax */
return - 1 ;
else if ( format [ i ] = = QUALIFIER_DOT )
break ; /* for */
}
if ( format [ + + i ] ! = SPECIFIER_UNGROUP )
return - 1 ;
index = i ;
break ;
case QUALIFIER_EQUAL : /* Equivalence class expressions */
{
unsigned int j ;
unsigned int k ;
if ( internalCollationUnconverted )
{
/* Lazy evalutation of collation array */
TrioGetCollation ( ) ;
internalCollationUnconverted = FALSE ;
}
for ( i = index + 2 ; ; i + + )
{
if ( format [ i ] = = NIL )
/* Error in syntax */
return - 1 ;
else if ( format [ i ] = = QUALIFIER_EQUAL )
break ; /* for */
else
{
/* Mark any equivalent character */
k = ( unsigned int ) format [ i ] ;
for ( j = 0 ; internalCollationArray [ k ] [ j ] ! = NIL ; j + + )
characterclass [ ( int ) internalCollationArray [ k ] [ j ] ] + + ;
}
}
if ( format [ + + i ] ! = SPECIFIER_UNGROUP )
return - 1 ;
index = i ;
}
break ;
case QUALIFIER_COLON : /* Character class expressions */
if ( StrEqualMax ( CLASS_ALNUM , sizeof ( CLASS_ALNUM ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isalnum ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_ALNUM ) - 1 ;
}
else if ( StrEqualMax ( CLASS_ALPHA , sizeof ( CLASS_ALPHA ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isalpha ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_ALPHA ) - 1 ;
}
else if ( StrEqualMax ( CLASS_CNTRL , sizeof ( CLASS_CNTRL ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( iscntrl ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_CNTRL ) - 1 ;
}
else if ( StrEqualMax ( CLASS_DIGIT , sizeof ( CLASS_DIGIT ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isdigit ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_DIGIT ) - 1 ;
}
else if ( StrEqualMax ( CLASS_GRAPH , sizeof ( CLASS_GRAPH ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isgraph ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_GRAPH ) - 1 ;
}
else if ( StrEqualMax ( CLASS_LOWER , sizeof ( CLASS_LOWER ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( islower ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_LOWER ) - 1 ;
}
else if ( StrEqualMax ( CLASS_PRINT , sizeof ( CLASS_PRINT ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isprint ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_PRINT ) - 1 ;
}
else if ( StrEqualMax ( CLASS_PUNCT , sizeof ( CLASS_PUNCT ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( ispunct ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_PUNCT ) - 1 ;
}
else if ( StrEqualMax ( CLASS_SPACE , sizeof ( CLASS_SPACE ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isspace ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_SPACE ) - 1 ;
}
else if ( StrEqualMax ( CLASS_UPPER , sizeof ( CLASS_UPPER ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isupper ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_UPPER ) - 1 ;
}
else if ( StrEqualMax ( CLASS_XDIGIT , sizeof ( CLASS_XDIGIT ) - 1 ,
& format [ index ] ) )
{
for ( i = 0 ; i < MAX_CHARACTER_CLASS ; i + + )
if ( isxdigit ( i ) )
characterclass [ i ] + + ;
index + = sizeof ( CLASS_XDIGIT ) - 1 ;
}
else
{
characterclass [ ( int ) ch ] + + ;
}
break ;
default :
2001-03-27 16:47:33 +04:00
characterclass [ ( int ) ch ] + + ;
2001-06-05 16:46:33 +04:00
break ;
2001-03-27 16:47:33 +04:00
}
break ;
2001-06-05 16:46:33 +04:00
# endif /* TRIO_EXTENSION */
2001-03-27 16:47:33 +04:00
default :
characterclass [ ( int ) ch ] + + ;
break ;
}
}
return 0 ;
}
/*************************************************************************
* TrioReadNumber [ private ]
*
* We implement our own number conversion in preference of strtol and
* strtoul , because we must handle ' long long ' and thousand separators .
*/
static BOOLEAN_T
2001-04-21 20:57:29 +04:00
TrioReadNumber ( trio_T * self ,
2001-06-05 16:46:33 +04:00
trio_uintmax_t * target ,
unsigned long flags ,
2001-04-21 20:57:29 +04:00
int width ,
int base )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
trio_uintmax_t number = 0 ;
2001-03-27 16:47:33 +04:00
int digit ;
int count ;
BOOLEAN_T isNegative = FALSE ;
int j ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
assert ( ( base > = MIN_BASE & & base < = MAX_BASE ) | | ( base = = NO_BASE ) ) ;
2001-06-05 16:46:33 +04:00
if ( internalDigitsUnconverted )
{
/* Lazy evaluation of digits array */
memset ( internalDigitArray , - 1 , sizeof ( internalDigitArray ) ) ;
for ( j = 0 ; j < ( int ) sizeof ( internalDigitsLower ) - 1 ; j + + )
{
internalDigitArray [ ( int ) internalDigitsLower [ j ] ] = j ;
internalDigitArray [ ( int ) internalDigitsUpper [ j ] ] = j ;
}
internalDigitsUnconverted = FALSE ;
}
2001-03-27 16:47:33 +04:00
TrioSkipWhitespaces ( self ) ;
if ( ! ( flags & FLAGS_UNSIGNED ) )
{
/* Leading sign */
if ( self - > current = = ' + ' )
{
self - > InStream ( self , NULL ) ;
}
else if ( self - > current = = ' - ' )
{
self - > InStream ( self , NULL ) ;
isNegative = TRUE ;
}
}
count = self - > processed ;
if ( flags & FLAGS_ALTERNATIVE )
{
switch ( base )
{
case NO_BASE :
case BASE_OCTAL :
case BASE_HEX :
case BASE_BINARY :
if ( self - > current = = ' 0 ' )
{
self - > InStream ( self , NULL ) ;
if ( self - > current )
{
if ( ( base = = BASE_HEX ) & &
( toupper ( self - > current ) = = ' X ' ) )
{
self - > InStream ( self , NULL ) ;
}
else if ( ( base = = BASE_BINARY ) & &
( toupper ( self - > current ) = = ' B ' ) )
{
self - > InStream ( self , NULL ) ;
}
}
}
else
return FALSE ;
break ;
default :
break ;
}
}
while ( ( ( width = = NO_WIDTH ) | | ( self - > processed - count < width ) ) & &
( ! ( ( self - > current = = EOF ) | | isspace ( self - > current ) ) ) )
{
if ( isascii ( self - > current ) )
{
2001-04-21 20:57:29 +04:00
digit = internalDigitArray [ self - > current ] ;
2001-03-27 16:47:33 +04:00
/* Abort if digit is not allowed in the specified base */
if ( ( digit = = - 1 ) | | ( digit > = base ) )
break ;
}
else if ( flags & FLAGS_QUOTE )
{
/* Compare with thousands separator */
2001-04-21 20:57:29 +04:00
for ( j = 0 ; internalThousandSeparator [ j ] & & self - > current ; j + + )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
if ( internalThousandSeparator [ j ] ! = self - > current )
2001-03-27 16:47:33 +04:00
break ;
self - > InStream ( self , NULL ) ;
}
2001-04-21 20:57:29 +04:00
if ( internalThousandSeparator [ j ] )
2001-03-27 16:47:33 +04:00
break ; /* Mismatch */
else
continue ; /* Match */
}
else
break ;
number * = base ;
number + = digit ;
self - > InStream ( self , NULL ) ;
}
/* Was anything read at all? */
if ( self - > processed = = count )
return FALSE ;
if ( target )
* target = ( isNegative ) ? - number : number ;
return TRUE ;
}
/*************************************************************************
* TrioReadChar [ private ]
*/
2001-06-05 16:46:33 +04:00
static int
2001-04-21 20:57:29 +04:00
TrioReadChar ( trio_T * self ,
char * target ,
2001-06-05 16:46:33 +04:00
unsigned long flags ,
2001-04-21 20:57:29 +04:00
int width )
2001-03-27 16:47:33 +04:00
{
int i ;
2001-06-05 16:46:33 +04:00
char ch ;
trio_uintmax_t number ;
2001-03-27 16:47:33 +04:00
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
for ( i = 0 ;
( self - > current ! = EOF ) & & ( i < width ) ;
i + + )
{
2001-06-05 16:46:33 +04:00
ch = ( char ) self - > current ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , NULL ) ;
if ( ( flags & FLAGS_ALTERNATIVE ) & & ( ch = = CHAR_BACKSLASH ) )
{
switch ( self - > current )
{
2001-04-21 20:57:29 +04:00
case ' \\ ' : ch = ' \\ ' ; break ;
2001-06-05 16:46:33 +04:00
case ' a ' : ch = ' \007 ' ; break ;
2001-04-21 20:57:29 +04:00
case ' b ' : ch = ' \b ' ; break ;
case ' f ' : ch = ' \f ' ; break ;
case ' n ' : ch = ' \n ' ; break ;
case ' r ' : ch = ' \r ' ; break ;
case ' t ' : ch = ' \t ' ; break ;
case ' v ' : ch = ' \v ' ; break ;
2001-03-27 16:47:33 +04:00
default :
if ( isdigit ( self - > current ) )
{
/* Read octal number */
if ( ! TrioReadNumber ( self , & number , 0 , 3 , BASE_OCTAL ) )
2001-06-05 16:46:33 +04:00
return 0 ;
2001-03-27 16:47:33 +04:00
ch = ( char ) number ;
}
else if ( toupper ( self - > current ) = = ' X ' )
{
/* Read hexadecimal number */
self - > InStream ( self , NULL ) ;
if ( ! TrioReadNumber ( self , & number , 0 , 2 , BASE_HEX ) )
2001-06-05 16:46:33 +04:00
return 0 ;
2001-03-27 16:47:33 +04:00
ch = ( char ) number ;
}
else
{
2001-06-05 16:46:33 +04:00
ch = ( char ) self - > current ;
2001-03-27 16:47:33 +04:00
}
break ;
}
}
2001-06-05 16:46:33 +04:00
2001-03-27 16:47:33 +04:00
if ( target )
target [ i ] = ch ;
2001-06-05 16:46:33 +04:00
}
return i + 1 ;
}
/*************************************************************************
* TrioReadString [ private ]
*/
static BOOLEAN_T
TrioReadString ( trio_T * self ,
char * target ,
unsigned long flags ,
int width )
{
int i ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
TrioSkipWhitespaces ( self ) ;
/*
* Continue until end of string is reached , a whitespace is encountered ,
* or width is exceeded
*/
for ( i = 0 ;
( ( width = = NO_WIDTH ) | | ( i < width ) ) & &
( ! ( ( self - > current = = EOF ) | | isspace ( self - > current ) ) ) ;
i + + )
{
if ( TrioReadChar ( self , & target [ i ] , flags , 1 ) = = 0 )
break ; /* for */
2001-03-27 16:47:33 +04:00
}
if ( target )
target [ i ] = NIL ;
return TRUE ;
}
2001-06-05 16:46:33 +04:00
/*************************************************************************
* TrioReadWideChar [ private ]
*/
# if TRIO_WIDECHAR
static int
TrioReadWideChar ( trio_T * self ,
wchar_t * target ,
unsigned long flags ,
int width )
{
int i ;
int j ;
int size ;
int amount = 0 ;
wchar_t wch ;
char buffer [ MB_LEN_MAX + 1 ] ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
for ( i = 0 ;
( self - > current ! = EOF ) & & ( i < width ) ;
i + + )
{
if ( isascii ( self - > current ) )
{
if ( TrioReadChar ( self , buffer , flags , 1 ) = = 0 )
return 0 ;
buffer [ 1 ] = NIL ;
}
else
{
/*
* Collect a multibyte character , by enlarging buffer until
* it contains a fully legal multibyte character , or the
* buffer is full .
*/
j = 0 ;
do
{
buffer [ j + + ] = ( char ) self - > current ;
buffer [ j ] = NIL ;
self - > InStream ( self , NULL ) ;
}
while ( ( j < ( int ) sizeof ( buffer ) ) & & ( mblen ( buffer , ( size_t ) j ) ! = j ) ) ;
}
if ( target )
{
size = mbtowc ( & wch , buffer , sizeof ( buffer ) ) ;
if ( size > 0 )
target [ i ] = wch ;
}
amount + = size ;
self - > InStream ( self , NULL ) ;
}
return amount ;
}
# endif /* TRIO_WIDECHAR */
/*************************************************************************
* TrioReadWideString [ private ]
*/
# if TRIO_WIDECHAR
static BOOLEAN_T
TrioReadWideString ( trio_T * self ,
wchar_t * target ,
unsigned long flags ,
int width )
{
int i ;
int size ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
TrioSkipWhitespaces ( self ) ;
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
mblen ( NULL , 0 ) ;
# endif
/*
* Continue until end of string is reached , a whitespace is encountered ,
* or width is exceeded
*/
for ( i = 0 ;
( ( width = = NO_WIDTH ) | | ( i < width ) ) & &
( ! ( ( self - > current = = EOF ) | | isspace ( self - > current ) ) ) ;
)
{
size = TrioReadWideChar ( self , & target [ i ] , flags , 1 ) ;
if ( size = = 0 )
break ; /* for */
i + = size ;
}
if ( target )
target [ i ] = L ' \0 ' ;
return TRUE ;
}
# endif /* TRIO_WIDECHAR */
2001-03-27 16:47:33 +04:00
/*************************************************************************
* TrioReadGroup [ private ]
*
* FIXME : characterclass does not work with multibyte characters
*/
static BOOLEAN_T
TrioReadGroup ( trio_T * self ,
char * target ,
int * characterclass ,
2001-06-05 16:46:33 +04:00
unsigned long flags ,
2001-03-27 16:47:33 +04:00
int width )
{
2001-04-21 20:57:29 +04:00
int ch ;
2001-03-27 16:47:33 +04:00
int i ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
ch = self - > current ;
for ( i = 0 ;
( ( width = = NO_WIDTH ) | | ( i < width ) ) & &
( ! ( ( ch = = EOF ) | |
( ( ( flags & FLAGS_EXCLUDE ) ! = 0 ) ^ ( characterclass [ ch ] = = 0 ) ) ) ) ;
i + + )
{
if ( target )
target [ i ] = ( char ) ch ;
self - > InStream ( self , & ch ) ;
}
if ( target )
target [ i ] = NIL ;
return TRUE ;
}
/*************************************************************************
* TrioReadDouble [ private ]
*
* FIXME :
* add long double
*/
static BOOLEAN_T
TrioReadDouble ( trio_T * self ,
double * target ,
2001-06-05 16:46:33 +04:00
unsigned long flags ,
2001-03-27 16:47:33 +04:00
int width )
{
int ch ;
char doubleString [ 512 ] = " " ;
int index = 0 ;
int start ;
2001-04-21 20:57:29 +04:00
int j ;
2001-06-05 16:46:33 +04:00
BOOLEAN_T isHex = FALSE ;
2001-03-27 16:47:33 +04:00
2001-04-21 20:57:29 +04:00
if ( ( width = = NO_WIDTH ) | | ( width > ( int ) sizeof ( doubleString ) - 1 ) )
2001-03-27 16:47:33 +04:00
width = sizeof ( doubleString ) - 1 ;
TrioSkipWhitespaces ( self ) ;
2001-04-21 20:57:29 +04:00
/*
* Read entire double number from stream . StrToDouble requires a
2001-03-27 16:47:33 +04:00
* string as input , but InStream can be anything , so we have to
* collect all characters .
*/
ch = self - > current ;
if ( ( ch = = ' + ' ) | | ( ch = = ' - ' ) )
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
width - - ;
}
start = index ;
switch ( ch )
{
case ' n ' :
case ' N ' :
/* Not-a-number */
if ( index ! = 0 )
break ;
/* FALLTHROUGH */
case ' i ' :
case ' I ' :
/* Infinity */
while ( isalpha ( ch ) & & ( index - start < width ) )
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
}
doubleString [ index ] = NIL ;
/* Case insensitive string comparison */
if ( StrEqual ( & doubleString [ start ] , INFINITE_UPPER ) | |
StrEqual ( & doubleString [ start ] , LONG_INFINITE_UPPER ) )
{
* target = ( ( start = = 1 & & doubleString [ 0 ] = = ' - ' ) )
? - HUGE_VAL
: HUGE_VAL ;
return TRUE ;
}
if ( StrEqual ( doubleString , NAN_LOWER ) )
{
/* NaN must not have a preceeding + nor - */
2001-06-05 16:46:33 +04:00
* target = TrioGenerateNaN ( ) ;
2001-03-27 16:47:33 +04:00
return TRUE ;
}
return FALSE ;
default :
break ;
}
2001-06-05 16:46:33 +04:00
if ( ch = = ' 0 ' )
{
doubleString [ index + + ] = ( char ) ch ;
self - > InStream ( self , & ch ) ;
if ( toupper ( ch ) = = ' X ' )
{
isHex = TRUE ;
doubleString [ index + + ] = ( char ) ch ;
self - > InStream ( self , & ch ) ;
}
}
2001-04-21 20:57:29 +04:00
while ( ( ch ! = EOF ) & & ( index - start < width ) )
2001-03-27 16:47:33 +04:00
{
/* Integer part */
2001-06-05 16:46:33 +04:00
if ( isHex ? isxdigit ( ch ) : isdigit ( ch ) )
2001-04-21 20:57:29 +04:00
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-04-21 20:57:29 +04:00
self - > InStream ( self , & ch ) ;
}
else if ( flags & FLAGS_QUOTE )
{
/* Compare with thousands separator */
for ( j = 0 ; internalThousandSeparator [ j ] & & self - > current ; j + + )
{
if ( internalThousandSeparator [ j ] ! = self - > current )
break ;
self - > InStream ( self , & ch ) ;
}
if ( internalThousandSeparator [ j ] )
break ; /* Mismatch */
else
continue ; /* Match */
}
else
break ; /* while */
2001-03-27 16:47:33 +04:00
}
if ( ch = = ' . ' )
{
/* Decimal part */
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
2001-06-05 16:46:33 +04:00
while ( ( isHex ? isxdigit ( ch ) : isdigit ( ch ) ) & &
( index - start < width ) )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
}
2001-06-05 16:46:33 +04:00
if ( isHex ? ( toupper ( ch ) = = ' P ' ) : ( toupper ( ch ) = = ' E ' ) )
2001-03-27 16:47:33 +04:00
{
/* Exponent */
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
if ( ( ch = = ' + ' ) | | ( ch = = ' - ' ) )
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
}
2001-06-05 16:46:33 +04:00
while ( ( isHex ? isxdigit ( ch ) : isdigit ( ch ) ) & &
( index - start < width ) )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
doubleString [ index + + ] = ( char ) ch ;
2001-03-27 16:47:33 +04:00
self - > InStream ( self , & ch ) ;
}
}
}
if ( ( index = = start ) | | ( * doubleString = = NIL ) )
return FALSE ;
if ( flags & FLAGS_LONGDOUBLE )
2001-06-05 16:46:33 +04:00
/* *longdoublePointer = StrToLongDouble()*/
return FALSE ; /* FIXME: Remove when long double is implemented */
2001-03-27 16:47:33 +04:00
else
{
* target = StrToDouble ( doubleString , NULL ) ;
}
return TRUE ;
}
/*************************************************************************
* TrioReadPointer [ private ]
*/
static BOOLEAN_T
2001-04-21 20:57:29 +04:00
TrioReadPointer ( trio_T * self ,
void * * target ,
2001-06-05 16:46:33 +04:00
unsigned long flags )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
trio_uintmax_t number ;
2001-03-27 16:47:33 +04:00
char buffer [ sizeof ( null ) ] ;
flags | = ( FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING ) ;
if ( TrioReadNumber ( self ,
& number ,
flags ,
POINTER_WIDTH ,
BASE_HEX ) )
{
2001-04-21 20:57:29 +04:00
/*
* The strange assignment of number is a workaround for a compiler
* warning
*/
2001-03-27 16:47:33 +04:00
if ( target )
2001-04-21 20:57:29 +04:00
* target = ( char * ) 0 + number ;
2001-03-27 16:47:33 +04:00
return TRUE ;
}
else if ( TrioReadString ( self ,
( flags & FLAGS_IGNORE )
? NULL
: buffer ,
0 ,
sizeof ( null ) - 1 ) )
{
if ( StrEqualCase ( buffer , null ) )
{
if ( target )
* target = NULL ;
return TRUE ;
}
}
return FALSE ;
}
/*************************************************************************
* TrioScan [ private ]
*/
static int
2001-04-21 20:57:29 +04:00
TrioScan ( const void * source ,
2001-03-27 16:47:33 +04:00
size_t sourceSize ,
void ( * InStream ) ( trio_T * , int * ) ,
const char * format ,
2001-04-21 20:57:29 +04:00
va_list arglist ,
void * * argarray )
2001-03-27 16:47:33 +04:00
{
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
int charlen ;
# endif
int status ;
int assignment ;
parameter_T parameters [ MAX_PARAMETERS ] ;
trio_T internalData ;
trio_T * data ;
int ch ;
int cnt ;
int index ; /* Index of format string */
int i ; /* Index of current parameter */
2001-06-05 16:46:33 +04:00
unsigned long flags ;
2001-03-27 16:47:33 +04:00
int width ;
int base ;
void * pointer ;
assert ( VALID ( InStream ) ) ;
assert ( VALID ( format ) ) ;
memset ( & internalData , 0 , sizeof ( internalData ) ) ;
data = & internalData ;
data - > InStream = InStream ;
2001-06-05 16:46:33 +04:00
data - > location = ( void * ) source ;
2001-03-27 16:47:33 +04:00
data - > max = sourceSize ;
# if defined(USE_LOCALE)
2001-04-21 20:57:29 +04:00
if ( NULL = = internalLocaleValues )
2001-03-27 16:47:33 +04:00
{
TrioSetLocale ( ) ;
}
# endif
2001-04-21 20:57:29 +04:00
status = TrioPreprocess ( TYPE_SCAN , format , parameters , arglist , argarray ) ;
2001-03-27 16:47:33 +04:00
if ( status < 0 )
return status ;
assignment = 0 ;
i = 0 ;
index = 0 ;
data - > InStream ( data , & ch ) ;
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
mblen ( NULL , 0 ) ;
# endif
while ( format [ index ] )
{
2001-06-05 16:46:33 +04:00
# if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2001-03-27 16:47:33 +04:00
if ( ! isascii ( format [ index ] ) )
{
charlen = mblen ( & format [ index ] , MB_LEN_MAX ) ;
/* Compare multibyte characters in format string */
for ( cnt = 0 ; cnt < charlen - 1 ; cnt + + )
{
if ( ch ! = format [ index + cnt ] )
{
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
data - > InStream ( data , & ch ) ;
}
continue ; /* while */
}
2001-06-05 16:46:33 +04:00
# endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
2001-03-27 16:47:33 +04:00
if ( EOF = = ch )
return EOF ;
if ( CHAR_IDENTIFIER = = format [ index ] )
{
if ( CHAR_IDENTIFIER = = format [ index + 1 ] )
{
/* Two % in format matches one % in input stream */
if ( CHAR_IDENTIFIER = = ch )
{
data - > InStream ( data , & ch ) ;
index + = 2 ;
continue ; /* while format chars left */
}
else
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
/* Skip the parameter entries */
while ( parameters [ i ] . type = = FORMAT_PARAMETER )
i + + ;
flags = parameters [ i ] . flags ;
/* Find width */
width = parameters [ i ] . width ;
if ( flags & FLAGS_WIDTH_PARAMETER )
{
/* Get width from parameter list */
2001-04-21 20:57:29 +04:00
width = ( int ) parameters [ width ] . data . number . as_signed ;
2001-03-27 16:47:33 +04:00
}
/* Find base */
base = parameters [ i ] . base ;
if ( flags & FLAGS_BASE_PARAMETER )
{
/* Get base from parameter list */
2001-04-21 20:57:29 +04:00
base = ( int ) parameters [ base ] . data . number . as_signed ;
2001-03-27 16:47:33 +04:00
}
switch ( parameters [ i ] . type )
{
case FORMAT_INT :
{
2001-06-05 16:46:33 +04:00
trio_uintmax_t number ;
2001-03-27 16:47:33 +04:00
if ( 0 = = base )
base = BASE_DECIMAL ;
if ( ! TrioReadNumber ( data ,
& number ,
flags ,
width ,
base ) )
return assignment ;
assignment + + ;
if ( ! ( flags & FLAGS_IGNORE ) )
{
pointer = parameters [ i ] . data . pointer ;
# if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
if ( flags & FLAGS_SIZE_T )
* ( size_t * ) pointer = ( size_t ) number ;
else
# endif
# if defined(QUALIFIER_PTRDIFF_T)
if ( flags & FLAGS_PTRDIFF_T )
* ( ptrdiff_t * ) pointer = ( ptrdiff_t ) number ;
else
# endif
# if defined(QUALIFIER_INTMAX_T)
if ( flags & FLAGS_INTMAX_T )
2001-06-05 16:46:33 +04:00
* ( trio_intmax_t * ) pointer = ( trio_intmax_t ) number ;
2001-03-27 16:47:33 +04:00
else
# endif
if ( flags & FLAGS_QUAD )
2001-06-05 16:46:33 +04:00
* ( trio_ulonglong_t * ) pointer = ( trio_ulonglong_t ) number ;
2001-03-27 16:47:33 +04:00
else if ( flags & FLAGS_LONG )
* ( long int * ) pointer = ( long int ) number ;
else if ( flags & FLAGS_SHORT )
* ( short int * ) pointer = ( short int ) number ;
else
* ( int * ) pointer = ( int ) number ;
}
}
break ; /* FORMAT_INT */
case FORMAT_STRING :
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
if ( flags & FLAGS_WIDECHAR )
{
if ( ! TrioReadWideString ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . wstring ,
flags ,
width ) )
return assignment ;
}
else
# endif
{
if ( ! TrioReadString ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . string ,
flags ,
width ) )
return assignment ;
}
2001-03-27 16:47:33 +04:00
assignment + + ;
break ; /* FORMAT_STRING */
case FORMAT_DOUBLE :
if ( ! TrioReadDouble ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . doublePointer ,
flags ,
width ) )
return assignment ;
assignment + + ;
break ; /* FORMAT_DOUBLE */
case FORMAT_GROUP :
{
int characterclass [ MAX_CHARACTER_CLASS + 1 ] ;
int rc ;
2001-06-05 16:46:33 +04:00
/* Skip over modifiers */
while ( format [ index ] ! = SPECIFIER_GROUP )
{
index + + ;
}
/* Skip over group specifier */
index + + ;
2001-03-27 16:47:33 +04:00
memset ( characterclass , 0 , sizeof ( characterclass ) ) ;
2001-06-05 16:46:33 +04:00
rc = TrioGetCharacterClass ( format ,
& index ,
& flags ,
2001-03-27 16:47:33 +04:00
characterclass ) ;
if ( rc < 0 )
return rc ;
if ( ! TrioReadGroup ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . string ,
characterclass ,
flags ,
parameters [ i ] . width ) )
return assignment ;
assignment + + ;
}
break ; /* FORMAT_GROUP */
case FORMAT_COUNT :
pointer = parameters [ i ] . data . pointer ;
if ( NULL ! = pointer )
{
# if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
if ( flags & FLAGS_SIZE_T )
* ( size_t * ) pointer = ( size_t ) data - > committed ;
else
# endif
# if defined(QUALIFIER_PTRDIFF_T)
if ( flags & FLAGS_PTRDIFF_T )
* ( ptrdiff_t * ) pointer = ( ptrdiff_t ) data - > committed ;
else
# endif
# if defined(QUALIFIER_INTMAX_T)
if ( flags & FLAGS_INTMAX_T )
2001-06-05 16:46:33 +04:00
* ( trio_intmax_t * ) pointer = ( trio_intmax_t ) data - > committed ;
2001-03-27 16:47:33 +04:00
else
# endif
if ( flags & FLAGS_QUAD )
{
2001-06-05 16:46:33 +04:00
* ( trio_ulonglong_t * ) pointer = ( trio_ulonglong_t ) data - > committed ;
2001-03-27 16:47:33 +04:00
}
else if ( flags & FLAGS_LONG )
{
* ( long int * ) pointer = ( long int ) data - > committed ;
}
else if ( flags & FLAGS_SHORT )
{
* ( short int * ) pointer = ( short int ) data - > committed ;
}
else
{
* ( int * ) pointer = ( int ) data - > committed ;
}
}
break ; /* FORMAT_COUNT */
case FORMAT_CHAR :
2001-06-05 16:46:33 +04:00
# if TRIO_WIDECHAR
if ( flags & FLAGS_WIDECHAR )
{
if ( TrioReadWideChar ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . wstring ,
flags ,
( width = = NO_WIDTH ) ? 1 : width ) > 0 )
return assignment ;
}
else
# endif
{
if ( TrioReadChar ( data ,
( flags & FLAGS_IGNORE )
? NULL
: parameters [ i ] . data . string ,
flags ,
( width = = NO_WIDTH ) ? 1 : width ) > 0 )
return assignment ;
}
2001-03-27 16:47:33 +04:00
assignment + + ;
break ; /* FORMAT_CHAR */
case FORMAT_POINTER :
if ( ! TrioReadPointer ( data ,
( flags & FLAGS_IGNORE )
? NULL
2001-04-21 20:57:29 +04:00
: ( void * * ) parameters [ i ] . data . pointer ,
2001-03-27 16:47:33 +04:00
flags ) )
return assignment ;
assignment + + ;
break ; /* FORMAT_POINTER */
case FORMAT_PARAMETER :
break ; /* FORMAT_PARAMETER */
default :
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
}
ch = data - > current ;
index = parameters [ i ] . indexAfterSpecifier ;
i + + ;
}
else /* Not an % identifier */
{
if ( isspace ( ( int ) format [ index ] ) )
{
/* Whitespaces may match any amount of whitespaces */
ch = TrioSkipWhitespaces ( data ) ;
}
else if ( ch = = format [ index ] )
{
data - > InStream ( data , & ch ) ;
}
else
return TRIO_ERROR_RETURN ( TRIO_EINVAL , index ) ;
index + + ;
}
}
return assignment ;
}
/*************************************************************************
* TrioInStreamFile [ private ]
*/
static void
2001-04-21 20:57:29 +04:00
TrioInStreamFile ( trio_T * self ,
int * intPointer )
2001-03-27 16:47:33 +04:00
{
FILE * file = ( FILE * ) self - > location ;
assert ( VALID ( self ) ) ;
assert ( VALID ( file ) ) ;
self - > current = fgetc ( file ) ;
self - > processed + + ;
self - > committed + + ;
if ( VALID ( intPointer ) )
{
* intPointer = self - > current ;
}
}
/*************************************************************************
* TrioInStreamFileDescriptor [ private ]
*/
static void
2001-04-21 20:57:29 +04:00
TrioInStreamFileDescriptor ( trio_T * self ,
int * intPointer )
2001-03-27 16:47:33 +04:00
{
int fd = * ( ( int * ) self - > location ) ;
int size ;
unsigned char input ;
assert ( VALID ( self ) ) ;
size = read ( fd , & input , sizeof ( char ) ) ;
self - > current = ( size = = 0 ) ? EOF : input ;
self - > processed + + ;
self - > committed + + ;
if ( VALID ( intPointer ) )
{
* intPointer = self - > current ;
}
}
/*************************************************************************
* TrioInStreamString [ private ]
*/
static void
2001-04-21 20:57:29 +04:00
TrioInStreamString ( trio_T * self ,
int * intPointer )
2001-03-27 16:47:33 +04:00
{
unsigned char * * buffer ;
assert ( VALID ( self ) ) ;
assert ( VALID ( self - > InStream ) ) ;
assert ( VALID ( self - > location ) ) ;
buffer = ( unsigned char * * ) self - > location ;
self - > current = ( * buffer ) [ 0 ] ;
if ( self - > current = = NIL )
self - > current = EOF ;
( * buffer ) + + ;
self - > processed + + ;
self - > committed + + ;
if ( VALID ( intPointer ) )
{
* intPointer = self - > current ;
}
}
/*************************************************************************
2001-04-21 20:57:29 +04:00
* scanf
*/
int
trio_scanf ( const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioScan ( stdin , 0 , TrioInStreamFile , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vscanf ( const char * format ,
va_list args )
{
assert ( VALID ( format ) ) ;
return TrioScan ( stdin , 0 , TrioInStreamFile , format , args , NULL ) ;
}
int
trio_scanfv ( const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioScan ( stdin , 0 , TrioInStreamFile , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* fscanf
*/
int
trio_fscanf ( FILE * file ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioScan ( file , 0 , TrioInStreamFile , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vfscanf ( FILE * file ,
const char * format ,
va_list args )
{
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
return TrioScan ( file , 0 , TrioInStreamFile , format , args , NULL ) ;
}
int
trio_fscanfv ( FILE * file ,
const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( file ) ) ;
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioScan ( file , 0 , TrioInStreamFile , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* dscanf
*/
int
trio_dscanf ( int fd ,
const char * format ,
. . . )
{
int status ;
va_list args ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
status = TrioScan ( & fd , 0 , TrioInStreamFileDescriptor , format , args , NULL ) ;
va_end ( args ) ;
return status ;
}
int
trio_vdscanf ( int fd ,
const char * format ,
va_list args )
{
assert ( VALID ( format ) ) ;
return TrioScan ( & fd , 0 , TrioInStreamFileDescriptor , format , args , NULL ) ;
}
int
trio_dscanfv ( int fd ,
const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioScan ( & fd , 0 , TrioInStreamFileDescriptor , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
/*************************************************************************
* sscanf
2001-03-27 16:47:33 +04:00
*/
int
2001-04-21 20:57:29 +04:00
trio_sscanf ( const char * buffer ,
const char * format ,
. . . )
2001-03-27 16:47:33 +04:00
{
int status ;
va_list args ;
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
va_start ( args , format ) ;
2001-04-21 20:57:29 +04:00
status = TrioScan ( & buffer , 0 , TrioInStreamString , format , args , NULL ) ;
2001-03-27 16:47:33 +04:00
va_end ( args ) ;
return status ;
}
2001-04-21 20:57:29 +04:00
int
trio_vsscanf ( const char * buffer ,
const char * format ,
va_list args )
{
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
return TrioScan ( & buffer , 0 , TrioInStreamString , format , args , NULL ) ;
}
int
trio_sscanfv ( const char * buffer ,
const char * format ,
void * * args )
{
2001-06-05 16:46:33 +04:00
va_list dummy ;
2001-04-21 20:57:29 +04:00
assert ( VALID ( buffer ) ) ;
assert ( VALID ( format ) ) ;
2001-06-05 16:46:33 +04:00
return TrioScan ( & buffer , 0 , TrioInStreamString , format , dummy , args ) ;
2001-04-21 20:57:29 +04:00
}
2001-06-05 16:46:33 +04:00