/src/sdk/src/libc/src/trio/trio.c
C | 2002 lines | 1466 code | 170 blank | 366 comment | 256 complexity | 3d3a27631c7dc8e23875fefdff23f878 MD5 | raw file
- /*
- * TODO:
- * - Scan is probably too permissive about its modifiers.
- * - C escapes in %#[] ?
- * - Multibyte characters (done for format parsing, except scan groups)
- * - Complex numbers? (C99 _Complex)
- * - Boolean values? (C99 _Bool)
- * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
- * to print the mantissa, e.g. NaN(0xc000000000000000)
- * - 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'.
- * - Scanning of collating symbols.
- */
- /*************************************************************************
- * Trio include files
- */
- #include "triodef.h"
- #include "trio.h"
- #include "triop.h"
- #if defined(TRIO_EMBED_NAN)
- # define TRIO_PUBLIC_NAN static
- # if TRIO_FEATURE_FLOAT
- # define TRIO_FUNC_NAN
- # define TRIO_FUNC_NINF
- # define TRIO_FUNC_PINF
- # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT
- # define TRIO_FUNC_ISINF
- # endif
- #endif
- #include "trionan.h"
- #if defined(TRIO_EMBED_STRING)
- # define TRIO_PUBLIC_STRING static
- # define TRIO_FUNC_LENGTH
- # define TRIO_FUNC_LENGTH_MAX
- # define TRIO_FUNC_TO_LONG
- # if TRIO_FEATURE_LOCALE
- # define TRIO_FUNC_COPY_MAX
- # endif
- # if TRIO_FEATURE_DYNAMICSTRING
- # define TRIO_FUNC_XSTRING_DUPLICATE
- # endif
- # if TRIO_EXTENSION && TRIO_FEATURE_SCANF
- # define TRIO_FUNC_EQUAL_LOCALE
- # endif
- # if TRIO_FEATURE_ERRNO
- # define TRIO_FUNC_ERROR
- # endif
- # if TRIO_FEATURE_FLOAT && TRIO_FEATURE_SCANF
- # define TRIO_FUNC_TO_DOUBLE
- # endif
- # if TRIO_FEATURE_DYNAMICSTRING
- # define TRIO_FUNC_STRING_EXTRACT
- # endif
- # if TRIO_FEATURE_DYNAMICSTRING
- # define TRIO_FUNC_STRING_TERMINATE
- # endif
- # if TRIO_FEATURE_USER_DEFINED
- # define TRIO_FUNC_DUPLICATE
- # endif
- # if TRIO_FEATURE_DYNAMICSTRING
- # define TRIO_FUNC_STRING_DESTROY
- # endif
- # if TRIO_FEATURE_USER_DEFINED
- # define TRIO_FUNC_DESTROY
- # endif
- # if TRIO_FEATURE_USER_DEFINED || (TRIO_FEATURE_FLOAT && TRIO_FEATURE_SCANF)
- # define TRIO_FUNC_EQUAL
- # endif
- # if TRIO_FEATURE_USER_DEFINED || TRIO_FEATURE_SCANF
- # define TRIO_FUNC_EQUAL_CASE
- # endif
- # if (TRIO_EXTENSION && TRIO_FEATURE_SCANF)
- # define TRIO_FUNC_EQUAL_MAX
- # endif
- # if TRIO_FEATURE_SCANF
- # define TRIO_FUNC_TO_UPPER
- # endif
- # if TRIO_FEATURE_DYNAMICSTRING
- # define TRIO_FUNC_XSTRING_APPEND_CHAR
- # endif
- #endif
- #include "triostr.h"
- /**************************************************************************
- *
- * Definitions
- *
- *************************************************************************/
- #include <limits.h>
- #if TRIO_FEATURE_FLOAT
- # include <math.h>
- # include <float.h>
- #endif
- #if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_FEATURE_WIDECHAR
- # if !defined(TRIO_PLATFORM_WINCE)
- //# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
- # if !defined(MB_LEN_MAX)
- # define MB_LEN_MAX 6
- # endif
- # endif
- #endif
- #if (TRIO_COMPILER_VISUALC - 0 >= 1100) || defined(TRIO_COMPILER_BORLAND)
- # define TRIO_COMPILER_SUPPORTS_VISUALC_INT
- #endif
- #if TRIO_FEATURE_FLOAT
- # if defined(PREDEF_STANDARD_C99) \
- || defined(PREDEF_STANDARD_UNIX03)
- # if !defined(HAVE_FLOORL)
- # define HAVE_FLOORL
- # endif
- # if !defined(HAVE_CEILL)
- # define HAVE_CEILL
- # endif
- # if !defined(HAVE_POWL)
- # define HAVE_POWL
- # endif
- # if !defined(HAVE_FMODL)
- # define HAVE_FMODL
- # endif
- # if !defined(HAVE_LOG10L)
- # define HAVE_LOG10L
- # endif
- # endif
- # if defined(TRIO_COMPILER_VISUALC)
- # if defined(floorl)
- # define HAVE_FLOORL
- # endif
- # if defined(ceill)
- # define HAVE_CEILL
- # endif
- # if defined(powl)
- # define HAVE_POWL
- # endif
- # if defined(fmodl)
- # define HAVE_FMODL
- # endif
- # if defined(log10l)
- # define HAVE_LOG10L
- # endif
- # endif
- #endif
- /*************************************************************************
- * Generic definitions
- */
- #if !(defined(DEBUG) || defined(NDEBUG))
- # define NDEBUG
- #endif
- #include <assert.h>
- #include <ctype.h>
- #if defined(PREDEF_STANDARD_C99) && !defined(isascii)
- # define isascii(x) ((x) & 0x7F)
- #endif
- #if defined(TRIO_COMPILER_ANCIENT)
- # include <varargs.h>
- #else
- # include <stdarg.h>
- #endif
- #include <stddef.h>
- #if defined(TRIO_PLATFORM_WINCE)
- extern int errno;
- #else
- # include <errno.h>
- #endif
- #ifndef NULL
- # define NULL 0
- #endif
- #define NIL ((char)0)
- #ifndef FALSE
- # define FALSE (1 == 0)
- # define TRUE (! FALSE)
- #endif
- #define BOOLEAN_T int
- /* mincore() can be used for debugging purposes */
- #define VALID(x) (NULL != (x))
- #if TRIO_FEATURE_ERRORCODE
- /*
- * Encode the error code and the position. This is decoded
- * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
- */
- # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
- #else
- # define TRIO_ERROR_RETURN(x,y) (-1)
- #endif
- typedef unsigned long trio_flags_t;
- /*************************************************************************
- * Platform specific definitions
- */
- #if defined(TRIO_PLATFORM_UNIX)
- # include <unistd.h>
- # include <signal.h>
- # include <locale.h>
- # if !defined(TRIO_FEATURE_LOCALE)
- # define USE_LOCALE
- # endif
- #endif /* TRIO_PLATFORM_UNIX */
- #if defined(TRIO_PLATFORM_VMS)
- # include <unistd.h>
- #endif
- #if defined(TRIO_PLATFORM_WIN32)
- # if defined(TRIO_PLATFORM_WINCE)
- int read(int handle, char *buffer, unsigned int length);
- int write(int handle, const char *buffer, unsigned int length);
- # else
- # include <io.h>
- # define read _read
- # define write _write
- # endif
- #endif /* TRIO_PLATFORM_WIN32 */
- #if TRIO_FEATURE_WIDECHAR
- # if defined(PREDEF_STANDARD_C94)
- # include <wchar.h>
- # include <wctype.h>
- typedef wchar_t trio_wchar_t;
- typedef wint_t trio_wint_t;
- # else
- typedef char trio_wchar_t;
- typedef int trio_wint_t;
- # define WCONST(x) L ## x
- # define WEOF EOF
- # define iswalnum(x) isalnum(x)
- # define iswalpha(x) isalpha(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
- #endif
- /*************************************************************************
- * Compiler dependent definitions
- */
- /* Support for long long */
- #ifndef __cplusplus
- # if !defined(USE_LONGLONG)
- # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
- # define USE_LONGLONG
- # else
- # if defined(TRIO_COMPILER_SUNPRO)
- # define USE_LONGLONG
- # else
- # if defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1400)
- # define USE_LONGLONG
- # else
- # if defined(_LONG_LONG) || defined(_LONGLONG)
- # define USE_LONGLONG
- # endif
- # endif
- # endif
- # endif
- # endif
- #endif
- /* The extra long numbers */
- #if defined(USE_LONGLONG)
- typedef signed long long int trio_longlong_t;
- typedef unsigned long long int trio_ulonglong_t;
- #else
- # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT)
- typedef signed __int64 trio_longlong_t;
- typedef unsigned __int64 trio_ulonglong_t;
- # else
- typedef TRIO_SIGNED long int trio_longlong_t;
- typedef unsigned long int trio_ulonglong_t;
- # endif
- #endif
- /* Maximal and fixed integer types */
- #if defined(PREDEF_STANDARD_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;
- #else
- # if defined(PREDEF_STANDARD_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;
- # else
- # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT)
- 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;
- # else
- 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 TRIO_SIGNED char trio_int8_t;
- # endif
- # if defined(TRIO_INT16_T)
- typedef TRIO_INT16_T trio_int16_t;
- # else
- typedef TRIO_SIGNED short trio_int16_t;
- # endif
- # if defined(TRIO_INT32_T)
- typedef TRIO_INT32_T trio_int32_t;
- # else
- typedef TRIO_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
- # endif
- # endif
- #endif
- #if defined(HAVE_FLOORL)
- # define trio_floor(x) floorl((x))
- #else
- # define trio_floor(x) floor((double)(x))
- #endif
- #if defined(HAVE_CEILL)
- # define trio_ceil(x) ceill((x))
- #else
- # define trio_ceil(x) ceil((double)(x))
- #endif
- #if defined(HAVE_FMODL)
- # define trio_fmod(x,y) fmodl((x),(y))
- #else
- # define trio_fmod(x,y) fmod((double)(x),(double)(y))
- #endif
- #if defined(HAVE_POWL)
- # define trio_pow(x,y) powl((x),(y))
- #else
- # define trio_pow(x,y) pow((double)(x),(double)(y))
- #endif
- #if defined(HAVE_LOG10L)
- # define trio_log10(x) log10l((x))
- #else
- # define trio_log10(x) log10((double)(x))
- #endif
- #if TRIO_FEATURE_FLOAT
- # define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
- #endif
- /*************************************************************************
- * Internal Definitions
- */
- #if TRIO_FEATURE_FLOAT
- # if !defined(DECIMAL_DIG)
- # define DECIMAL_DIG DBL_DIG
- # endif
- /* Long double sizes */
- # ifdef LDBL_DIG
- # define MAX_MANTISSA_DIGITS LDBL_DIG
- # define MAX_EXPONENT_DIGITS 4
- # define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
- # else
- # define MAX_MANTISSA_DIGITS DECIMAL_DIG
- # define MAX_EXPONENT_DIGITS 3
- # define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
- # endif
- # if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
- # undef LDBL_DIG
- # undef LDBL_MANT_DIG
- # undef LDBL_EPSILON
- # define LDBL_DIG DBL_DIG
- # define LDBL_MANT_DIG DBL_MANT_DIG
- # define LDBL_EPSILON DBL_EPSILON
- # endif
- #endif /* TRIO_FEATURE_FLOAT */
- /* The maximal number of digits is for base 2 */
- #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
- /* The width of a pointer. The number of bits in a hex digit is 4 */
- #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
- #if TRIO_FEATURE_FLOAT
- /* Infinite and Not-A-Number for floating-point */
- # 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"
- #endif
- /* Various constants */
- enum {
- TYPE_PRINT = 1,
- #if TRIO_FEATURE_SCANF
- TYPE_SCAN = 2,
- #endif
- /* Flags. FLAGS_LAST must be less than ULONG_MAX */
- 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_IGNORE = 2 * FLAGS_WIDECHAR,
- FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
- FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
- FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
- FLAGS_LAST = FLAGS_FIXED_SIZE,
- /* Reused flags */
- FLAGS_EXCLUDE = FLAGS_SHORT,
- FLAGS_USER_DEFINED = FLAGS_IGNORE,
- FLAGS_USER_DEFINED_PARAMETER = FLAGS_IGNORE_PARAMETER,
- FLAGS_ROUNDING = FLAGS_INTMAX_T,
- /* Compounded flags */
- FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
- FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
- NO_POSITION = -1,
- NO_WIDTH = 0,
- NO_PRECISION = -1,
- NO_SIZE = -1,
- /* Do not change these */
- 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 + 1,
- #if TRIO_FEATURE_USER_DEFINED
- /* Maximal string lengths for user-defined specifiers */
- MAX_USER_NAME = 64,
- MAX_USER_DATA = 256,
- #endif
-
- /* Maximal length of locale separator strings */
- MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
- /* Maximal number of integers in grouping */
- MAX_LOCALE_GROUPS = 64
- };
- #define NO_GROUPING ((int)CHAR_MAX)
- /* Fundamental formatting parameter types */
- #define FORMAT_SENTINEL -1 /* marks end of parameters array */
- #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
- #define FORMAT_ERRNO 9
- #define FORMAT_USER_DEFINED 10
- /* Character constants */
- #define CHAR_IDENTIFIER '%'
- #define CHAR_ALT_IDENTIFIER '$'
- #define CHAR_BACKSLASH '\\'
- #define CHAR_QUOTE '\"'
- #define CHAR_ADJUST ' '
- #if TRIO_EXTENSION
- /* Character class expressions */
- # define CLASS_ALNUM "[:alnum:]"
- # define CLASS_ALPHA "[:alpha:]"
- # define CLASS_BLANK "[:blank:]"
- # 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:]"
- #endif
- /*
- * 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
- * S Widechar string (wchar_t *)
- * u Unsigned
- * x Hex
- * X Hex
- * [] Group
- * <> User-defined
- *
- * 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'
- #if TRIO_FEATURE_FLOAT
- # 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'
- #endif
- #define SPECIFIER_POINTER 'p'
- #if TRIO_FEATURE_SCANF
- # define SPECIFIER_GROUP '['
- # define SPECIFIER_UNGROUP ']'
- #endif
- #define SPECIFIER_COUNT 'n'
- #if TRIO_UNIX98
- # define SPECIFIER_CHAR_UPPER 'C'
- # define SPECIFIER_STRING_UPPER 'S'
- #endif
- #define SPECIFIER_HEXFLOAT 'a'
- #define SPECIFIER_HEXFLOAT_UPPER 'A'
- #define SPECIFIER_ERRNO 'm'
- #if TRIO_FEATURE_BINARY
- # define SPECIFIER_BINARY 'b'
- # define SPECIFIER_BINARY_UPPER 'B'
- #endif
- #if TRIO_FEATURE_USER_DEFINED
- # define SPECIFIER_USER_DEFINED_BEGIN '<'
- # define SPECIFIER_USER_DEFINED_END '>'
- # define SPECIFIER_USER_DEFINED_SEPARATOR ':'
- # define SPECIFIER_USER_DEFINED_EXTRA '|'
- #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 9th 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)
- *
- * 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
- */
- #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 '^' /* For scanlists */
- #define QUALIFIER_SIZE_T 'z'
- #define QUALIFIER_PTRDIFF_T 't'
- #define QUALIFIER_INTMAX_T 'j'
- #define QUALIFIER_QUAD 'q'
- #define QUALIFIER_SIZE_T_UPPER 'Z'
- #if TRIO_MISC
- # define QUALIFIER_WIDECHAR 'w'
- #endif
- #define QUALIFIER_FIXED_SIZE 'I'
- #define QUALIFIER_QUOTE '\''
- #define QUALIFIER_STICKY '!'
- #define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
- #define QUALIFIER_ROUNDING_UPPER 'R'
- #if TRIO_EXTENSION
- # define QUALIFIER_PARAM '@' /* Experimental */
- # define QUALIFIER_COLON ':' /* For scanlists */
- # define QUALIFIER_EQUAL '=' /* For scanlists */
- #endif
- /*************************************************************************
- *
- * Internal Structures
- *
- *************************************************************************/
- /* Parameters */
- typedef struct {
- /* An indication of which entry in the data union is used */
- int type;
- /* The flags */
- trio_flags_t flags;
- /* The width qualifier */
- int width;
- /* The precision qualifier */
- int precision;
- /* The base qualifier */
- int base;
- /* Base from specifier */
- int baseSpecifier;
- /* The size for the variable size qualifier */
- int varsize;
- /* Offset of the first character of the specifier */
- int beginOffset;
- /* Offset of the first character after the specifier */
- int endOffset;
- /* Position in the argument list that this parameter refers to */
- int position;
- /* The data from the argument list */
- union {
- char *string;
- #if TRIO_FEATURE_WIDECHAR
- trio_wchar_t *wstring;
- #endif
- trio_pointer_t pointer;
- union {
- trio_intmax_t as_signed;
- trio_uintmax_t as_unsigned;
- } number;
- #if TRIO_FEATURE_FLOAT
- double doubleNumber;
- double *doublePointer;
- trio_long_double_t longdoubleNumber;
- trio_long_double_t *longdoublePointer;
- #endif
- int errorNumber;
- } data;
- #if TRIO_FEATURE_USER_DEFINED
- /* For the user-defined specifier */
- union {
- char namespace[MAX_USER_NAME];
- int handler; /* if flags & FLAGS_USER_DEFINED_PARAMETER */
- } user_defined;
- char user_data[MAX_USER_DATA];
- #endif
- } trio_parameter_t;
- /* Container for customized functions */
- typedef struct {
- union {
- trio_outstream_t out;
- trio_instream_t in;
- } stream;
- trio_pointer_t closure;
- } trio_custom_t;
- /* General trio "class" */
- typedef struct _trio_class_t {
- /*
- * The function to write characters to a stream.
- */
- void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
- /*
- * The function to read characters from a stream.
- */
- void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
- /*
- * The current location in the stream.
- */
- trio_pointer_t location;
- /*
- * The character currently being processed.
- */
- int current;
- /*
- * The number of characters that would have been written/read
- * if there had been sufficient space.
- */
- int processed;
- /*
- * The number of characters that are actually written/read.
- * Processed and committed will only differ for the *nprintf
- * and *nscanf functions.
- */
- int committed;
- /*
- * The upper limit of characters that may be written/read.
- */
- int max;
- /*
- * The last output error that was detected.
- */
- int error;
- } trio_class_t;
- /* References (for user-defined callbacks) */
- typedef struct _trio_reference_t {
- trio_class_t *data;
- trio_parameter_t *parameter;
- } trio_reference_t;
- #if TRIO_FEATURE_USER_DEFINED
- /* Registered entries (for user-defined callbacks) */
- typedef struct _trio_userdef_t {
- struct _trio_userdef_t *next;
- trio_callback_t callback;
- char *name;
- } trio_userdef_t;
- #endif
- /*************************************************************************
- *
- * Internal Variables
- *
- *************************************************************************/
- static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.112 2008/11/09 10:52:26 breese Exp $";
- #if TRIO_FEATURE_FLOAT
- /*
- * Need this to workaround a parser bug in HP C/iX compiler that fails
- * to resolves macro definitions that includes type 'long double',
- * e.g: va_arg(arg_ptr, long double)
- */
- # if defined(TRIO_PLATFORM_MPEIX)
- static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
- # endif
- #endif
- static TRIO_CONST char internalNullString[] = "(nil)";
- #if defined(USE_LOCALE)
- static struct lconv *internalLocaleValues = NULL;
- #endif
- /*
- * UNIX98 says "in a locale where the radix character is not defined,
- * the radix character defaults to a period (.)"
- */
- #if TRIO_FEATURE_FLOAT || TRIO_FEATURE_LOCALE || defined(USE_LOCALE)
- static int internalDecimalPointLength = 1;
- static char internalDecimalPoint = '.';
- static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
- #endif
- #if TRIO_FEATURE_QUOTE || TRIO_FEATURE_LOCALE || TRIO_EXTENSION
- static int internalThousandSeparatorLength = 1;
- static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
- static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
- #endif
- static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- #if TRIO_FEATURE_SCANF
- static BOOLEAN_T internalDigitsUnconverted = TRUE;
- static int internalDigitArray[128];
- # if TRIO_EXTENSION
- static BOOLEAN_T internalCollationUnconverted = TRUE;
- static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
- # endif
- #endif
- #if TRIO_FEATURE_USER_DEFINED
- static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
- static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
- static trio_userdef_t *internalUserDef = NULL;
- #endif
- /*************************************************************************
- *
- * Internal Functions
- *
- ************************************************************************/
- #if defined(TRIO_EMBED_NAN)
- # include "trionan.c"
- #endif
- #if defined(TRIO_EMBED_STRING)
- # include "triostr.c"
- #endif
- /*************************************************************************
- * TrioIsQualifier
- *
- * Description:
- * Remember to add all new qualifiers to this function.
- * QUALIFIER_POSITION must not be added.
- */
- TRIO_PRIVATE BOOLEAN_T
- TrioIsQualifier
- TRIO_ARGS1((character),
- TRIO_CONST char character)
- {
- /* QUALIFIER_POSITION is not included */
- switch (character)
- {
- 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_CIRCUMFLEX:
- case QUALIFIER_LONG_UPPER:
- case QUALIFIER_SIZE_T:
- case QUALIFIER_PTRDIFF_T:
- case QUALIFIER_INTMAX_T:
- case QUALIFIER_QUAD:
- case QUALIFIER_SIZE_T_UPPER:
- #if defined(QUALIFIER_WIDECHAR)
- case QUALIFIER_WIDECHAR:
- #endif
- case QUALIFIER_QUOTE:
- case QUALIFIER_STICKY:
- case QUALIFIER_VARSIZE:
- #if defined(QUALIFIER_PARAM)
- case QUALIFIER_PARAM:
- #endif
- case QUALIFIER_FIXED_SIZE:
- case QUALIFIER_ROUNDING_UPPER:
- return TRUE;
- default:
- return FALSE;
- }
- }
- /*************************************************************************
- * TrioSetLocale
- */
- #if defined(USE_LOCALE)
- TRIO_PRIVATE void
- TrioSetLocale(TRIO_NOARGS)
- {
- internalLocaleValues = (struct lconv *)localeconv();
- if (internalLocaleValues)
- {
- if ((internalLocaleValues->decimal_point) &&
- (internalLocaleValues->decimal_point[0] != NIL))
- {
- internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
- if (internalDecimalPointLength == 1)
- {
- internalDecimalPoint = internalLocaleValues->decimal_point[0];
- }
- else
- {
- internalDecimalPoint = NIL;
- trio_copy_max(internalDecimalPointString,
- sizeof(internalDecimalPointString),
- internalLocaleValues->decimal_point);
- }
- }
- # if TRIO_EXTENSION
- if ((internalLocaleValues->thousands_sep) &&
- (internalLocaleValues->thousands_sep[0] != NIL))
- {
- trio_copy_max(internalThousandSeparator,
- sizeof(internalThousandSeparator),
- internalLocaleValues->thousands_sep);
- internalThousandSeparatorLength = trio_length(internalThousandSeparator);
- }
- # endif
- # if TRIO_EXTENSION
- if ((internalLocaleValues->grouping) &&
- (internalLocaleValues->grouping[0] != NIL))
- {
- trio_copy_max(internalGrouping,
- sizeof(internalGrouping),
- internalLocaleValues->grouping);
- }
- # endif
- }
- }
- #endif /* defined(USE_LOCALE) */
- #if TRIO_FEATURE_FLOAT && TRIO_FEATURE_QUOTE
- TRIO_PRIVATE int
- TrioCalcThousandSeparatorLength
- TRIO_ARGS1((digits),
- int digits)
- {
- int count = 0;
- int step = NO_GROUPING;
- char *groupingPointer = internalGrouping;
- while (digits > 0)
- {
- if (*groupingPointer == CHAR_MAX)
- {
- /* Disable grouping */
- break; /* while */
- }
- else if (*groupingPointer == 0)
- {
- /* Repeat last group */
- if (step == NO_GROUPING)
- {
- /* Error in locale */
- break; /* while */
- }
- }
- else
- {
- step = *groupingPointer++;
- }
- if (digits > step)
- count += internalThousandSeparatorLength;
- digits -= step;
- }
- return count;
- }
- #endif /* TRIO_FEATURE_FLOAT && TRIO_FEATURE_QUOTE */
- #if TRIO_FEATURE_QUOTE
- TRIO_PRIVATE BOOLEAN_T
- TrioFollowedBySeparator
- TRIO_ARGS1((position),
- int position)
- {
- int step = 0;
- char *groupingPointer = internalGrouping;
- position--;
- if (position == 0)
- return FALSE;
- while (position > 0)
- {
- if (*groupingPointer == CHAR_MAX)
- {
- /* Disable grouping */
- break; /* while */
- }
- else if (*groupingPointer != 0)
- {
- step = *groupingPointer++;
- }
- if (step == 0)
- break;
- position -= step;
- }
- return (position == 0);
- }
- #endif /* TRIO_FEATURE_QUOTE */
- /*************************************************************************
- * TrioGetPosition
- *
- * Get the %n$ position.
- */
- TRIO_PRIVATE int
- TrioGetPosition
- TRIO_ARGS2((format, offsetPointer),
- TRIO_CONST char *format,
- int *offsetPointer)
- {
- #if TRIO_FEATURE_POSITIONAL
- char *tmpformat;
- int number = 0;
- int offset = *offsetPointer;
- number = (int)trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL);
- offset = (int)(tmpformat - format);
- if ((number != 0) && (QUALIFIER_POSITION == format[offset++]))
- {
- *offsetPointer = offset;
- /*
- * number is decreased by 1, because n$ starts from 1, whereas
- * the array it is indexing starts from 0.
- */
- return number - 1;
- }
- #endif
- return NO_POSITION;
- }
- /*************************************************************************
- * TrioFindNamespace
- *
- * Find registered user-defined specifier.
- * The prev argument is used for optimization only.
- */
- #if TRIO_FEATURE_USER_DEFINED
- TRIO_PRIVATE trio_userdef_t *
- TrioFindNamespace
- TRIO_ARGS2((name, prev),
- TRIO_CONST char *name,
- trio_userdef_t **prev)
- {
- trio_userdef_t *def;
-
- if (internalEnterCriticalRegion)
- (void)internalEnterCriticalRegion(NULL);
-
- for (def = internalUserDef; def; def = def->next)
- {
- /* Case-sensitive string comparison */
- if (trio_equal_case(def->name, name))
- break;
-
- if (prev)
- *prev = def;
- }
-
- if (internalLeaveCriticalRegion)
- (void)internalLeaveCriticalRegion(NULL);
-
- return def;
- }
- #endif
- /*************************************************************************
- * TrioPower
- *
- * Description:
- * Calculate pow(base, exponent), where number and exponent are integers.
- */
- #if TRIO_FEATURE_FLOAT
- TRIO_PRIVATE trio_long_double_t
- TrioPower
- TRIO_ARGS2((number, exponent),
- int number,
- int exponent)
- {
- trio_long_double_t result;
- if (number == 10)
- {
- switch (exponent)
- {
- /* Speed up calculation of common cases */
- case 0:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
- break;
- case 1:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
- break;
- case 2:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
- break;
- case 3:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
- break;
- case 4:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
- break;
- case 5:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
- break;
- case 6:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
- break;
- case 7:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
- break;
- case 8:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
- break;
- case 9:
- result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
- break;
- default:
- result = trio_pow((trio_long_double_t)number,
- (trio_long_double_t)exponent);
- break;
- }
- }
- else
- {
- return trio_pow((trio_long_double_t)number,
- (trio_long_double_t)exponent);
- }
- return result;
- }
- #endif /* TRIO_FEATURE_FLOAT */
- /*************************************************************************
- * TrioLogarithm
- */
- #if TRIO_FEATURE_FLOAT
- TRIO_PRIVATE trio_long_double_t
- TrioLogarithm
- TRIO_ARGS2((number, base),
- trio_long_double_t number,
- int base)
- {
- trio_long_double_t result;
- if (number <= 0.0)
- {
- /* xlC crashes on log(0) */
- result = (number == 0.0) ? trio_ninf() : trio_nan();
- }
- else
- {
- if (base == 10)
- {
- result = trio_log10(number);
- }
- else
- {
- result = trio_log10(number) / trio_log10((double)base);
- }
- }
- return result;
- }
- #endif /* TRIO_FEATURE_FLOAT */
- /*************************************************************************
- * TrioLogarithmBase
- */
- #if TRIO_FEATURE_FLOAT
- TRIO_PRIVATE double
- TrioLogarithmBase
- TRIO_ARGS1((base),
- int base)
- {
- switch (base)
- {
- case BASE_BINARY : return 1.0;
- case BASE_OCTAL : return 3.0;
- case BASE_DECIMAL: return 3.321928094887362345;
- case BASE_HEX : return 4.0;
- default : return TrioLogarithm((double)base, 2);
- }
- }
- #endif /* TRIO_FEATURE_FLOAT */
- /*************************************************************************
- * TrioParseQualifiers
- *
- * Description:
- * Parse the qualifiers of a potential conversion specifier
- */
- TRIO_PRIVATE int
- TrioParseQualifiers
- TRIO_ARGS4((type, format, offset, parameter),
- int type,
- TRIO_CONST char *format,
- int offset,
- trio_parameter_t *parameter)
- {
- char ch;
- int dots = 0; /* Count number of dots in modifier part */
- char *tmpformat;
- parameter->beginOffset = offset - 1;
- parameter->flags = FLAGS_NEW;
- parameter->position = TrioGetPosition(format, &offset);
- /* Default values */
- parameter->width = NO_WIDTH;
- parameter->precision = NO_PRECISION;
- parameter->base = NO_BASE;
- parameter->varsize = NO_SIZE;
- while (TrioIsQualifier(format[offset]))
- {
- ch = format[offset++];
- switch (ch)
- {
- case QUALIFIER_SPACE:
- parameter->flags |= FLAGS_SPACE;
- break;
- case QUALIFIER_PLUS:
- parameter->flags |= FLAGS_SHOWSIGN;
- break;
- case QUALIFIER_MINUS:
- parameter->flags |= FLAGS_LEFTADJUST;
- parameter->flags &= ~FLAGS_NILPADDING;
- break;
- case QUALIFIER_ALTERNATIVE:
- parameter->flags |= FLAGS_ALTERNATIVE;
- break;
- case QUALIFIER_DOT:
- if (dots == 0) /* Precision */
- {
- dots++;
- /* Skip if no precision */
- if (QUALIFIER_DOT == format[offset])
- break;
- /* After the first dot we have the precision */
- parameter->flags |= FLAGS_PRECISION;
- if ((QUALIFIER_STAR == format[offset])
- #if defined(QUALIFIER_PARAM)
- || (QUALIFIER_PARAM == format[offset])
- #endif
- )
- {
- offset++;
- parameter->flags |= FLAGS_PRECISION_PARAMETER;
- parameter->precision = TrioGetPosition(format, &offset);
- }
- else
- {
- parameter->precision = trio_to_long(&format[offset],
- &tmpformat,
- BASE_DECIMAL);
- offset = (int)(tmpformat - format);
- }
- }
- else if (dots == 1) /* Base */
- {
- dots++;
- /* After the second dot we have the base */
- parameter->flags |= FLAGS_BASE;
- if ((QUALIFIER_STAR == format[offset])
- #if defined(QUALIFIER_PARAM)
- || (QUALIFIER_PARAM == format[offset])
- #endif
- )
- {
- offset++;
- parameter->flags |= FLAGS_BASE_PARAMETER;
- parameter->base = TrioGetPosition(format, &offset);
- }
- else
- {
- parameter->base = trio_to_long(&format[offset],
- &tmpformat,
- BASE_DECIMAL);
- if (parameter->base > MAX_BASE)
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- offset = (int)(tmpformat - format);
- }
- }
- else
- {
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- }
- break; /* QUALIFIER_DOT */
- #if defined(QUALIFIER_PARAM)
- case QUALIFIER_PARAM:
- parameter->type = TYPE_PRINT;
- /* FALLTHROUGH */
- #endif
- case QUALIFIER_STAR:
- /* This has different meanings for print and scan */
- if (TYPE_PRINT == type)
- {
- /* Read with from parameter */
- parameter->flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
- int width = TrioGetPosition(format, &offset);
- if (NO_POSITION != width) parameter->width = width;
- /* else keep parameter->width = NO_WIDTH which != NO_POSITION */
- }
- #if TRIO_FEATURE_SCANF
- else
- {
- /* Scan, but do not store result */
- parameter->flags |= FLAGS_IGNORE;
- }
- #endif
- break; /* QUALIFIER_STAR */
- case '0':
- if (! (parameter->flags & FLAGS_LEFTADJUST))
- parameter->flags |= FLAGS_NILPADDING;
- /* FALLTHROUGH */
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- parameter->flags |= FLAGS_WIDTH;
- /*
- * &format[offset - 1] is used to "rewind" the read
- * character from format
- */
- parameter->width = trio_to_long(&format[offset - 1],
- &tmpformat,
- BASE_DECIMAL);
- offset = (int)(tmpformat - format);
- break;
- case QUALIFIER_SHORT:
- if (parameter->flags & FLAGS_SHORTSHORT)
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- else if (parameter->flags & FLAGS_SHORT)
- parameter->flags |= FLAGS_SHORTSHORT;
- else
- parameter->flags |= FLAGS_SHORT;
- break;
- case QUALIFIER_LONG:
- if (parameter->flags & FLAGS_QUAD)
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- else if (parameter->flags & FLAGS_LONG)
- parameter->flags |= FLAGS_QUAD;
- else
- parameter->flags |= FLAGS_LONG;
- break;
- #if TRIO_FEATURE_LONGDOUBLE
- case QUALIFIER_LONG_UPPER:
- parameter->flags |= FLAGS_LONGDOUBLE;
- break;
- #endif
- #if TRIO_FEATURE_SIZE_T
- case QUALIFIER_SIZE_T:
- parameter->flags |= FLAGS_SIZE_T;
- /* Modify flags for later truncation of number */
- if (sizeof(size_t) == sizeof(trio_ulonglong_t))
- parameter->flags |= FLAGS_QUAD;
- else if (sizeof(size_t) == sizeof(long))
- parameter->flags |= FLAGS_LONG;
- break;
- #endif
- #if TRIO_FEATURE_PTRDIFF_T
- case QUALIFIER_PTRDIFF_T:
- parameter->flags |= FLAGS_PTRDIFF_T;
- if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
- parameter->flags |= FLAGS_QUAD;
- else if (sizeof(ptrdiff_t) == sizeof(long))
- parameter->flags |= FLAGS_LONG;
- break;
- #endif
- #if TRIO_FEATURE_INTMAX_T
- case QUALIFIER_INTMAX_T:
- parameter->flags |= FLAGS_INTMAX_T;
- if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
- parameter->flags |= FLAGS_QUAD;
- else if (sizeof(trio_intmax_t) == sizeof(long))
- parameter->flags |= FLAGS_LONG;
- break;
- #endif
- #if TRIO_FEATURE_QUAD
- case QUALIFIER_QUAD:
- parameter->flags |= FLAGS_QUAD;
- break;
- #endif
- #if TRIO_FEATURE_FIXED_SIZE
- case QUALIFIER_FIXED_SIZE:
- if (parameter->flags & FLAGS_FIXED_SIZE)
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- if (parameter->flags & (FLAGS_ALL_SIZES |
- FLAGS_LONGDOUBLE |
- FLAGS_WIDECHAR |
- FLAGS_VARSIZE_PARAMETER))
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- if ((format[offset] == '6') &&
- (format[offset + 1] == '4'))
- {
- parameter->varsize = sizeof(trio_int64_t);
- offset += 2;
- }
- else if ((format[offset] == '3') &&
- (format[offset + 1] == '2'))
- {
- parameter->varsize = sizeof(trio_int32_t);
- offset += 2;
- }
- else if ((format[offset] == '1') &&
- (format[offset + 1] == '6'))
- {
- parameter->varsize = sizeof(trio_int16_t);
- offset += 2;
- }
- else if (format[offset] == '8')
- {
- parameter->varsize = sizeof(trio_int8_t);
- offset++;
- }
- else
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- parameter->flags |= FLAGS_FIXED_SIZE;
- break;
- #endif /* TRIO_FEATURE_FIXED_SIZE */
- #if defined(QUALIFIER_WIDECHAR)
- case QUALIFIER_WIDECHAR:
- parameter->flags |= FLAGS_WIDECHAR;
- break;
- #endif
- #if TRIO_FEATURE_SIZE_T_UPPER
- case QUALIFIER_SIZE_T_UPPER:
- break;
- #endif
- #if TRIO_FEATURE_QUOTE
- case QUALIFIER_QUOTE:
- parameter->flags |= FLAGS_QUOTE;
- break;
- #endif
- #if TRIO_FEATURE_STICKY
- case QUALIFIER_STICKY:
- parameter->flags |= FLAGS_STICKY;
- break;
- #endif
- #if TRIO_FEATURE_VARSIZE
- case QUALIFIER_VARSIZE:
- parameter->flags |= FLAGS_VARSIZE_PARAMETER;
- break;
- #endif
- #if TRIO_FEATURE_ROUNDING
- case QUALIFIER_ROUNDING_UPPER:
- parameter->flags |= FLAGS_ROUNDING;
- break;
- #endif
- default:
- /* Bail out completely to make the error more obvious */
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- }
- } /* while qualifier */
- parameter->endOffset = offset;
- return 0;
- }
- /*************************************************************************
- * TrioParseSpecifier
- *
- * Description:
- * Parse the specifier part of a potential conversion specifier
- */
- TRIO_PRIVATE int
- TrioParseSpecifier
- TRIO_ARGS4((type, format, offset, parameter),
- int type,
- TRIO_CONST char *format,
- int offset,
- trio_parameter_t *parameter)
- {
- parameter->baseSpecifier = NO_BASE;
- switch (format[offset++])
- {
- #if defined(SPECIFIER_CHAR_UPPER)
- case SPECIFIER_CHAR_UPPER:
- parameter->flags |= FLAGS_WIDECHAR;
- /* FALLTHROUGH */
- #endif
- case SPECIFIER_CHAR:
- if (parameter->flags & FLAGS_LONG)
- parameter->flags |= FLAGS_WIDECHAR;
- else if (parameter->flags & FLAGS_SHORT)
- parameter->flags &= ~FLAGS_WIDECHAR;
- parameter->type = FORMAT_CHAR;
- break;
- #if defined(SPECIFIER_STRING_UPPER)
- case SPECIFIER_STRING_UPPER:
- parameter->flags |= FLAGS_WIDECHAR;
- /* FALLTHROUGH */
- #endif
- case SPECIFIER_STRING:
- if (parameter->flags & FLAGS_LONG)
- parameter->flags |= FLAGS_WIDECHAR;
- else if (parameter->flags & FLAGS_SHORT)
- parameter->flags &= ~FLAGS_WIDECHAR;
- parameter->type = FORMAT_STRING;
- break;
- #if defined(SPECIFIER_GROUP)
- case SPECIFIER_GROUP:
- if (TYPE_SCAN == type)
- {
- int depth = 1;
- parameter->type = FORMAT_GROUP;
- if (format[offset] == QUALIFIER_CIRCUMFLEX)
- offset++;
- if (format[offset] == SPECIFIER_UNGROUP)
- offset++;
- if (format[offset] == QUALIFIER_MINUS)
- offset++;
- /* Skip nested brackets */
- while (format[offset] != NIL)
- {
- if (format[offset] == SPECIFIER_GROUP)
- {
- depth++;
- }
- else if (format[offset] == SPECIFIER_UNGROUP)
- {
- if (--depth <= 0)
- {
- offset++;
- break;
- }
- }
- offset++;
- }
- }
- break;
- #endif /* defined(SPECIFIER_GROUP) */
- case SPECIFIER_INTEGER:
- parameter->type = FORMAT_INT;
- break;
- case SPECIFIER_UNSIGNED:
- parameter->flags |= FLAGS_UNSIGNED;
- parameter->type = FORMAT_INT;
- break;
- case SPECIFIER_DECIMAL:
- parameter->baseSpecifier = BASE_DECIMAL;
- parameter->type = FORMAT_INT;
- break;
- case SPECIFIER_OCTAL:
- parameter->flags |= FLAGS_UNSIGNED;
- parameter->baseSpecifier = BASE_OCTAL;
- parameter->type = FORMAT_INT;
- break;
- #if TRIO_FEATURE_BINARY
- case SPECIFIER_BINARY_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- case SPECIFIER_BINARY:
- parameter->flags |= FLAGS_NILPADDING;
- parameter->baseSpecifier = BASE_BINARY;
- parameter->type = FORMAT_INT;
- break;
- #endif
- case SPECIFIER_HEX_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- case SPECIFIER_HEX:
- parameter->flags |= FLAGS_UNSIGNED;
- parameter->baseSpecifier = BASE_HEX;
- parameter->type = FORMAT_INT;
- break;
- #if defined(SPECIFIER_FLOAT_E)
- # if defined(SPECIFIER_FLOAT_E_UPPER)
- case SPECIFIER_FLOAT_E_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- # endif
- case SPECIFIER_FLOAT_E:
- parameter->flags |= FLAGS_FLOAT_E;
- parameter->type = FORMAT_DOUBLE;
- break;
- #endif
- #if defined(SPECIFIER_FLOAT_G)
- # if defined(SPECIFIER_FLOAT_G_UPPER)
- case SPECIFIER_FLOAT_G_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- # endif
- case SPECIFIER_FLOAT_G:
- parameter->flags |= FLAGS_FLOAT_G;
- parameter->type = FORMAT_DOUBLE;
- break;
- #endif
- #if defined(SPECIFIER_FLOAT_F)
- # if defined(SPECIFIER_FLOAT_F_UPPER)
- case SPECIFIER_FLOAT_F_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- # endif
- case SPECIFIER_FLOAT_F:
- parameter->type = FORMAT_DOUBLE;
- break;
- #endif
- #if defined(TRIO_COMPILER_VISUALC)
- # pragma warning( push )
- # pragma warning( disable : 4127 ) /* Conditional expression is constant */
- #endif
- case SPECIFIER_POINTER:
- if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
- parameter->flags |= FLAGS_QUAD;
- else if (sizeof(trio_pointer_t) == sizeof(long))
- parameter->flags |= FLAGS_LONG;
- parameter->type = FORMAT_POINTER;
- break;
- #if defined(TRIO_COMPILER_VISUALC)
- # pragma warning( pop )
- #endif
- case SPECIFIER_COUNT:
- parameter->type = FORMAT_COUNT;
- break;
- #if TRIO_FEATURE_HEXFLOAT
- case SPECIFIER_HEXFLOAT_UPPER:
- parameter->flags |= FLAGS_UPPER;
- /* FALLTHROUGH */
- case SPECIFIER_HEXFLOAT:
- parameter->baseSpecifier = BASE_HEX;
- parameter->type = FORMAT_DOUBLE;
- break;
- #endif
- #if TRIO_FEATURE_ERRNO
- case SPECIFIER_ERRNO:
- parameter->type = FORMAT_ERRNO;
- break;
- #endif
- #if TRIO_FEATURE_USER_DEFINED
- case SPECIFIER_USER_DEFINED_BEGIN:
- {
- unsigned int max;
- int without_namespace = TRUE;
- char* tmpformat = (char *)&format[offset];
- int ch;
- parameter->type = FORMAT_USER_DEFINED;
- parameter->user_defined.namespace[0] = NIL;
- while ((ch = format[offset]) != NIL)
- {
- offset++;
- if ((ch == SPECIFIER_USER_DEFINED_END) || (ch == SPECIFIER_USER_DEFINED_EXTRA))
- {
- if (without_namespace)
- /* No namespace, handler will be passed as an argument */
- parameter->flags |= FLAGS_USER_DEFINED_PARAMETER;
- /* Copy the user data */
- max = (unsigned int)(&format[offset] - tmpformat);
- if (max > MAX_USER_DATA)
- max = MAX_USER_DATA;
- trio_copy_max(parameter->user_data, max, tmpformat);
- /* Skip extra data (which is only there to keep the compiler happy) */
- while ((ch != NIL) && (ch != SPECIFIER_USER_DEFINED_END))
- ch = format[offset++];
- break; /* while */
- }
- if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
- {
- without_namespace = FALSE;
- /* Copy the namespace for later looking-up */
- max = (int)(&format[offset] - tmpformat);
- if (max > MAX_USER_NAME)
- max = MAX_USER_NAME;
- trio_copy_max(parameter->user_defined.namespace, max, tmpformat);
- tmpformat = (char *)&format[offset];
- }
- }
- if (ch != SPECIFIER_USER_DEFINED_END)
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- }
- break;
- #endif /* TRIO_FEATURE_USER_DEFINED */
- default:
- /* Bail out completely to make the error more obvious */
- return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
- }
- parameter->endOffset = offset;
- return 0;
- }
- /*************************************************************************
- * TrioParse
- *
- * Description:
- * Parse the format string
- */
- TRIO_PRIVATE int
- TrioParse
- TRIO_ARGS5((type, format, parameters, arglist, argarray),
- int type,
- TRIO_CONST char *format,
- trio_parameter_t *parameters,
- va_list arglist,
- trio_pointer_t *argarray)
- {
- /* Count the number of times a parameter is referenced */
- unsigned short usedEntries[MAX_PARAMETERS];
- /* Parameter counters */
- int parameterPosition;
- int maxParam = -1;
- /* Utility variables */
- int offset; /* Offset into formatting string */
- BOOLEAN_T positional; /* Does the specifier have a positional? */
- #if TRIO_FEATURE_STICKY
- BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
- #endif
- /*
- * indices specifies the order in which the parameters must be
- * read from the va_args (this is necessary to handle positionals)
- */
- int indices[MAX_PARAMETERS];
- int pos = 0;
- /* Various variables */
- #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
- int charlen;
- #endif
- int save_errno;
- int i = -1;
- int num;
- /*
- * The 'parameters' array is not initialized, but we need to
- * know which entries we have used.
- */
- memset(usedEntries, 0, sizeof(usedEntries));
- save_errno = errno;
- offset = 0;
- parameterPosition = 0;
- #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
- (void)mblen(NULL, 0);
- #endif
-
- while (format[offset])
- {
- trio_parameter_t parameter = {};
- int status;
- #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
- if (! isascii(format[offset]))
- {
- /*
- * Multibyte characters cannot be legal specifiers or
- * modifiers, so we skip over them.
- */
- charlen = mblen(&format[offset], MB_LEN_MAX);
- offset += (charlen > 0) ? charlen : 1;
- continue; /* while */
- }
- #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
- switch(format[offset++]) {
- case CHAR_IDENTIFIER:
- {
- if (CHAR_IDENTIFIER == format[offset])
- {
- /* skip double "%" */
- offset++;
- continue; /* while */
- }
- status = TrioParseQualifiers(type, format, offset, ¶meter);
- if (status < 0)
- return status; /* Return qualifier syntax error */
- status = TrioParseSpecifier(type, format, parameter.endOffset, ¶meter);
- if (status < 0)
- return status; /* Return specifier syntax error */
- }
- break;
- #if TRIO_EXTENSION
- case CHAR_ALT_IDENTIFIER:
- {
- status = TrioParseQualifiers(type, format, offset, ¶meter);
- if (status < 0)
- continue; /* False alert, not a user defined specifier */
- status = TrioParseSpecifier(type, format, parameter.endOffset, ¶meter);
- if ((status < 0) || (FORMAT_USER_DEFINED != parameter.type))
- continue; /* False alert, not a user defined specifier */
- }
- break;
- #endif
- default:
- continue; /* while */
- }
- /* now handle the parsed conversion specification */
- positional = (NO_POSITION != parameter.position);
- /*
- * Parameters only need the type and value. The value is
- * read later.
- */
- if (parameter.flags & FLAGS_WIDTH_PARAMETER)
- {
- if (parameter.width == NO_WIDTH)
- {
- parameter.width = parameterPosition++;
- }
- else
- {
- if (! positional)
- parameter.position = parameter.width + 1;
- }
- usedEntries[parameter.width] += 1;
- if (parameter.width > maxParam) maxParam = parameter.width;
- parameters[pos].type = FORMAT_PARAMETER;
- parameters[pos].flags = 0;
- indices[parameter.width] = pos;
- parameter.width = pos++;
- }
- if (parameter.flags & FLAGS_PRECISION_PARAMETER)
- {
- if (parameter.precision == NO_PRECISION)
- {
- parameter.precision = parameterPosition++;
- }
- else
- {
- if (! positional)
- parameter.position = parameter.precision + 1;
- }
- usedEntries[parameter.precision] += 1;
- if (parameter.precision > maxParam) maxParam = parameter.precision;
- parameters[pos].type = FORMAT_PARAMETER;
- parameters[pos].flags = 0;
- indices[parameter.precision] = pos;
- parameter.precision = pos++;
- }
- if (parameter.flags & FLAGS_BASE_PARAMETER)
- {
- if (parameter.base == NO_BASE)
- {
- parameter.base = parameterPosition++;
- }
- else
- {
- if (! positional)
- parameter.position = parameter.base + 1;
- }
- usedEntries[parameter.base] += 1;
- if (parameter.base > maxParam) maxParam = parameter.base;
- parameters[pos].type = FORMAT_PARAMETER;
-