From 450296070e14629141738fbb34b9a0ad13af1f02 Mon Sep 17 00:00:00 2001 From: Bjorn Reese Date: Tue, 21 Aug 2001 09:23:53 +0000 Subject: [PATCH] Re-worked NaN and Inf support --- ChangeLog | 7 + Makefile.am | 4 +- include/libxml/Makefile.am | 3 +- include/libxml/trionan.h | 54 ++++ trio.c | 122 ++------- triodef.h | 82 ++++++ trionan.c | 538 +++++++++++++++++++++++++++++++++++++ xmlcatalog.c | 7 + xpath.c | 146 ++-------- 9 files changed, 724 insertions(+), 239 deletions(-) create mode 100644 include/libxml/trionan.h create mode 100644 triodef.h create mode 100644 trionan.c diff --git a/ChangeLog b/ChangeLog index 1ae75ed5..4d8e21f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Tue Aug 21 11:18:45 CEST 2001 Bjorn Reese + + * Makefile.am trio.c triodef.h trionan.c xpath.c + include/libxml/Makefile.am include/libxml/trionan.h: + Re-worked Not-A-Number and Infinity support. + * xmlcatalog.c: added readline include files + Mon Aug 20 02:04:13 CEST 2001 Daniel Veillard * Makefile.am xmlcatalog.c libxml.spec.in: renaming diff --git a/Makefile.am b/Makefile.am index 2e1d622c..36f24b17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,14 +23,14 @@ libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c \ valid.c xlink.c HTMLparser.c HTMLtree.c debugXML.c xpath.c \ xpointer.c xinclude.c nanohttp.c nanoftp.c DOCBparser.c \ - catalog.c strio.c trio.c + catalog.c trionan.c strio.c trio.c else libxml2_la_SOURCES = SAX.c entities.c encoding.c error.c parserInternals.c \ parser.c tree.c hash.c list.c xmlIO.c xmlmemory.c uri.c \ valid.c xlink.c HTMLparser.c HTMLtree.c debugXML.c xpath.c \ xpointer.c xinclude.c nanohttp.c nanoftp.c DOCBparser.c \ - catalog.c + catalog.c trionan.c endif diff --git a/include/libxml/Makefile.am b/include/libxml/Makefile.am index 38ad0ef5..9bf32489 100644 --- a/include/libxml/Makefile.am +++ b/include/libxml/Makefile.am @@ -29,7 +29,8 @@ xmlinc_HEADERS = \ xmlversion.h \ xmlwin32version.h \ DOCBparser.h \ - catalog.h + catalog.h \ + trionan.h install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(xmlincdir) $(DESTDIR)$(xmlincdir)/libxml diff --git a/include/libxml/trionan.h b/include/libxml/trionan.h new file mode 100644 index 00000000..f955198c --- /dev/null +++ b/include/libxml/trionan.h @@ -0,0 +1,54 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * 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. + * + ************************************************************************/ + +#ifndef __TRIO_NAN_H__ +#define __TRIO_NAN_H__ + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Return NaN (Not-a-Number). + */ +double trio_nan(void); + +/* + * Return positive infinity. + */ +double trio_pinf(void); + +/* + * Return negative infinity. + */ +double trio_ninf(void); + +/* + * If number is a NaN return non-zero, otherwise return zero. + */ +int trio_isnan(double number); + +/* + * If number is positive infinity return 1, if number is negative + * infinity return -1, otherwise return 0. + */ +int trio_isinf(double number); + +#ifdef __cplusplus +} +#endif + +#endif /* __TRIO_NAN_H__ */ diff --git a/trio.c b/trio.c index 380f54c5..1d6ea6a4 100644 --- a/trio.c +++ b/trio.c @@ -46,8 +46,10 @@ static const char rcsid[] = "@(#)$Id$"; /************************************************************************* * Trio include files */ +#include "triodef.h" #include "trio.h" #include "triop.h" +#include "trionan.h" #include "strio.h" /* @@ -60,32 +62,6 @@ static const char rcsid[] = "@(#)$Id$"; # define TRIO_ERROR_RETURN(x,y) (-1) #endif - -/************************************************************************* - * Platform and compiler support detection - */ -#if defined(unix) || defined(__xlC__) || defined(_AIX) || defined(__QNX__) -# define PLATFORM_UNIX -#elif defined(AMIGA) && defined(__GNUC__) -# define PLATFORM_UNIX -#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 -#endif - #if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR # define TRIO_COMPILER_SUPPORTS_MULTIBYTE # if !defined(MB_LEN_MAX) @@ -127,7 +103,7 @@ static const char rcsid[] = "@(#)$Id$"; #define VALID(x) (NULL != (x)) /* xlC crashes on log10(0) */ -#define guarded_log10(x) (((x) == 0.0) ? -HUGE_VAL : log10(x)) +#define guarded_log10(x) (((x) == 0.0) ? trio_ninf() : log10(x)) #define guarded_log16(x) (guarded_log10(x) / log10(16.0)) @@ -146,6 +122,8 @@ static const char rcsid[] = "@(#)$Id$"; # define write _write #endif /* PLATFORM_WIN32 */ +#define TRIO_MSVC_VERSION_5 1100 + #if TRIO_WIDECHAR # if defined(TRIO_COMPILER_SUPPORTS_ISO94) # include @@ -192,7 +170,7 @@ typedef int wint_t; 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) +# if (_MSC_VER >= TRIO_MSVC_VERSION_5) typedef signed __int64 trio_longlong_t; typedef unsigned __int64 trio_ulonglong_t; # else @@ -781,74 +759,6 @@ TrioIsQualifier(const char ch) } } -/************************************************************************* - * 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. - */ -static double -TrioDivide(double dividend, double divisor) -{ - return dividend / divisor; -} - -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); - value = TrioDivide(0.0, 0.0); - signal(SIGFPE, signal_handler); - return value; -#else - return TrioDivide(0.0, 0.0); -#endif -} - -/************************************************************************* - * 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 -} - /************************************************************************* * TrioSetLocale [private] */ @@ -1930,7 +1840,7 @@ TrioPreprocess(int type, */ static void TrioWriteNumber(trio_T *self, - trio_uintmax_t number, + trio_intmax_t snumber, unsigned long flags, int width, int precision, @@ -1941,6 +1851,7 @@ TrioWriteNumber(trio_T *self, char *bufferend; char *pointer; const char *digits; + trio_uintmax_t number; int i; int length; char *p; @@ -1956,9 +1867,8 @@ TrioWriteNumber(trio_T *self, isNegative = (flags & FLAGS_UNSIGNED) ? FALSE - : ((trio_intmax_t)number < 0); - if (isNegative) - number = -number; + : (snumber < 0); + number = (isNegative) ? -snumber : snumber; if (flags & FLAGS_QUAD) number &= (trio_ulonglong_t)-1; @@ -2374,7 +2284,7 @@ TrioWriteDouble(trio_T *self, number = (double)longdoubleNumber; /* Look for infinite numbers and non-a-number first */ - switch (TrioIsInfinite(number)) + switch (trio_isinf(number)) { case 1: /* Positive infinity */ @@ -2398,7 +2308,7 @@ TrioWriteDouble(trio_T *self, /* Finitude */ break; } - if (TrioIsNan(number)) + if (trio_isnan(number)) { TrioWriteString(self, (flags & FLAGS_UPPER) @@ -2448,7 +2358,7 @@ TrioWriteDouble(trio_T *self, { /* Scale the number */ workNumber = guarded_log10(number); - if (workNumber == -HUGE_VAL) + if (trio_isinf(workNumber) == -1) { exponent = 0; /* Undo setting */ @@ -4916,14 +4826,14 @@ TrioReadDouble(trio_T *self, StrEqual(&doubleString[start], LONG_INFINITE_UPPER)) { *target = ((start == 1 && doubleString[0] == '-')) - ? -HUGE_VAL - : HUGE_VAL; + ? trio_ninf() + : trio_pinf(); return TRUE; } if (StrEqual(doubleString, NAN_LOWER)) { /* NaN must not have a preceeding + nor - */ - *target = TrioGenerateNaN(); + *target = trio_nan(); return TRUE; } return FALSE; diff --git a/triodef.h b/triodef.h new file mode 100644 index 00000000..407ea039 --- /dev/null +++ b/triodef.h @@ -0,0 +1,82 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * 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. + * + ************************************************************************/ + +#ifndef __TRIO_TRIODEF_H__ +#define __TRIO_TRIODEF_H__ + +/************************************************************************* + * Platform and compiler support detection + */ +#if defined(__GNUC__) +# define TRIO_COMPILER_GCC +#elif defined(__SUNPRO_C) +# define TRIO_COMPILER_SUNPRO +#elif defined(__SUNPRO_CC) +# define TRIO_COMPILER_SUNPRO +# define __SUNPRO_C __SUNPRO_CC +#elif defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__) +# define TRIO_COMPILER_XLC +#elif defined(_AIX) && !defined(__GNUC__) +# define TRIO_COMPILER_XLC /* Workaround for old xlc */ +#elif defined(__DECC) || defined(__DECCXX) +# define TRIO_COMPILER_DECC +#elif defined(_MSC_VER) +# define TRIO_COMPILER_MSVC +#endif + +#if defined(unix) || defined(__unix) || defined(__unix__) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_XLC) || defined(_AIX) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_DECC) || defined(__osf__) +# define TRIO_PLATFORM_UNIX +#elif defined(__NetBSD__) +# define TRIO_PLATFORM_UNIX +#elif defined(__QNX__) +# define TRIO_PLATFORM_UNIX +#elif defined(AMIGA) && defined(TRIO_COMPILER_GCC) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32) +# define TRIO_PLATFORM_WIN32 +#endif + +#if defined(__STDC__) +# define TRIO_COMPILER_SUPPORTS_C90 +# if defined(__STDC_VERSION__) +# if (__STDC_VERSION__ >= 199409L) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# if (__STDC_VERSION__ >= 199901L) +# define TRIO_COMPILER_SUPPORTS_C99 +# endif +# elif defined(TRIO_COMPILER_SUNPRO) +# if (__SUNPRO_C >= 0x420) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# endif +#endif + +#if defined(_XOPEN_SOURCE) +# if defined(_XOPEN_SOURCE_EXTENDED) +# define TRIO_COMPILER_SUPPORTS_UNIX95 +# endif +# if (_XOPEN_VERSION >= 500) +# define TRIO_COMPILER_SUPPORTS_UNIX98 +# endif +#endif + +#endif /* __TRIO_TRIODEF_H__ */ diff --git a/trionan.c b/trionan.c new file mode 100644 index 00000000..d8bd99b2 --- /dev/null +++ b/trionan.c @@ -0,0 +1,538 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * 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. + * + ************************************************************************ + * + * Functions to handle special quantities in floating-point numbers + * (that is, NaNs and infinity). They provide the capability to detect + * and fabricate special quantities. + * + * Although written to be as portable as possible, it can never be + * guaranteed to work on all platforms, as not all hardware supports + * special quantities. + * + * The approach used here (approximately) is to: + * + * 1. Use C99 functionality when available. + * 2. Use IEEE 754 bit-patterns if possible. + * 3. Use platform-specific techniques. + * + * This program has been tested on the following platforms (in + * alphabetic order) + * + * OS CPU Compiler + * ------------------------------------------------- + * AIX 4.1.4 PowerPC gcc + * Darwin 1.3.7 PowerPC gcc + * FreeBSD 2.2 x86 gcc + * FreeBSD 3.3 x86 gcc + * FreeBSD 4.3 x86 gcc + * FreeBSD 4.3 Alpha gcc + * HP-UX 10.20 PA-RISC gcc + * HP-UX 10.20 PA-RISC HP C++ + * IRIX 6.5 MIPS MIPSpro C + * Linux 2.2 x86 gcc + * Linux 2.2 Alpha gcc + * Linux 2.4 IA64 gcc + * Linux 2.4 StrongARM gcc + * NetBSD 1.4 x86 gcc + * NetBSD 1.4 StrongARM gcc + * NetBSD 1.5 Alpha gcc + * RISC OS 4 StrongARM Norcroft C + * Solaris 2.5.1 x86 gcc + * Solaris 2.5.1 Sparc gcc + * Solaris 2.6 Sparc WorkShop 4.2 + * Solaris 8 Sparc Forte C 6 + * Tru64 4.0D Alpha gcc + * Tru64 5.1 Alpha gcc + * WinNT x86 MSVC 5.0 & 6.0 + * + ************************************************************************/ + +static const char rcsid[] = "@(#)$Id$"; + + +/************************************************************************* + * Include files + */ +#include "triodef.h" +#include "trionan.h" + +#include +#include +#include +#include +#if defined(TRIO_PLATFORM_UNIX) +# include +#endif +#include + +#ifndef __STDC__ +# define volatile +# define const +#endif + +/************************************************************************* + * Definitions + */ + +/* We must enable IEEE floating-point on Alpha */ +#if defined(__alpha) && !defined(_IEEE_FP) +# if defined(TRIO_COMPILER_DECC) +# error "Must be compiled with option -ieee" +# elif defined(TRIO_COMPILER_GCC) && (defined(__osf__) || defined(__linux__)) +# error "Must be compiled with option -mieee" +# endif +#endif /* __alpha && ! _IEEE_FP */ + +/* + * In ANSI/IEEE 754-1985 64-bits double format numbers have the + * following properties (amoungst others) + * + * o FLT_RADIX == 2: binary encoding + * o DBL_MAX_EXP == 1024: 11 bits exponent, where one bit is used + * to indicate special numbers (e.g. NaN and Infinity), so the + * maximum exponent is 10 bits wide (2^10 == 1024). + * o DBL_MANT_DIG == 53: The mantissa is 52 bits wide, but because + * numbers are normalized the initial binary 1 is represented + * implictly (the so-called "hidden bit"), which leaves us with + * the ability to represent 53 bits wide mantissa. + */ +#if (FLT_RADIX == 2) && (DBL_MAX_EXP == 1024) && (DBL_MANT_DIG == 53) +# define USE_IEEE_754 +#endif + + +/************************************************************************* + * Data + */ + +#if defined(USE_IEEE_754) + +/* + * Endian-agnostic indexing macro. + * + * The value of internalEndianMagic, when converted into a 64-bit + * integer, becomes 0x0001020304050607 (we could have used a 64-bit + * integer value instead of a double, but not all platforms supports + * that type). The value is automatically encoded with the correct + * endianess by the compiler, which means that we can support any + * kind of endianess. The individual bytes are then used as an index + * for the IEEE 754 bit-patterns and masks. + */ +#define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[(x)]) + +static const double internalEndianMagic = 1.4015997730788920e-309; + +/* Mask for the exponent */ +static const unsigned char ieee_754_exponent_mask[] = { + 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Mask for the mantissa */ +static const unsigned char ieee_754_mantissa_mask[] = { + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* Bit-pattern for infinity */ +static const unsigned char ieee_754_infinity_array[] = { + 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Bit-pattern for quiet NaN */ +static const unsigned char ieee_754_qnan_array[] = { + 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +/************************************************************************* + * trio_make_double + */ +static double +trio_make_double(const unsigned char *values) +{ + volatile double result; + int i; + + for (i = 0; i < (int)sizeof(double); i++) { + ((volatile unsigned char *)&result)[TRIO_DOUBLE_INDEX(i)] = values[i]; + } + return result; +} + +/************************************************************************* + * trio_examine_double + */ +static int +trio_is_special_quantity(double number, + int *has_mantissa) +{ + unsigned int i; + unsigned char current; + int is_special_quantity = (1 == 1); + + *has_mantissa = 0; + + for (i = 0; i < (unsigned int)sizeof(double); i++) { + current = ((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)]; + is_special_quantity + &= ((current & ieee_754_exponent_mask[i]) == ieee_754_exponent_mask[i]); + *has_mantissa |= (current & ieee_754_mantissa_mask[i]); + } + return is_special_quantity; +} + +#endif /* USE_IEEE_754 */ + + +/************************************************************************* + * trio_pinf + */ +double +trio_pinf(void) +{ + /* Cache the result */ + static double result = 0.0; + + if (result == 0.0) { + +#if defined(INFINITY) && defined(__STDC_IEC_559__) + result = (double)INFINITY; + +#elif defined(USE_IEEE_754) + result = trio_make_double(ieee_754_infinity_array); + +#else + /* + * If HUGE_VAL is different from DBL_MAX, then HUGE_VAL is used + * as infinity. Otherwise we have to resort to an overflow + * operation to generate infinity. + */ +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + result = HUGE_VAL; + if (HUGE_VAL == DBL_MAX) { + /* Force overflow */ + result += HUGE_VAL; + } + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + +#endif + } + return result; +} + +/************************************************************************* + * trio_ninf + */ +double +trio_ninf(void) +{ + static double result = 0.0; + + if (result == 0.0) { + /* + * Negative infinity is calculated by negating positive infinity, + * which can be done because it is legal to do calculations on + * infinity (for example, 1 / infinity == 0). + */ + result = -trio_pinf(); + } + return result; +} + +/************************************************************************* + * trio_nan + */ +double +trio_nan(void) +{ + /* Cache the result */ + static double result = 0.0; + + if (result == 0.0) { + +#if defined(TRIO_COMPILER_SUPPORTS_C99) + result = nan(NULL); + +#elif defined(NAN) && defined(__STDC_IEC_559__) + result = (double)NAN; + +#elif defined(USE_IEEE_754) + result = trio_make_double(ieee_754_qnan_array); + +#else + /* + * There are several ways to generate NaN. The one used here is + * to divide infinity by infinity. I would have preferred to add + * negative infinity to positive infinity, but that yields wrong + * result (infinity) on FreeBSD. + * + * This may fail if the hardware does not support NaN, or if + * the Invalid Operation floating-point exception is unmasked. + */ +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + result = trio_pinf() / trio_pinf(); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + +#endif + } + return result; +} + +/************************************************************************* + * trio_isnan + */ +int +trio_isnan(volatile double number) +{ +#if defined(isnan) || defined(TRIO_COMPILER_SUPPORTS_UNIX95) + /* + * C99 defines isnan() as a macro. UNIX95 defines isnan() as a + * function. This function was already present in XPG4, but this + * is a bit tricky to detect with compiler defines, so we choose + * the conservative approach and only use it for UNIX95. + */ + return isnan(number); + +#elif defined(TRIO_COMPILER_MSVC) + /* + * MSC has an _isnan() function + */ + return _isnan(number); + +#elif defined(USE_IEEE_754) + /* + * Examine IEEE 754 bit-pattern. A NaN must have a special exponent + * pattern, and a non-empty mantissa. + */ + int has_mantissa; + int is_special_quantity; + + is_special_quantity = trio_is_special_quantity(number, &has_mantissa); + + return (is_special_quantity && has_mantissa); + +#else + /* + * Fallback solution + */ + int status; + double integral, fraction; + +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + status = (/* + * 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))); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + return status; + +#endif +} + +/************************************************************************* + * trio_isinf + */ +int +trio_isinf(volatile double number) +{ +#if defined(TRIO_COMPILER_DECC) + /* + * DECC has an isinf() macro, but it works differently than that + * of C99, so we use the fp_class() function instead. + */ + return ((fp_class(number) == FP_POS_INF) + ? 1 + : ((fp_class(number) == FP_NEG_INF) ? -1 : 0)); + +#elif defined(isinf) + /* + * C99 defines isinf() as a macro. + */ + return isinf(number); + +#elif defined(TRIO_COMPILER_MSVC) + /* + * MSVC has an _fpclass() function that can be used to detect infinity. + */ + return ((_fpclass(number) == _FPCLASS_PINF) + ? 1 + : ((_fpclass(number) == _FPCLASS_NINF) ? -1 : 0)); + +#elif defined(USE_IEEE_754) + /* + * Examine IEEE 754 bit-pattern. Infinity must have a special exponent + * pattern, and an empty mantissa. + */ + int has_mantissa; + int is_special_quantity; + + is_special_quantity = trio_is_special_quantity(number, &has_mantissa); + + return (is_special_quantity && !has_mantissa) + ? ((number < 0.0) ? -1 : 1) + : 0; + +#else + /* + * Fallback solution. + */ + int status; + +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + double infinity = trio_pinf(); + + status = ((number == infinity) + ? 1 + : ((number == -infinity) ? -1 : 0)); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + return status; + +#endif +} + +/************************************************************************* + */ +#if defined(STANDALONE) +# include + +int main(void) +{ + double my_nan; + double my_pinf; + double my_ninf; +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int); +# endif + + my_nan = trio_nan(); + my_pinf = trio_pinf(); + my_ninf = trio_ninf(); + + printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_nan, + ((unsigned char *)&my_nan)[0], + ((unsigned char *)&my_nan)[1], + ((unsigned char *)&my_nan)[2], + ((unsigned char *)&my_nan)[3], + ((unsigned char *)&my_nan)[4], + ((unsigned char *)&my_nan)[5], + ((unsigned char *)&my_nan)[6], + ((unsigned char *)&my_nan)[7], + trio_isnan(my_nan), trio_isinf(my_nan)); + printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_pinf, + ((unsigned char *)&my_pinf)[0], + ((unsigned char *)&my_pinf)[1], + ((unsigned char *)&my_pinf)[2], + ((unsigned char *)&my_pinf)[3], + ((unsigned char *)&my_pinf)[4], + ((unsigned char *)&my_pinf)[5], + ((unsigned char *)&my_pinf)[6], + ((unsigned char *)&my_pinf)[7], + trio_isnan(my_pinf), trio_isinf(my_pinf)); + printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_ninf, + ((unsigned char *)&my_ninf)[0], + ((unsigned char *)&my_ninf)[1], + ((unsigned char *)&my_ninf)[2], + ((unsigned char *)&my_ninf)[3], + ((unsigned char *)&my_ninf)[4], + ((unsigned char *)&my_ninf)[5], + ((unsigned char *)&my_ninf)[6], + ((unsigned char *)&my_ninf)[7], + trio_isnan(my_ninf), trio_isinf(my_ninf)); + +# if defined(TRIO_PLATFORM_UNIX) + signal_handler = signal(SIGFPE, SIG_IGN); +# endif + + my_pinf = DBL_MAX + DBL_MAX; + my_ninf = -my_pinf; + my_nan = my_pinf / my_pinf; + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_nan, + ((unsigned char *)&my_nan)[0], + ((unsigned char *)&my_nan)[1], + ((unsigned char *)&my_nan)[2], + ((unsigned char *)&my_nan)[3], + ((unsigned char *)&my_nan)[4], + ((unsigned char *)&my_nan)[5], + ((unsigned char *)&my_nan)[6], + ((unsigned char *)&my_nan)[7], + trio_isnan(my_nan), trio_isinf(my_nan)); + printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_pinf, + ((unsigned char *)&my_pinf)[0], + ((unsigned char *)&my_pinf)[1], + ((unsigned char *)&my_pinf)[2], + ((unsigned char *)&my_pinf)[3], + ((unsigned char *)&my_pinf)[4], + ((unsigned char *)&my_pinf)[5], + ((unsigned char *)&my_pinf)[6], + ((unsigned char *)&my_pinf)[7], + trio_isnan(my_pinf), trio_isinf(my_pinf)); + printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_ninf, + ((unsigned char *)&my_ninf)[0], + ((unsigned char *)&my_ninf)[1], + ((unsigned char *)&my_ninf)[2], + ((unsigned char *)&my_ninf)[3], + ((unsigned char *)&my_ninf)[4], + ((unsigned char *)&my_ninf)[5], + ((unsigned char *)&my_ninf)[6], + ((unsigned char *)&my_ninf)[7], + trio_isnan(my_ninf), trio_isinf(my_ninf)); + + return 0; +} +#endif diff --git a/xmlcatalog.c b/xmlcatalog.c index 0063bcab..1a65450b 100644 --- a/xmlcatalog.c +++ b/xmlcatalog.c @@ -12,6 +12,13 @@ #include #include +#ifdef HAVE_LIBREADLINE +#include +#ifdef HAVE_LIBHISTORY +#include +#endif +#endif + #include #include #include diff --git a/xpath.c b/xpath.c index 2228ff57..984752ac 100644 --- a/xpath.c +++ b/xpath.c @@ -30,12 +30,6 @@ #ifdef HAVE_FLOAT_H #include #endif -#ifdef HAVE_IEEEFP_H -#include -#endif -#ifdef HAVE_NAN_H -#include -#endif #ifdef HAVE_CTYPE_H #include #endif @@ -57,6 +51,7 @@ #include #endif #include +#include /* #define DEBUG */ /* #define DEBUG_STEP */ @@ -81,108 +76,6 @@ double xmlXPathNAN = 0; double xmlXPathPINF = 1; double xmlXPathNINF = -1; -#ifndef isinf -#ifndef HAVE_ISINF - -#if HAVE_FPCLASS - -int isinf(double d) { - fpclass_t type = fpclass(d); - switch (type) { - case FP_NINF: - return(-1); - case FP_PINF: - return(1); - } - return(0); -} - -#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D) - -#if HAVE_FP_CLASS_H -#include -#endif - -int isinf(double d) { -#if HAVE_FP_CLASS - int fpclass = fp_class(d); -#else - int fpclass = fp_class_d(d); -#endif - if (fpclass == FP_POS_INF) - return(1); - if (fpclass == FP_NEG_INF) - return(-1); - return(0); -} - -#elif defined(HAVE_CLASS) - -int isinf(double d) { - int fpclass = class(d); - if (fpclass == FP_PLUS_INF) - return(1); - if (fpclass == FP_MINUS_INF) - return(-1); - return(0); -} -#elif defined(finite) || defined(HAVE_FINITE) -int isinf(double x) { return !finite(x) && x==x; } -#elif defined(HUGE_VAL) -int isinf(double x) -{ - if (x == HUGE_VAL) - return(1); - if (x == -HUGE_VAL) - return(-1); - return(0); -} -#endif - -#endif /* ! HAVE_ISINF */ -#endif /* ! defined(isinf) */ - -#ifndef isnan -#ifndef HAVE_ISNAN - -#ifdef HAVE_ISNAND -#define isnan(f) isnand(f) -#endif /* HAVE_iSNAND */ - -#endif /* ! HAVE_iSNAN */ -#endif /* ! defined(isnan) */ - - -/** - * xmlXPathDivideBy: - * - * The best way found so far to generate the NAN, +-INF - * without hitting a compiler bug or optimization :-\ - * - * Returns the double resulting from the division - */ -double -xmlXPathDivideBy(double f, double fzero) { - double ret; -#ifdef HAVE_SIGNAL -#ifdef SIGFPE -#ifdef SIG_IGN - void (*sighandler)(int); - sighandler = signal(SIGFPE, SIG_IGN); -#endif -#endif -#endif - ret = f / fzero; -#ifdef HAVE_SIGNAL -#ifdef SIGFPE -#ifdef SIG_IGN - signal(SIGFPE, sighandler); -#endif -#endif -#endif - return(ret); -} - /** * xmlXPathInit: * @@ -194,16 +87,9 @@ xmlXPathInit(void) { if (initialized) return; -#if defined(HUGE_VAL) && defined(DBL_MAX) - xmlXPathPINF = (HUGE_VAL == DBL_MAX) ? - xmlXPathDivideBy(1.0, 0.0) : HUGE_VAL; - xmlXPathNINF = -xmlXPathPINF; - xmlXPathNAN = xmlXPathDivideBy(xmlXPathPINF, xmlXPathPINF); -#else - xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0); - xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0); - xmlXPathNINF = xmlXPathDivideBy(-1.0, 0.0); -#endif + xmlXPathPINF = trio_pinf(); + xmlXPathNINF = trio_ninf(); + xmlXPathNAN = trio_nan(); initialized = 1; } @@ -640,7 +526,7 @@ xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { else fprintf(output, "false\n"); break; case XPATH_NUMBER: - switch (isinf(cur->floatval)) { + switch (trio_isinf(cur->floatval)) { case 1: fprintf(output, "Object is a number : +Infinity\n"); break; @@ -648,7 +534,7 @@ xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { fprintf(output, "Object is a number : -Infinity\n"); break; default: - if (isnan(cur->floatval)) { + if (trio_isnan(cur->floatval)) { fprintf(output, "Object is a number : NaN\n"); } else { fprintf(output, "Object is a number : %0g\n", cur->floatval); @@ -1169,7 +1055,7 @@ xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { static void xmlXPathFormatNumber(double number, char buffer[], int buffersize) { - switch (isinf(number)) { + switch (trio_isinf(number)) { case 1: if (buffersize > (int)sizeof("+Infinity")) sprintf(buffer, "+Infinity"); @@ -1179,7 +1065,7 @@ xmlXPathFormatNumber(double number, char buffer[], int buffersize) sprintf(buffer, "-Infinity"); break; default: - if (isnan(number)) { + if (trio_isnan(number)) { if (buffersize > (int)sizeof("NaN")) sprintf(buffer, "NaN"); } else { @@ -2927,7 +2813,7 @@ xmlXPathCastBooleanToString (int val) { xmlChar * xmlXPathCastNumberToString (double val) { xmlChar *ret; - switch (isinf(val)) { + switch (trio_isinf(val)) { case 1: ret = xmlStrdup((const xmlChar *) "+Infinity"); break; @@ -2935,7 +2821,7 @@ xmlXPathCastNumberToString (double val) { ret = xmlStrdup((const xmlChar *) "-Infinity"); break; default: - if (isnan(val)) { + if (trio_isnan(val)) { ret = xmlStrdup((const xmlChar *) "NaN"); } else { /* could be improved */ @@ -3221,7 +3107,7 @@ xmlXPathConvertNumber(xmlXPathObjectPtr val) { */ int xmlXPathCastNumberToBoolean (double val) { - if (isnan(val) || (val == 0.0)) + if (trio_isnan(val) || (val == 0.0)) return(0); return(1); } @@ -3828,13 +3714,13 @@ xmlXPathCompareNodeSets(int inf, int strict, } for (i = 0;i < ns1->nodeNr;i++) { val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); - if (isnan(val1)) + if (trio_isnan(val1)) continue; for (j = 0;j < ns2->nodeNr;j++) { if (init == 0) { values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); } - if (isnan(values2[j])) + if (trio_isnan(values2[j])) continue; if (inf && strict) ret = (val1 < values2[j]); @@ -6291,9 +6177,9 @@ xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); - if ((ctxt->value->floatval == xmlXPathNAN) || - (ctxt->value->floatval == xmlXPathPINF) || - (ctxt->value->floatval == xmlXPathNINF) || + if ((trio_isnan(ctxt->value->floatval)) || + (trio_isinf(ctxt->value->floatval) == 1) || + (trio_isinf(ctxt->value->floatval) == -1) || (ctxt->value->floatval == 0.0)) return;