code:
/*************************************************************************
 *
 * $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.
 *
 *************************************************************************
 *
 * http://ctrio.sourceforge.net/
 *
 ************************************************************************/

#ifndef TRIO_TRIO_H
#define TRIO_TRIO_H

#if !defined(WITHOUT_TRIO)

/*
 * Use autoconf defines if present. Packages using trio must define
 * HAVE_CONFIG_H as a compiler option themselves.
 */
#if defined(HAVE_CONFIG_H)
# include "config.h"
#endif

#include "triodef.h"

#include <stdio.h>
#include <stdlib.h>
#if defined(TRIO_COMPILER_ANCIENT)
# include <varargs.h>
#else
# include <stdarg.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Error codes.
 *
 * Remember to add a textual description to trio_strerror.
 */
enum {
  TRIO_EOF      = 1,
  TRIO_EINVAL   = 2,
  TRIO_ETOOMANY = 3,
  TRIO_EDBLREF  = 4,
  TRIO_EGAP     = 5,
  TRIO_ENOMEM   = 6,
  TRIO_ERANGE   = 7,
  TRIO_ERRNO    = 8,
  TRIO_ECUSTOM  = 9
};

/* Error macros */
#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF)
#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8)
#define TRIO_ERROR_NAME(x) trio_strerror(x)

typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int));
typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t));

TRIO_CONST char *trio_strerror TRIO_PROTO((int));

/*************************************************************************
 * Print Functions
 */

int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...));
int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args));

int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));

int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));

int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
			     TRIO_CONST char *format, ...));
int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
			      TRIO_CONST char *format, va_list args));
int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
			      TRIO_CONST char *format, void **args));

int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...));
int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args));
int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args));

int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
		   va_list args));
int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
		   void **args));

int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
                      va_list args));

char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...));
char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));

int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...));
int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args));

/*************************************************************************
 * Scan Functions
 */
int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...));
int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args));
int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args));

int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));

int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));

int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
			    TRIO_CONST char *format, ...));
int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
			     TRIO_CONST char *format, va_list args));
int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
			     TRIO_CONST char *format, void **args));

int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...));
int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args));
int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args));

/*************************************************************************
 * Locale Functions
 */
void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint));
void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator));
void trio_locale_set_grouping TRIO_PROTO((char *grouping));

/*************************************************************************
 * Renaming
 */
#ifdef TRIO_REPLACE_STDIO
/* Replace the <stdio.h> functions */
#ifndef HAVE_PRINTF
# define printf trio_printf
#endif
#ifndef HAVE_VPRINTF
# define vprintf trio_vprintf
#endif
#ifndef HAVE_FPRINTF
# define fprintf trio_fprintf
#endif
#ifndef HAVE_VFPRINTF
# define vfprintf trio_vfprintf
#endif
#ifndef HAVE_SPRINTF
# define sprintf trio_sprintf
#endif
#ifndef HAVE_VSPRINTF
# define vsprintf trio_vsprintf
#endif
#ifndef HAVE_SNPRINTF
# define snprintf trio_snprintf
#endif
#ifndef HAVE_VSNPRINTF
# define vsnprintf trio_vsnprintf
#endif
#ifndef HAVE_SCANF
# define scanf trio_scanf
#endif
#ifndef HAVE_VSCANF
# define vscanf trio_vscanf
#endif
#ifndef HAVE_FSCANF
# define fscanf trio_fscanf
#endif
#ifndef HAVE_VFSCANF
# define vfscanf trio_vfscanf
#endif
#ifndef HAVE_SSCANF
# define sscanf trio_sscanf
#endif
#ifndef HAVE_VSSCANF
# define vsscanf trio_vsscanf
#endif
/* These aren't stdio functions, but we make them look similar */
#define dprintf trio_dprintf
#define vdprintf trio_vdprintf
#define aprintf trio_aprintf
#define vaprintf trio_vaprintf
#define asprintf trio_asprintf
#define vasprintf trio_vasprintf
#define dscanf trio_dscanf
#define vdscanf trio_vdscanf
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* WITHOUT_TRIO */

#endif /* TRIO_TRIO_H */


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
 *
 * 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(__osf__) && defined(__LANGUAGE_C__)
# define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */
#elif defined(_MSC_VER)
# define TRIO_COMPILER_MSVC
#elif defined(__BORLANDC__)
# define TRIO_COMPILER_BCB
#endif

#if defined(VMS) || defined(__VMS)
/*
 * VMS is placed first to avoid identifying the platform as Unix
 * based on the DECC compiler later on.
 */
# define TRIO_PLATFORM_VMS
#elif 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(__Lynx__)
# define TRIO_PLATFORM_UNIX
#elif defined(__QNX__)
# define TRIO_PLATFORM_UNIX
# define TRIO_PLATFORM_QNX
#elif defined(__CYGWIN__)
# 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
#elif defined(mpeix) || defined(__mpexl)
# define TRIO_PLATFORM_MPEIX
#endif

#if defined(_AIX)
# define TRIO_PLATFORM_AIX
#elif defined(__hpux)
# define TRIO_PLATFORM_HPUX
#elif defined(sun) || defined(__sun__)
# if defined(__SVR4) || defined(__svr4__)
#  define TRIO_PLATFORM_SOLARIS
# else
#  define TRIO_PLATFORM_SUNOS
# endif
#endif

#if defined(__STDC__) || defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
# define TRIO_COMPILER_SUPPORTS_C89
# if defined(__STDC_VERSION__)
#  define TRIO_COMPILER_SUPPORTS_C90
#  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
# if (_XOPEN_VERSION >= 600)
#  define TRIO_COMPILER_SUPPORTS_UNIX01
# endif
#endif

/*************************************************************************
 * Generic defines
 */

#if !defined(TRIO_PUBLIC)
# define TRIO_PUBLIC
#endif
#if !defined(TRIO_PRIVATE)
# define TRIO_PRIVATE static
#endif

#if !(defined(TRIO_COMPILER_SUPPORTS_C89) || defined(__cplusplus))
# define TRIO_COMPILER_ANCIENT
#endif

#if defined(TRIO_COMPILER_ANCIENT)
# define TRIO_CONST
# define TRIO_VOLATILE
# define TRIO_SIGNED
typedef double trio_long_double_t;
typedef char * trio_pointer_t;
# define TRIO_SUFFIX_LONG(x) x
# define TRIO_PROTO(x) ()
# define TRIO_NOARGS
# define TRIO_ARGS1(list,a1) list a1;
# define TRIO_ARGS2(list,a1,a2) list a1; a2;
# define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3;
# define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4;
# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5;
# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6;
# define TRIO_VARGS2(list,a1,a2) list a1; a2
# define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3
# define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4
# define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5
# define TRIO_VA_DECL va_dcl
# define TRIO_VA_START(x,y) va_start(x)
# define TRIO_VA_END(x) va_end(x)
#else /* ANSI C */
# define TRIO_CONST const
# define TRIO_VOLATILE volatile
# define TRIO_SIGNED signed
typedef long double trio_long_double_t;
typedef void * trio_pointer_t;
# define TRIO_SUFFIX_LONG(x) x ## L
# define TRIO_PROTO(x) x
# define TRIO_NOARGS void
# define TRIO_ARGS1(list,a1) (a1)
# define TRIO_ARGS2(list,a1,a2) (a1,a2)
# define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3)
# define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4)
# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5)
# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6)
# define TRIO_VARGS2 TRIO_ARGS2
# define TRIO_VARGS3 TRIO_ARGS3
# define TRIO_VARGS4 TRIO_ARGS4
# define TRIO_VARGS5 TRIO_ARGS5
# define TRIO_VA_DECL ...
# define TRIO_VA_START(x,y) va_start(x,y)
# define TRIO_VA_END(x) va_end(x)
#endif

#if defined(TRIO_COMPILER_SUPPORTS_C99) || defined(__cplusplus)
# define TRIO_INLINE inline
#elif defined(TRIO_COMPILER_GCC)
# define TRIO_INLINE __inline__
#elif defined(TRIO_COMPILER_MSVC)
# define TRIO_INLINE _inline
#elif defined(TRIO_COMPILER_BCB)
# define TRIO_INLINE __inline
#else
# define TRIO_INLINE
#endif

/*************************************************************************
 * Workarounds
 */

#if defined(TRIO_PLATFORM_VMS)
/*
 * Computations done with constants at compile time can trigger these
 * even when compiling with IEEE enabled.
 */
# pragma message disable (UNDERFLOW, FLOATOVERFL)

# if (__CRTL_VER < 80000000)
/*
 * Although the compiler supports C99 language constructs, the C
 * run-time library does not contain all C99 functions.
 *
 * This was the case for 70300022. Update the 80000000 value when
 * it has been accurately determined what version of the library
 * supports C99.
 */
#  if defined(TRIO_COMPILER_SUPPORTS_C99)
#   undef TRIO_COMPILER_SUPPORTS_C99
#  endif
# endif
#endif

/*
 * Not all preprocessors supports the LL token.
 */
#if defined(TRIO_COMPILER_BCB)
#else
# define TRIO_COMPILER_SUPPORTS_LL
#endif

#endif /* TRIO_TRIODEF_H */

license: mit


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
 *
 * 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.
 *
 ************************************************************************/

/*
 * TODO:
 *  o Put all the magic into trio_fpclassify_and_signbit(), and use this from
 *    trio_isnan() etc.
 */

/*************************************************************************
 * Include files
 */
#include "triodef.h"
#include "trionan.h"

#include <math.h>
#include <string.h>
#include <limits.h>
#include <float.h>
#if defined(TRIO_PLATFORM_UNIX)
# include <signal.h>
#endif
#if defined(TRIO_COMPILER_DECC)
#  if defined(__linux__)
#   include <cpml.h>
#  else
#   include <fp_class.h>
#  endif
#endif
#include <assert.h>

#if defined(TRIO_DOCUMENTATION)
# include "doc/doc_nan.h"
#endif
/** @addtogroup SpecialQuantities
    @{
*/

/*************************************************************************
 * Definitions
 */

#define TRIO_TRUE (1 == 1)
#define TRIO_FALSE (0 == 1)

/*
 * We must enable IEEE floating-point on Alpha
 */
#if defined(__alpha) && !defined(_IEEE_FP)
# if defined(TRIO_COMPILER_DECC)
#  if defined(TRIO_PLATFORM_VMS)
#   error "Must be compiled with option /IEEE_MODE=UNDERFLOW_TO_ZERO/FLOAT=IEEE"
#  else
#   if !defined(_CFE)
#    error "Must be compiled with option -ieee"
#   endif
#  endif
# 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
 *     implicitly (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

/*************************************************************************
 * Constants
 */

static TRIO_CONST char rcsid[] = "@(#)$Id$";

#if defined(USE_IEEE_754)

/*
 * Endian-agnostic indexing macro.
 *
 * The value of internalEndianMagic, when converted into a 64-bit
 * integer, becomes 0x0706050403020100 (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)[7-(x)])

#if (defined(__BORLANDC__) && __BORLANDC__ >= 0x0590)
static TRIO_CONST double internalEndianMagic = 7.949928895127362e-275;
#else
static TRIO_CONST double internalEndianMagic = 7.949928895127363e-275;
#endif

/* Mask for the exponent */
static TRIO_CONST unsigned char ieee_754_exponent_mask[] = {
  0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* Mask for the mantissa */
static TRIO_CONST unsigned char ieee_754_mantissa_mask[] = {
  0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

/* Mask for the sign bit */
static TRIO_CONST unsigned char ieee_754_sign_mask[] = {
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* Bit-pattern for negative zero */
static TRIO_CONST unsigned char ieee_754_negzero_array[] = {
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* Bit-pattern for infinity */
static TRIO_CONST unsigned char ieee_754_infinity_array[] = {
  0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* Bit-pattern for quiet NaN */
static TRIO_CONST unsigned char ieee_754_qnan_array[] = {
  0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/*************************************************************************
 * Functions
 */

/*
 * trio_make_double
 */
TRIO_PRIVATE double
trio_make_double
TRIO_ARGS1((values),
	   TRIO_CONST unsigned char *values)
{
  TRIO_VOLATILE double result;
  int i;

  for (i = 0; i < (int)sizeof(double); i++) {
    ((TRIO_VOLATILE unsigned char *)&result)[TRIO_DOUBLE_INDEX(i)] = values[i];
  }
  return result;
}

/*
 * trio_is_special_quantity
 */
TRIO_PRIVATE int
trio_is_special_quantity
TRIO_ARGS2((number, has_mantissa),
	   double number,
	   int *has_mantissa)
{
  unsigned int i;
  unsigned char current;
  int is_special_quantity = TRIO_TRUE;

  *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;
}

/*
 * trio_is_negative
 */
TRIO_PRIVATE int
trio_is_negative
TRIO_ARGS1((number),
	   double number)
{
  unsigned int i;
  int is_negative = TRIO_FALSE;

  for (i = 0; i < (unsigned int)sizeof(double); i++) {
    is_negative |= (((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)]
		    & ieee_754_sign_mask[i]);
  }
  return is_negative;
}

#endif /* USE_IEEE_754 */

/**
   Generate negative zero.

   @return Floating-point representation of negative zero.
*/
TRIO_PUBLIC double
trio_nzero(TRIO_NOARGS)
{
#if defined(USE_IEEE_754)
  return trio_make_double(ieee_754_negzero_array);
#else
  TRIO_VOLATILE double zero = 0.0;

  return -zero;
#endif
}

/**
   Generate positive infinity.

   @return Floating-point representation of positive infinity.
*/
TRIO_PUBLIC double
trio_pinf(TRIO_NOARGS)
{
  /* 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;
}

/**
   Generate negative infinity.

   @return Floating-point value of negative infinity.
*/
TRIO_PUBLIC double
trio_ninf(TRIO_NOARGS)
{
  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;
}

/**
   Generate NaN.

   @return Floating-point representation of NaN.
*/
TRIO_PUBLIC double
trio_nan(TRIO_NOARGS)
{
  /* Cache the result */
  static double result = 0.0;

  if (result == 0.0) {

#if defined(TRIO_COMPILER_SUPPORTS_C99)
    result = nan("");

#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;
}

/**
   Check for NaN.

   @param number An arbitrary floating-point number.
   @return Boolean value indicating whether or not the number is a NaN.
*/
TRIO_PUBLIC int
trio_isnan
TRIO_ARGS1((number),
	   double number)
{
#if (defined(TRIO_COMPILER_SUPPORTS_C99) && 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) || defined(TRIO_COMPILER_BCB)
  /*
   * Microsoft Visual C++ and Borland C++ Builder have an _isnan()
   * function.
   */
  return _isnan(number) ? TRIO_TRUE : TRIO_FALSE;

#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
	     */
	    ((TRIO_VOLATILE double)number != (TRIO_VOLATILE double)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
}

/**
   Check for infinity.

   @param number An arbitrary floating-point number.
   @return 1 if positive infinity, -1 if negative infinity, 0 otherwise.
*/
TRIO_PUBLIC int
trio_isinf
TRIO_ARGS1((number),
	   double number)
{
#if defined(TRIO_COMPILER_DECC) && !defined(__linux__)
  /*
   * 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)
    ? ((number > 0.0) ? 1 : -1)
    : 0;

#elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
  /*
   * Microsoft Visual C++ and Borland C++ Builder have 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 0
	/* Temporary fix - this routine is not used anywhere */
/**
   Check for finity.

   @param number An arbitrary floating-point number.
   @return Boolean value indicating whether or not the number is a finite.
*/
TRIO_PUBLIC int
trio_isfinite
TRIO_ARGS1((number),
	   double number)
{
#if defined(TRIO_COMPILER_SUPPORTS_C99) && defined(isfinite)
  /*
   * C99 defines isfinite() as a macro.
   */
  return isfinite(number);

#elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
  /*
   * Microsoft Visual C++ and Borland C++ Builder use _finite().
   */
  return _finite(number);

#elif defined(USE_IEEE_754)
  /*
   * Examine IEEE 754 bit-pattern. For finity we do not care about the
   * mantissa.
   */
  int dummy;

  return (! trio_is_special_quantity(number, &dummy));

#else
  /*
   * Fallback solution.
   */
  return ((trio_isinf(number) == 0) && (trio_isnan(number) == 0));

#endif
}

#endif

/*
 * The sign of NaN is always false
 */
TRIO_PUBLIC int
trio_fpclassify_and_signbit
TRIO_ARGS2((number, is_negative),
	   double number,
	   int *is_negative)
{
#if defined(fpclassify) && defined(signbit)
  /*
   * C99 defines fpclassify() and signbit() as a macros
   */
  *is_negative = signbit(number);
  switch (fpclassify(number)) {
  case FP_NAN:
    return TRIO_FP_NAN;
  case FP_INFINITE:
    return TRIO_FP_INFINITE;
  case FP_SUBNORMAL:
    return TRIO_FP_SUBNORMAL;
  case FP_ZERO:
    return TRIO_FP_ZERO;
  default:
    return TRIO_FP_NORMAL;
  }

#else
# if defined(TRIO_COMPILER_DECC)
  /*
   * DECC has an fp_class() function.
   */
#  define TRIO_FPCLASSIFY(n) fp_class(n)
#  define TRIO_QUIET_NAN FP_QNAN
#  define TRIO_SIGNALLING_NAN FP_SNAN
#  define TRIO_POSITIVE_INFINITY FP_POS_INF
#  define TRIO_NEGATIVE_INFINITY FP_NEG_INF
#  define TRIO_POSITIVE_SUBNORMAL FP_POS_DENORM
#  define TRIO_NEGATIVE_SUBNORMAL FP_NEG_DENORM
#  define TRIO_POSITIVE_ZERO FP_POS_ZERO
#  define TRIO_NEGATIVE_ZERO FP_NEG_ZERO
#  define TRIO_POSITIVE_NORMAL FP_POS_NORM
#  define TRIO_NEGATIVE_NORMAL FP_NEG_NORM

# elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
  /*
   * Microsoft Visual C++ and Borland C++ Builder have an _fpclass()
   * function.
   */
#  define TRIO_FPCLASSIFY(n) _fpclass(n)
#  define TRIO_QUIET_NAN _FPCLASS_QNAN
#  define TRIO_SIGNALLING_NAN _FPCLASS_SNAN
#  define TRIO_POSITIVE_INFINITY _FPCLASS_PINF
#  define TRIO_NEGATIVE_INFINITY _FPCLASS_NINF
#  define TRIO_POSITIVE_SUBNORMAL _FPCLASS_PD
#  define TRIO_NEGATIVE_SUBNORMAL _FPCLASS_ND
#  define TRIO_POSITIVE_ZERO _FPCLASS_PZ
#  define TRIO_NEGATIVE_ZERO _FPCLASS_NZ
#  define TRIO_POSITIVE_NORMAL _FPCLASS_PN
#  define TRIO_NEGATIVE_NORMAL _FPCLASS_NN

# elif defined(FP_PLUS_NORM)
  /*
   * HP-UX 9.x and 10.x have an fpclassify() function, that is different
   * from the C99 fpclassify() macro supported on HP-UX 11.x.
   *
   * AIX has class() for C, and _class() for C++, which returns the
   * same values as the HP-UX fpclassify() function.
   */
#  if defined(TRIO_PLATFORM_AIX)
#   if defined(__cplusplus)
#    define TRIO_FPCLASSIFY(n) _class(n)
#   else
#    define TRIO_FPCLASSIFY(n) class(n)
#   endif
#  else
#   define TRIO_FPCLASSIFY(n) fpclassify(n)
#  endif
#  define TRIO_QUIET_NAN FP_QNAN
#  define TRIO_SIGNALLING_NAN FP_SNAN
#  define TRIO_POSITIVE_INFINITY FP_PLUS_INF
#  define TRIO_NEGATIVE_INFINITY FP_MINUS_INF
#  define TRIO_POSITIVE_SUBNORMAL FP_PLUS_DENORM
#  define TRIO_NEGATIVE_SUBNORMAL FP_MINUS_DENORM
#  define TRIO_POSITIVE_ZERO FP_PLUS_ZERO
#  define TRIO_NEGATIVE_ZERO FP_MINUS_ZERO
#  define TRIO_POSITIVE_NORMAL FP_PLUS_NORM
#  define TRIO_NEGATIVE_NORMAL FP_MINUS_NORM
# endif

# if defined(TRIO_FPCLASSIFY) && !defined(TRIO_FPCLASSIFY_HACK)
  switch (TRIO_FPCLASSIFY(number)) {
  case TRIO_QUIET_NAN:
  case TRIO_SIGNALLING_NAN:
    *is_negative = TRIO_FALSE; /* NaN has no sign */
    return TRIO_FP_NAN;
  case TRIO_POSITIVE_INFINITY:
    *is_negative = TRIO_FALSE;
    return TRIO_FP_INFINITE;
  case TRIO_NEGATIVE_INFINITY:
    *is_negative = TRIO_TRUE;
    return TRIO_FP_INFINITE;
  case TRIO_POSITIVE_SUBNORMAL:
    *is_negative = TRIO_FALSE;
    return TRIO_FP_SUBNORMAL;
  case TRIO_NEGATIVE_SUBNORMAL:
    *is_negative = TRIO_TRUE;
    return TRIO_FP_SUBNORMAL;
  case TRIO_POSITIVE_ZERO:
    *is_negative = TRIO_FALSE;
    return TRIO_FP_ZERO;
  case TRIO_NEGATIVE_ZERO:
    *is_negative = TRIO_TRUE;
    return TRIO_FP_ZERO;
  case TRIO_POSITIVE_NORMAL:
    *is_negative = TRIO_FALSE;
    return TRIO_FP_NORMAL;
  case TRIO_NEGATIVE_NORMAL:
    *is_negative = TRIO_TRUE;
    return TRIO_FP_NORMAL;
  default:
    /* Just in case... */
    *is_negative = (number < 0.0);
    return TRIO_FP_NORMAL;
  }

# else
  /*
   * Fallback solution.
   */
  int rc;

  if (number == 0.0) {
    /*
     * In IEEE 754 the sign of zero is ignored in comparisons, so we
     * have to handle this as a special case by examining the sign bit
     * directly.
     */
#  if defined(USE_IEEE_754)
    *is_negative = trio_is_negative(number);
#  else
    *is_negative = TRIO_FALSE; /* FIXME */
#  endif
    return TRIO_FP_ZERO;
  }
  if (trio_isnan(number)) {
    *is_negative = TRIO_FALSE;
    return TRIO_FP_NAN;
  }
  if ((rc = trio_isinf(number))) {
    *is_negative = (rc == -1);
    return TRIO_FP_INFINITE;
  }
  if ((number > 0.0) && (number < DBL_MIN)) {
    *is_negative = TRIO_FALSE;
    return TRIO_FP_SUBNORMAL;
  }
  if ((number < 0.0) && (number > -DBL_MIN)) {
    *is_negative = TRIO_TRUE;
    return TRIO_FP_SUBNORMAL;
  }
  *is_negative = (number < 0.0);
  return TRIO_FP_NORMAL;

# endif
#endif
}

/**
   Examine the sign of a number.

   @param number An arbitrary floating-point number.
   @return Boolean value indicating whether or not the number has the
   sign bit set (i.e. is negative).
*/
TRIO_PUBLIC int
trio_signbit
TRIO_ARGS1((number),
	   double number)
{
  int is_negative;

  (void)trio_fpclassify_and_signbit(number, &is_negative);
  return is_negative;
}

#if 0
	/* Temporary fix - this routine is not used in libxml */
/**
   Examine the class of a number.

   @param number An arbitrary floating-point number.
   @return Enumerable value indicating the class of @p number
*/
TRIO_PUBLIC int
trio_fpclassify
TRIO_ARGS1((number),
	   double number)
{
  int dummy;

  return trio_fpclassify_and_signbit(number, &dummy);
}

#endif

/** @} SpecialQuantities */

/*************************************************************************
 * For test purposes.
 *
 * Add the following compiler option to include this test code.
 *
 *  Unix : -DSTANDALONE
 *  VMS  : /DEFINE=(STANDALONE)
 */
#if defined(STANDALONE)
# include <stdio.h>

static TRIO_CONST char *
getClassification
TRIO_ARGS1((type),
	   int type)
{
  switch (type) {
  case TRIO_FP_INFINITE:
    return "FP_INFINITE";
  case TRIO_FP_NAN:
    return "FP_NAN";
  case TRIO_FP_NORMAL:
    return "FP_NORMAL";
  case TRIO_FP_SUBNORMAL:
    return "FP_SUBNORMAL";
  case TRIO_FP_ZERO:
    return "FP_ZERO";
  default:
    return "FP_UNKNOWN";
  }
}

static void
print_class
TRIO_ARGS2((prefix, number),
	   TRIO_CONST char *prefix,
	   double number)
{
  printf("%-6s: %s %-15s %g\n",
	 prefix,
	 trio_signbit(number) ? "-" : "+",
	 getClassification(TRIO_FPCLASSIFY(number)),
	 number);
}

int main(TRIO_NOARGS)
{
  double my_nan;
  double my_pinf;
  double my_ninf;
# if defined(TRIO_PLATFORM_UNIX)
  void (*signal_handler) TRIO_PROTO((int));
# endif

  my_nan = trio_nan();
  my_pinf = trio_pinf();
  my_ninf = trio_ninf();

  print_class("Nan", my_nan);
  print_class("PInf", my_pinf);
  print_class("NInf", my_ninf);
  print_class("PZero", 0.0);
  print_class("NZero", -0.0);
  print_class("PNorm", 1.0);
  print_class("NNorm", -1.0);
  print_class("PSub", 1.01e-307 - 1.00e-307);
  print_class("NSub", 1.00e-307 - 1.01e-307);

  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


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
 *
 * 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

#include "triodef.h"

#ifdef __cplusplus
extern "C" {
#endif

enum {
  TRIO_FP_INFINITE,
  TRIO_FP_NAN,
  TRIO_FP_NORMAL,
  TRIO_FP_SUBNORMAL,
  TRIO_FP_ZERO
};

/*
 * Return NaN (Not-a-Number).
 */
TRIO_PUBLIC double trio_nan TRIO_PROTO((void));

/*
 * Return positive infinity.
 */
TRIO_PUBLIC double trio_pinf TRIO_PROTO((void));

/*
 * Return negative infinity.
 */
TRIO_PUBLIC double trio_ninf TRIO_PROTO((void));

/*
 * Return negative zero.
 */
TRIO_PUBLIC double trio_nzero TRIO_PROTO((TRIO_NOARGS));

/*
 * If number is a NaN return non-zero, otherwise return zero.
 */
TRIO_PUBLIC int trio_isnan TRIO_PROTO((double number));

/*
 * If number is positive infinity return 1, if number is negative
 * infinity return -1, otherwise return 0.
 */
TRIO_PUBLIC int trio_isinf TRIO_PROTO((double number));

/*
 * If number is finite return non-zero, otherwise return zero.
 */
#if 0
	/* Temporary fix - these 2 routines not used in libxml */
TRIO_PUBLIC int trio_isfinite TRIO_PROTO((double number));

TRIO_PUBLIC int trio_fpclassify TRIO_PROTO((double number));
#endif

TRIO_PUBLIC int trio_signbit TRIO_PROTO((double number));

TRIO_PUBLIC int trio_fpclassify_and_signbit TRIO_PROTO((double number, int *is_negative));

#ifdef __cplusplus
}
#endif

#endif /* TRIO_NAN_H */


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2000 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.
 *
 ************************************************************************
 *
 * Private functions, types, etc. used for callback functions.
 *
 * The ref pointer is an opaque type and should remain as such.
 * Private data must only be accessible through the getter and
 * setter functions.
 *
 ************************************************************************/

#ifndef TRIO_TRIOP_H
#define TRIO_TRIOP_H

#include "triodef.h"

#include <stdlib.h>
#if defined(TRIO_COMPILER_ANCIENT)
# include <varargs.h>
#else
# include <stdarg.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifndef TRIO_C99
# define TRIO_C99 1
#endif
#ifndef TRIO_BSD
# define TRIO_BSD 1
#endif
#ifndef TRIO_GNU
# define TRIO_GNU 1
#endif
#ifndef TRIO_MISC
# define TRIO_MISC 1
#endif
#ifndef TRIO_UNIX98
# define TRIO_UNIX98 1
#endif
#ifndef TRIO_MICROSOFT
# define TRIO_MICROSOFT 1
#endif
#ifndef TRIO_EXTENSION
# define TRIO_EXTENSION 1
#endif
#ifndef TRIO_WIDECHAR /* Does not work yet. Do not enable */
# define TRIO_WIDECHAR 0
#endif
#ifndef TRIO_ERRORS
# define TRIO_ERRORS 1
#endif

#ifndef TRIO_MALLOC
# define TRIO_MALLOC(n) malloc(n)
#endif
#ifndef TRIO_REALLOC
# define TRIO_REALLOC(x,n) realloc((x),(n))
#endif
#ifndef TRIO_FREE
# define TRIO_FREE(x) free(x)
#endif

/*************************************************************************
 * User-defined specifiers
 */

typedef int (*trio_callback_t) TRIO_PROTO((trio_pointer_t));

trio_pointer_t trio_register TRIO_PROTO((trio_callback_t callback, const char *name));
void trio_unregister TRIO_PROTO((trio_pointer_t handle));

TRIO_CONST char *trio_get_format TRIO_PROTO((trio_pointer_t ref));
trio_pointer_t trio_get_argument TRIO_PROTO((trio_pointer_t ref));

/* Modifiers */
int  trio_get_width TRIO_PROTO((trio_pointer_t ref));
void trio_set_width TRIO_PROTO((trio_pointer_t ref, int width));
int  trio_get_precision TRIO_PROTO((trio_pointer_t ref));
void trio_set_precision TRIO_PROTO((trio_pointer_t ref, int precision));
int  trio_get_base TRIO_PROTO((trio_pointer_t ref));
void trio_set_base TRIO_PROTO((trio_pointer_t ref, int base));
int  trio_get_padding TRIO_PROTO((trio_pointer_t ref));
void trio_set_padding TRIO_PROTO((trio_pointer_t ref, int is_padding));
int  trio_get_short TRIO_PROTO((trio_pointer_t ref)); /* h */
void trio_set_shortshort TRIO_PROTO((trio_pointer_t ref, int is_shortshort));
int  trio_get_shortshort TRIO_PROTO((trio_pointer_t ref)); /* hh */
void trio_set_short TRIO_PROTO((trio_pointer_t ref, int is_short));
int  trio_get_long TRIO_PROTO((trio_pointer_t ref)); /* l */
void trio_set_long TRIO_PROTO((trio_pointer_t ref, int is_long));
int  trio_get_longlong TRIO_PROTO((trio_pointer_t ref)); /* ll */
void trio_set_longlong TRIO_PROTO((trio_pointer_t ref, int is_longlong));
int  trio_get_longdouble TRIO_PROTO((trio_pointer_t ref)); /* L */
void trio_set_longdouble TRIO_PROTO((trio_pointer_t ref, int is_longdouble));
int  trio_get_alternative TRIO_PROTO((trio_pointer_t ref)); /* # */
void trio_set_alternative TRIO_PROTO((trio_pointer_t ref, int is_alternative));
int  trio_get_alignment TRIO_PROTO((trio_pointer_t ref)); /* - */
void trio_set_alignment TRIO_PROTO((trio_pointer_t ref, int is_leftaligned));
int  trio_get_spacing TRIO_PROTO((trio_pointer_t ref)); /*  TRIO_PROTO((space) */
void trio_set_spacing TRIO_PROTO((trio_pointer_t ref, int is_space));
int  trio_get_sign TRIO_PROTO((trio_pointer_t ref)); /* + */
void trio_set_sign TRIO_PROTO((trio_pointer_t ref, int is_showsign));
int  trio_get_quote TRIO_PROTO((trio_pointer_t ref)); /* ' */
void trio_set_quote TRIO_PROTO((trio_pointer_t ref, int is_quote));
int  trio_get_upper TRIO_PROTO((trio_pointer_t ref));
void trio_set_upper TRIO_PROTO((trio_pointer_t ref, int is_upper));
#if TRIO_C99
int  trio_get_largest TRIO_PROTO((trio_pointer_t ref)); /* j */
void trio_set_largest TRIO_PROTO((trio_pointer_t ref, int is_largest));
int  trio_get_ptrdiff TRIO_PROTO((trio_pointer_t ref)); /* t */
void trio_set_ptrdiff TRIO_PROTO((trio_pointer_t ref, int is_ptrdiff));
int  trio_get_size TRIO_PROTO((trio_pointer_t ref)); /* z / Z */
void trio_set_size TRIO_PROTO((trio_pointer_t ref, int is_size));
#endif

/* Printing */
int trio_print_ref TRIO_PROTO((trio_pointer_t ref, const char *format, ...));
int trio_vprint_ref TRIO_PROTO((trio_pointer_t ref, const char *format, va_list args));
int trio_printv_ref TRIO_PROTO((trio_pointer_t ref, const char *format, trio_pointer_t *args));

void trio_print_int TRIO_PROTO((trio_pointer_t ref, int number));
void trio_print_uint TRIO_PROTO((trio_pointer_t ref, unsigned int number));
/*  void trio_print_long TRIO_PROTO((trio_pointer_t ref, long number)); */
/*  void trio_print_ulong TRIO_PROTO((trio_pointer_t ref, unsigned long number)); */
void trio_print_double TRIO_PROTO((trio_pointer_t ref, double number));
void trio_print_string TRIO_PROTO((trio_pointer_t ref, char *string));
void trio_print_pointer TRIO_PROTO((trio_pointer_t ref, trio_pointer_t pointer));

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* TRIO_TRIOP_H */


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 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.
 *
 ************************************************************************/

/*************************************************************************
 * Include files
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "triodef.h"
#include "triostr.h"

/*************************************************************************
 * Definitions
 */

#if !defined(TRIO_STRING_PUBLIC)
# define TRIO_STRING_PUBLIC TRIO_PUBLIC
#endif
#if !defined(TRIO_STRING_PRIVATE)
# define TRIO_STRING_PRIVATE TRIO_PRIVATE
#endif

#if !defined(NULL)
# define NULL 0
#endif
#if !defined(NIL)
# define NIL ((char)0)
#endif
#if !defined(FALSE)
# define FALSE (1 == 0)
# define TRUE (! FALSE)
#endif
#if !defined(BOOLEAN_T)
# define BOOLEAN_T int
#endif

#if defined(TRIO_COMPILER_SUPPORTS_C99)
# define USE_STRTOD
# define USE_STRTOF
#elif defined(TRIO_COMPILER_MSVC)
# define USE_STRTOD
#endif

#if defined(TRIO_PLATFORM_UNIX)
# define USE_STRCASECMP
# define USE_STRNCASECMP
# if defined(TRIO_PLATFORM_SUNOS)
#  define USE_SYS_ERRLIST
# else
#  define USE_STRERROR
# endif
# if defined(TRIO_PLATFORM_QNX)
#  define strcasecmp(x,y) stricmp(x,y)
#  define strncasecmp(x,y,n) strnicmp(x,y,n)
# endif
#elif defined(TRIO_PLATFORM_WIN32)
# define USE_STRCASECMP
# if defined(_WIN32_WCE)
#  define strcasecmp(x,y) _stricmp(x,y)
# else
#  define strcasecmp(x,y) strcmpi(x,y)
# endif
#endif

#if !(defined(TRIO_PLATFORM_SUNOS))
# define USE_TOLOWER
# define USE_TOUPPER
#endif

/*************************************************************************
 * Structures
 */

struct _trio_string_t
{
  char *content;
  size_t length;
  size_t allocated;
};

/*************************************************************************
 * Constants
 */

#if !defined(TRIO_MINIMAL)
static TRIO_CONST char rcsid[] = "@(#)$Id$";
#endif

/*************************************************************************
 * Static String Functions
 */

#if defined(TRIO_DOCUMENTATION)
# include "doc/doc_static.h"
#endif
/** @addtogroup StaticStrings
    @{
*/

/**
   Create new string.

   @param size Size of new string.
   @return Pointer to string, or NULL if allocation failed.
*/
TRIO_STRING_PUBLIC char *
trio_create
TRIO_ARGS1((size),
	   size_t size)
{
  return (char *)TRIO_MALLOC(size);
}

/**
   Destroy string.

   @param string String to be freed.
*/
TRIO_STRING_PUBLIC void
trio_destroy
TRIO_ARGS1((string),
	   char *string)
{
  if (string)
    {
      TRIO_FREE(string);
    }
}

/**
   Count the number of characters in a string.

   @param string String to measure.
   @return Number of characters in @string.
*/
TRIO_STRING_PUBLIC size_t
trio_length
TRIO_ARGS1((string),
	   TRIO_CONST char *string)
{
  return strlen(string);
}

#if !defined(TRIO_MINIMAL)
/**
   Append @p source at the end of @p target.

   @param target Target string.
   @param source Source string.
   @return Boolean value indicating success or failure.

   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p target string and @p source string.
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC int
trio_append
TRIO_ARGS2((target, source),
	   char *target,
	   TRIO_CONST char *source)
{
  assert(target);
  assert(source);

  return (strcat(target, source) != NULL);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Append at most @p max characters from @p source to @p target.

   @param target Target string.
   @param max Maximum number of characters to append.
   @param source Source string.
   @return Boolean value indicating success or failure.

   @pre @p target must point to a memory chuck with sufficient room to
   contain the @p target string and the @p source string (at most @p max
   characters).
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC int
trio_append_max
TRIO_ARGS3((target, max, source),
	   char *target,
	   size_t max,
	   TRIO_CONST char *source)
{
  size_t length;

  assert(target);
  assert(source);

  length = trio_length(target);

  if (max > length)
    {
      strncat(target, source, max - length - 1);
    }
  return TRUE;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Determine if a string contains a substring.

   @param string String to be searched.
   @param substring String to be found.
   @return Boolean value indicating success or failure.
*/
TRIO_STRING_PUBLIC int
trio_contains
TRIO_ARGS2((string, substring),
	   TRIO_CONST char *string,
	   TRIO_CONST char *substring)
{
  assert(string);
  assert(substring);

  return (0 != strstr(string, substring));
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Copy @p source to @p target.

   @param target Target string.
   @param source Source string.
   @return Boolean value indicating success or failure.

   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p source string.
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC int
trio_copy
TRIO_ARGS2((target, source),
	   char *target,
	   TRIO_CONST char *source)
{
  assert(target);
  assert(source);

  (void)strcpy(target, source);
  return TRUE;
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Copy at most @p max characters from @p source to @p target.

   @param target Target string.
   @param max Maximum number of characters to append.
   @param source Source string.
   @return Boolean value indicating success or failure.

   @pre @p target must point to a memory chunk with sufficient room to
   contain the @p source string (at most @p max characters).
   @pre No boundary checking is performed, so insufficient memory will
   result in a buffer overrun.
   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC int
trio_copy_max
TRIO_ARGS3((target, max, source),
	   char *target,
	   size_t max,
	   TRIO_CONST char *source)
{
  assert(target);
  assert(source);
  assert(max > 0); /* Includes != 0 */

  (void)strncpy(target, source, max - 1);
  target[max - 1] = (char)0;
  return TRUE;
}

/*
 * TrioDuplicateMax
 */
TRIO_STRING_PRIVATE char *
TrioDuplicateMax
TRIO_ARGS2((source, size),
	   TRIO_CONST char *source,
	   size_t size)
{
  char *target;

  assert(source);

  /* Make room for string plus a terminating zero */
  size++;
  target = trio_create(size);
  if (target)
    {
      trio_copy_max(target, size, source);
    }
  return target;
}

/**
   Duplicate @p source.

   @param source Source string.
   @return A copy of the @p source string.

   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC char *
trio_duplicate
TRIO_ARGS1((source),
	   TRIO_CONST char *source)
{
  return TrioDuplicateMax(source, trio_length(source));
}

#if !defined(TRIO_MINIMAL)
/**
   Duplicate at most @p max characters of @p source.

   @param source Source string.
   @param max Maximum number of characters to duplicate.
   @return A copy of the @p source string.

   @post @p target will be zero terminated.
*/
TRIO_STRING_PUBLIC char *
trio_duplicate_max TRIO_ARGS2((source, max),
			      TRIO_CONST char *source,
			      size_t max)
{
  size_t length;

  assert(source);
  assert(max > 0);

  length = trio_length(source);
  if (length > max)
    {
      length = max;
    }
  return TrioDuplicateMax(source, length);
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Compare if two strings are equal.

   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Case-insensitive comparison.
*/
TRIO_STRING_PUBLIC int
trio_equal
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
#if defined(USE_STRCASECMP)
      return (0 == strcasecmp(first, second));
#else
      while ((*first != NIL) && (*second != NIL))
	{
	  if (trio_to_upper(*first) != trio_to_upper(*second))
	    {
	      break;
	    }
	  first++;
	  second++;
	}
      return ((*first == NIL) && (*second == NIL));
#endif
    }
  return FALSE;
}

/**
   Compare if two strings are equal.

   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Case-sensitive comparison.
*/
TRIO_STRING_PUBLIC int
trio_equal_case
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
      return (0 == strcmp(first, second));
    }
  return FALSE;
}

#if !defined(TRIO_MINIMAL)
/**
   Compare if two strings up until the first @p max characters are equal.

   @param first First string.
   @param max Maximum number of characters to compare.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Case-sensitive comparison.
*/
TRIO_STRING_PUBLIC int
trio_equal_case_max
TRIO_ARGS3((first, max, second),
	   TRIO_CONST char *first,
	   size_t max,
	   TRIO_CONST char *second)
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
      return (0 == strncmp(first, second, max));
    }
  return FALSE;
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Compare if two strings are equal.

   @param first First string.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Collating characters are considered equal.
*/
TRIO_STRING_PUBLIC int
trio_equal_locale
TRIO_ARGS2((first, second),
	   TRIO_CONST char *first,
	   TRIO_CONST char *second)
{
  assert(first);
  assert(second);

#if defined(LC_COLLATE)
  return (strcoll(first, second) == 0);
#else
  return trio_equal(first, second);
#endif
}

/**
   Compare if two strings up until the first @p max characters are equal.

   @param first First string.
   @param max Maximum number of characters to compare.
   @param second Second string.
   @return Boolean indicating whether the two strings are equal or not.

   Case-insensitive comparison.
*/
TRIO_STRING_PUBLIC int
trio_equal_max
TRIO_ARGS3((first, max, second),
	   TRIO_CONST char *first,
	   size_t max,
	   TRIO_CONST char *second)
{
  assert(first);
  assert(second);

  if ((first != NULL) && (second != NULL))
    {
#if defined(USE_STRNCASECMP)
      return (0 == strncasecmp(first, second, max));
#else
      /* Not adequately tested yet */
      size_t cnt = 0;
      while ((*first != NIL) && (*second != NIL) && (cnt <= max))
	{
	  if (trio_to_upper(*first) != trio_to_upper(*second))
	    {
	      break;
	    }
	  first++;
	  second++;
	  cnt++;
	}
      return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
#endif
    }
  return FALSE;
}

/**
   Provide a textual description of an error code (errno).

   @param error_number Error number.
   @return Textual description of @p error_number.
*/
TRIO_STRING_PUBLIC TRIO_CONST char *
trio_error
TRIO_ARGS1((error_number),
	   int error_number)
{
#if defined(USE_STRERROR)

  return strerror(error_number);

#elif defined(USE_SYS_ERRLIST)

  extern char *sys_errlist[];
  extern int sys_nerr;

  return ((error_number < 0) || (error_number >= sys_nerr))
    ? "unknown"
    : sys_errlist[error_number];

#else

  return "unknown";

#endif
}

#if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE)
/**
   Format the date/time according to @p format.

   @param target Target string.
   @param max Maximum number of characters to format.
   @param format Formatting string.
   @param datetime Date/time structure.
   @return Number of formatted characters.

   The formatting string accepts the same specifiers as the standard C
   function strftime.
*/
TRIO_STRING_PUBLIC size_t
trio_format_date_max
TRIO_ARGS4((target, max, format, datetime),
	   char *target,
	   size_t max,
	   TRIO_CONST char *format,
	   TRIO_CONST struct tm *datetime)
{
  assert(target);
  assert(format);
  assert(datetime);
  assert(max > 0);

  return strftime(target, max, format, datetime);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Calculate a hash value for a string.

   @param string String to be calculated on.
   @param type Hash function.
   @return Calculated hash value.

   @p type can be one of the following
   @li @c TRIO_HASH_PLAIN Plain hash function.
*/
TRIO_STRING_PUBLIC unsigned long
trio_hash
TRIO_ARGS2((string, type),
	   TRIO_CONST char *string,
	   int type)
{
  unsigned long value = 0L;
  char ch;

  assert(string);

  switch (type)
    {
    case TRIO_HASH_PLAIN:
      while ( (ch = *string++) != NIL )
	{
	  value *= 31;
	  value += (unsigned long)ch;
	}
      break;
    default:
      assert(FALSE);
      break;
    }
  return value;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Find first occurrence of a character in a string.

   @param string String to be searched.
   @param character Character to be found.
   @param A pointer to the found character, or NULL if character was not found.
 */
TRIO_STRING_PUBLIC char *
trio_index
TRIO_ARGS2((string, character),
	   TRIO_CONST char *string,
	   int character)
{
  assert(string);

  return strchr(string, character);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Find last occurrence of a character in a string.

   @param string String to be searched.
   @param character Character to be found.
   @param A pointer to the found character, or NULL if character was not found.
 */
TRIO_STRING_PUBLIC char *
trio_index_last
TRIO_ARGS2((string, character),
	   TRIO_CONST char *string,
	   int character)
{
  assert(string);

  return strchr(string, character);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Convert the alphabetic letters in the string to lower-case.

   @param target String to be converted.
   @return Number of processed characters (converted or not).
*/
TRIO_STRING_PUBLIC int
trio_lower
TRIO_ARGS1((target),
	   char *target)
{
  assert(target);

  return trio_span_function(target, target, trio_to_lower);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Compare two strings using wildcards.

   @param string String to be searched.
   @param pattern Pattern, including wildcards, to search for.
   @return Boolean value indicating success or failure.

   Case-insensitive comparison.

   The following wildcards can be used
   @li @c * Match any number of characters.
   @li @c ? Match a single character.
*/
TRIO_STRING_PUBLIC int
trio_match
TRIO_ARGS2((string, pattern),
	   TRIO_CONST char *string,
	   TRIO_CONST char *pattern)
{
  assert(string);
  assert(pattern);

  for (; ('*' != *pattern); ++pattern, ++string)
    {
      if (NIL == *string)
	{
	  return (NIL == *pattern);
	}
      if ((trio_to_upper((int)*string) != trio_to_upper((int)*pattern))
	  && ('?' != *pattern))
	{
	  return FALSE;
	}
    }
  /* two-line patch to prevent *too* much recursiveness: */
  while ('*' == pattern[1])
    pattern++;

  do
    {
      if ( trio_match(string, &pattern[1]) )
	{
	  return TRUE;
	}
    }
  while (*string++);

  return FALSE;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Compare two strings using wildcards.

   @param string String to be searched.
   @param pattern Pattern, including wildcards, to search for.
   @return Boolean value indicating success or failure.

   Case-sensitive comparison.

   The following wildcards can be used
   @li @c * Match any number of characters.
   @li @c ? Match a single character.
*/
TRIO_STRING_PUBLIC int
trio_match_case
TRIO_ARGS2((string, pattern),
	   TRIO_CONST char *string,
	   TRIO_CONST char *pattern)
{
  assert(string);
  assert(pattern);

  for (; ('*' != *pattern); ++pattern, ++string)
    {
      if (NIL == *string)
	{
	  return (NIL == *pattern);
	}
      if ((*string != *pattern)
	  && ('?' != *pattern))
	{
	  return FALSE;
	}
    }
  /* two-line patch to prevent *too* much recursiveness: */
  while ('*' == pattern[1])
    pattern++;

  do
    {
      if ( trio_match_case(string, &pattern[1]) )
	{
	  return TRUE;
	}
    }
  while (*string++);

  return FALSE;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Execute a function on each character in string.

   @param target Target string.
   @param source Source string.
   @param Function Function to be executed.
   @return Number of processed characters.
*/
TRIO_STRING_PUBLIC size_t
trio_span_function
TRIO_ARGS3((target, source, Function),
	   char *target,
	   TRIO_CONST char *source,
	   int (*Function) TRIO_PROTO((int)))
{
  size_t count = 0;

  assert(target);
  assert(source);
  assert(Function);

  while (*source != NIL)
    {
      *target++ = Function(*source++);
      count++;
    }
  return count;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Search for a substring in a string.

   @param string String to be searched.
   @param substring String to be found.
   @return Pointer to first occurrence of @p substring in @p string, or NULL
   if no match was found.
*/
TRIO_STRING_PUBLIC char *
trio_substring
TRIO_ARGS2((string, substring),
	   TRIO_CONST char *string,
	   TRIO_CONST char *substring)
{
  assert(string);
  assert(substring);

  return strstr(string, substring);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Search for a substring in the first @p max characters of a string.

   @param string String to be searched.
   @param max Maximum characters to be searched.
   @param substring String to be found.
   @return Pointer to first occurrence of @p substring in @p string, or NULL
   if no match was found.
*/
TRIO_STRING_PUBLIC char *
trio_substring_max
TRIO_ARGS3((string, max, substring),
	   TRIO_CONST char *string,
	   size_t max,
	   TRIO_CONST char *substring)
{
  size_t count;
  size_t size;
  char *result = NULL;

  assert(string);
  assert(substring);

  size = trio_length(substring);
  if (size <= max)
    {
      for (count = 0; count <= max - size; count++)
	{
	  if (trio_equal_max(substring, size, &string[count]))
	    {
	      result = (char *)&string[count];
	      break;
	    }
	}
    }
  return result;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Tokenize string.

   @param string String to be tokenized.
   @param tokens String containing list of delimiting characters.
   @return Start of new token.

   @warning @p string will be destroyed.
*/
TRIO_STRING_PUBLIC char *
trio_tokenize
TRIO_ARGS2((string, delimiters),
	   char *string,
	   TRIO_CONST char *delimiters)
{
  assert(delimiters);

  return strtok(string, delimiters);
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

   The following Extended Backus-Naur form is used
   @verbatim
   double        ::= [ <sign> ]
                     ( <number> |
                       <number> <decimal_point> <number> |
                       <decimal_point> <number> )
                     [ <exponential> [ <sign> ] <number> ]
   number        ::= 1*( <digit> )
   digit         ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
   exponential   ::= ( 'e' | 'E' )
   sign          ::= ( '-' | '+' )
   decimal_point ::= '.'
   @endverbatim
*/
/* FIXME: Add EBNF for hex-floats */
TRIO_STRING_PUBLIC trio_long_double_t
trio_to_long_double
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
{
#if defined(USE_STRTOLD)
  return strtold(source, endp);
#else
  int isNegative = FALSE;
  int isExponentNegative = FALSE;
  trio_long_double_t integer = 0.0;
  trio_long_double_t fraction = 0.0;
  unsigned long exponent = 0;
  trio_long_double_t base;
  trio_long_double_t fracdiv = 1.0;
  trio_long_double_t value = 0.0;

  /* First try hex-floats */
  if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
    {
      base = 16.0;
      source += 2;
      while (isxdigit((int)*source))
	{
	  integer *= base;
	  integer += (isdigit((int)*source)
		      ? (*source - '0')
		      : 10 + (trio_to_upper((int)*source) - 'A'));
	  source++;
	}
      if (*source == '.')
	{
	  source++;
	  while (isxdigit((int)*source))
	    {
	      fracdiv /= base;
	      fraction += fracdiv * (isdigit((int)*source)
				     ? (*source - '0')
				     : 10 + (trio_to_upper((int)*source) - 'A'));
	      source++;
	    }
	  if ((*source == 'p') || (*source == 'P'))
	    {
	      source++;
	      if ((*source == '+') || (*source == '-'))
		{
		  isExponentNegative = (*source == '-');
		  source++;
		}
	      while (isdigit((int)*source))
		{
		  exponent *= 10;
		  exponent += (*source - '0');
		  source++;
		}
	    }
	}
      /* For later use with exponent */
      base = 2.0;
    }
  else /* Then try normal decimal floats */
    {
      base = 10.0;
      isNegative = (*source == '-');
      /* Skip sign */
      if ((*source == '+') || (*source == '-'))
	source++;

      /* Integer part */
      while (isdigit((int)*source))
	{
	  integer *= base;
	  integer += (*source - '0');
	  source++;
	}

      if (*source == '.')
	{
	  source++; /* skip decimal point */
	  while (isdigit((int)*source))
	    {
	      fracdiv /= base;
	      fraction += (*source - '0') * fracdiv;
	      source++;
	    }
	}
      if ((*source == 'e')
	  || (*source == 'E')
#if TRIO_MICROSOFT
	  || (*source == 'd')
	  || (*source == 'D')
#endif
	  )
	{
	  source++; /* Skip exponential indicator */
	  isExponentNegative = (*source == '-');
	  if ((*source == '+') || (*source == '-'))
	    source++;
	  while (isdigit((int)*source))
	    {
	      exponent *= (int)base;
	      exponent += (*source - '0');
	      source++;
	    }
	}
    }

  value = integer + fraction;
  if (exponent != 0)
    {
      if (isExponentNegative)
	value /= pow(base, (double)exponent);
      else
	value *= pow(base, (double)exponent);
    }
  if (isNegative)
    value = -value;

  if (endp)
    *endp = (char *)source;
  return value;
#endif
}

/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

   See @ref trio_to_long_double.
*/
TRIO_STRING_PUBLIC double
trio_to_double
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
{
#if defined(USE_STRTOD)
  return strtod(source, endp);
#else
  return (double)trio_to_long_double(source, endp);
#endif
}

#if !defined(TRIO_MINIMAL)
/**
   Convert string to floating-point number.

   @param source String to be converted.
   @param endp Pointer to end of the converted string.
   @return A floating-point number.

   See @ref trio_to_long_double.
*/
TRIO_STRING_PUBLIC float
trio_to_float
TRIO_ARGS2((source, endp),
	   TRIO_CONST char *source,
	   char **endp)
{
#if defined(USE_STRTOF)
  return strtof(source, endp);
#else
  return (float)trio_to_long_double(source, endp);
#endif
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Convert string to signed integer.

   @param string String to be converted.
   @param endp Pointer to end of converted string.
   @param base Radix number of number.
*/
TRIO_STRING_PUBLIC long
trio_to_long
TRIO_ARGS3((string, endp, base),
	   TRIO_CONST char *string,
	   char **endp,
	   int base)
{
  assert(string);
  assert((base >= 2) && (base <= 36));

  return strtol(string, endp, base);
}

#if !defined(TRIO_MINIMAL)
/**
   Convert one alphabetic letter to lower-case.

   @param source The letter to be converted.
   @return The converted letter.
*/
TRIO_STRING_PUBLIC int
trio_to_lower
TRIO_ARGS1((source),
	   int source)
{
#if defined(USE_TOLOWER)

  return tolower(source);

#else

  /* Does not handle locales or non-contiguous alphabetic characters */
  return ((source >= (int)'A') && (source <= (int)'Z'))
    ? source - 'A' + 'a'
    : source;

#endif
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Convert string to unsigned integer.

   @param string String to be converted.
   @param endp Pointer to end of converted string.
   @param base Radix number of number.
*/
TRIO_STRING_PUBLIC unsigned long
trio_to_unsigned_long
TRIO_ARGS3((string, endp, base),
	   TRIO_CONST char *string,
	   char **endp,
	   int base)
{
  assert(string);
  assert((base >= 2) && (base <= 36));

  return strtoul(string, endp, base);
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Convert one alphabetic letter to upper-case.

   @param source The letter to be converted.
   @return The converted letter.
*/
TRIO_STRING_PUBLIC int
trio_to_upper
TRIO_ARGS1((source),
	   int source)
{
#if defined(USE_TOUPPER)

  return toupper(source);

#else

  /* Does not handle locales or non-contiguous alphabetic characters */
  return ((source >= (int)'a') && (source <= (int)'z'))
    ? source - 'a' + 'A'
    : source;

#endif
}

#if !defined(TRIO_MINIMAL)
/**
   Convert the alphabetic letters in the string to upper-case.

   @param target The string to be converted.
   @return The number of processed characters (converted or not).
*/
TRIO_STRING_PUBLIC int
trio_upper
TRIO_ARGS1((target),
	   char *target)
{
  assert(target);

  return trio_span_function(target, target, trio_to_upper);
}
#endif /* !defined(TRIO_MINIMAL) */

/** @} End of StaticStrings */

/*************************************************************************
 * Dynamic String Functions
 */

#if defined(TRIO_DOCUMENTATION)
# include "doc/doc_dynamic.h"
#endif
/** @addtogroup DynamicStrings
    @{
*/

/*
 * TrioStringAlloc
 */
TRIO_STRING_PRIVATE trio_string_t *
TrioStringAlloc(TRIO_NOARGS)
{
  trio_string_t *self;

  self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t));
  if (self)
    {
      self->content = NULL;
      self->length = 0;
      self->allocated = 0;
    }
  return self;
}

/*
 * TrioStringGrow
 *
 * The size of the string will be increased by 'delta' characters. If
 * 'delta' is zero, the size will be doubled.
 */
TRIO_STRING_PRIVATE BOOLEAN_T
TrioStringGrow
TRIO_ARGS2((self, delta),
	   trio_string_t *self,
	   size_t delta)
{
  BOOLEAN_T status = FALSE;
  char *new_content;
  size_t new_size;

  new_size = (delta == 0)
    ? ( (self->allocated == 0) ? 1 : self->allocated * 2 )
    : self->allocated + delta;

  new_content = (char *)TRIO_REALLOC(self->content, new_size);
  if (new_content)
    {
      self->content = new_content;
      self->allocated = new_size;
      status = TRUE;
    }
  return status;
}

#if !defined(TRIO_MINIMAL)
/*
 * TrioStringGrowTo
 *
 * The size of the string will be increased to 'length' plus one characters.
 * If 'length' is less than the original size, the original size will be
 * used (that is, the size of the string is never decreased).
 */
TRIO_STRING_PRIVATE BOOLEAN_T
TrioStringGrowTo
TRIO_ARGS2((self, length),
	   trio_string_t *self,
	   size_t length)
{
  length++; /* Room for terminating zero */
  return (self->allocated < length)
    ? TrioStringGrow(self, length - self->allocated)
    : TRUE;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/**
   Create a new dynamic string.

   @param initial_size Initial size of the buffer.
   @return Newly allocated dynamic string, or NULL if memory allocation failed.
*/
TRIO_STRING_PUBLIC trio_string_t *
trio_string_create
TRIO_ARGS1((initial_size),
	   int initial_size)
{
  trio_string_t *self;

  self = TrioStringAlloc();
  if (self)
    {
      if (TrioStringGrow(self,
			 (size_t)((initial_size > 0) ? initial_size : 1)))
	{
	  self->content[0] = (char)0;
	  self->allocated = initial_size;
	}
      else
	{
	  trio_string_destroy(self);
	  self = NULL;
	}
    }
  return self;
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Deallocate the dynamic string and its contents.

   @param self Dynamic string
*/
TRIO_STRING_PUBLIC void
trio_string_destroy
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  assert(self);

  if (self)
    {
      trio_destroy(self->content);
      TRIO_FREE(self);
    }
}

#if !defined(TRIO_MINIMAL)
/**
   Get a pointer to the content.

   @param self Dynamic string.
   @param offset Offset into content.
   @return Pointer to the content.

   @p Offset can be zero, positive, or negative. If @p offset is zero,
   then the start of the content will be returned. If @p offset is positive,
   then a pointer to @p offset number of characters from the beginning of the
   content is returned. If @p offset is negative, then a pointer to @p offset
   number of characters from the ending of the string, starting at the
   terminating zero, is returned.
*/
TRIO_STRING_PUBLIC char *
trio_string_get
TRIO_ARGS2((self, offset),
	   trio_string_t *self,
	   int offset)
{
  char *result = NULL;

  assert(self);

  if (self->content != NULL)
    {
      if (self->length == 0)
	{
	  (void)trio_string_length(self);
	}
      if (offset >= 0)
	{
	  if (offset > (int)self->length)
	    {
	      offset = self->length;
	    }
	}
      else
	{
	  offset += self->length + 1;
	  if (offset < 0)
	    {
	      offset = 0;
	    }
	}
      result = &(self->content[offset]);
    }
  return result;
}
#endif /* !defined(TRIO_MINIMAL) */

/**
   Extract the content.

   @param self Dynamic String
   @return Content of dynamic string.

   The content is removed from the dynamic string. This enables destruction
   of the dynamic string without deallocation of the content.
*/
TRIO_STRING_PUBLIC char *
trio_string_extract
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  char *result;

  assert(self);

  result = self->content;
  /* FIXME: Allocate new empty buffer? */
  self->content = NULL;
  self->length = self->allocated = 0;
  return result;
}

#if !defined(TRIO_MINIMAL)
/**
   Set the content of the dynamic string.

   @param self Dynamic String
   @param buffer The new content.

   Sets the content of the dynamic string to a copy @p buffer.
   An existing content will be deallocated first, if necessary.

   @remark
   This function will make a copy of @p buffer.
   You are responsible for deallocating @p buffer yourself.
*/
TRIO_STRING_PUBLIC void
trio_xstring_set
TRIO_ARGS2((self, buffer),
	   trio_string_t *self,
	   char *buffer)
{
  assert(self);

  trio_destroy(self->content);
  self->content = trio_duplicate(buffer);
}
#endif /* !defined(TRIO_MINIMAL) */

/*
 * trio_string_size
 */
TRIO_STRING_PUBLIC int
trio_string_size
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  assert(self);

  return self->allocated;
}

/*
 * trio_string_terminate
 */
TRIO_STRING_PUBLIC void
trio_string_terminate
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  trio_xstring_append_char(self, 0);
}

#if !defined(TRIO_MINIMAL)
/**
   Append the second string to the first.

   @param self Dynamic string to be modified.
   @param other Dynamic string to copy from.
   @return Boolean value indicating success or failure.
*/
TRIO_STRING_PUBLIC int
trio_string_append
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  size_t length;

  assert(self);
  assert(other);

  length = self->length + other->length;
  if (!TrioStringGrowTo(self, length))
    goto error;
  trio_copy(&self->content[self->length], other->content);
  self->length = length;
  return TRUE;

 error:
  return FALSE;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_append
 */
TRIO_STRING_PUBLIC int
trio_xstring_append
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  size_t length;

  assert(self);
  assert(other);

  length = self->length + trio_length(other);
  if (!TrioStringGrowTo(self, length))
    goto error;
  trio_copy(&self->content[self->length], other);
  self->length = length;
  return TRUE;

 error:
  return FALSE;
}
#endif /* !defined(TRIO_MINIMAL) */

/*
 * trio_xstring_append_char
 */
TRIO_STRING_PUBLIC int
trio_xstring_append_char
TRIO_ARGS2((self, character),
	   trio_string_t *self,
	   char character)
{
  assert(self);

  if ((int)self->length >= trio_string_size(self))
    {
      if (!TrioStringGrow(self, 0))
	goto error;
    }
  self->content[self->length] = character;
  self->length++;
  return TRUE;

 error:
  return FALSE;
}

#if !defined(TRIO_MINIMAL)
/**
   Search for the first occurrence of second parameter in the first.

   @param self Dynamic string to be modified.
   @param other Dynamic string to copy from.
   @return Boolean value indicating success or failure.
*/
TRIO_STRING_PUBLIC int
trio_string_contains
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_contains(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_contains
 */
TRIO_STRING_PUBLIC int
trio_xstring_contains
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_contains(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_copy
 */
TRIO_STRING_PUBLIC int
trio_string_copy
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  self->length = 0;
  return trio_string_append(self, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_copy
 */
TRIO_STRING_PUBLIC int
trio_xstring_copy
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  self->length = 0;
  return trio_xstring_append(self, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_duplicate
 */
TRIO_STRING_PUBLIC trio_string_t *
trio_string_duplicate
TRIO_ARGS1((other),
	   trio_string_t *other)
{
  trio_string_t *self;

  assert(other);

  self = TrioStringAlloc();
  if (self)
    {
      self->content = TrioDuplicateMax(other->content, other->length);
      if (self->content)
	{
	  self->length = other->length;
	  self->allocated = self->length + 1;
	}
      else
	{
	  self->length = self->allocated = 0;
	}
    }
  return self;
}
#endif /* !defined(TRIO_MINIMAL) */

/*
 * trio_xstring_duplicate
 */
TRIO_STRING_PUBLIC trio_string_t *
trio_xstring_duplicate
TRIO_ARGS1((other),
	   TRIO_CONST char *other)
{
  trio_string_t *self;

  assert(other);

  self = TrioStringAlloc();
  if (self)
    {
      self->content = TrioDuplicateMax(other, trio_length(other));
      if (self->content)
	{
	  self->length = trio_length(self->content);
	  self->allocated = self->length + 1;
	}
      else
	{
	  self->length = self->allocated = 0;
	}
    }
  return self;
}

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_equal
 */
TRIO_STRING_PUBLIC int
trio_string_equal
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_equal(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_equal
 */
TRIO_STRING_PUBLIC int
trio_xstring_equal
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_equal(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_equal_max
 */
TRIO_STRING_PUBLIC int
trio_string_equal_max
TRIO_ARGS3((self, max, other),
	   trio_string_t *self,
	   size_t max,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_equal_max(self->content, max, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_equal_max
 */
TRIO_STRING_PUBLIC int
trio_xstring_equal_max
TRIO_ARGS3((self, max, other),
	   trio_string_t *self,
	   size_t max,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_equal_max(self->content, max, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_equal_case
 */
TRIO_STRING_PUBLIC int
trio_string_equal_case
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_equal_case(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_equal_case
 */
TRIO_STRING_PUBLIC int
trio_xstring_equal_case
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_equal_case(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_equal_case_max
 */
TRIO_STRING_PUBLIC int
trio_string_equal_case_max
TRIO_ARGS3((self, max, other),
	   trio_string_t *self,
	   size_t max,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_equal_case_max(self->content, max, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_equal_case_max
 */
TRIO_STRING_PUBLIC int
trio_xstring_equal_case_max
TRIO_ARGS3((self, max, other),
	   trio_string_t *self,
	   size_t max,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_equal_case_max(self->content, max, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE)
/*
 * trio_string_format_data_max
 */
TRIO_STRING_PUBLIC size_t
trio_string_format_date_max
TRIO_ARGS4((self, max, format, datetime),
	   trio_string_t *self,
	   size_t max,
	   TRIO_CONST char *format,
	   TRIO_CONST struct tm *datetime)
{
  assert(self);

  return trio_format_date_max(self->content, max, format, datetime);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_index
 */
TRIO_STRING_PUBLIC char *
trio_string_index
TRIO_ARGS2((self, character),
	   trio_string_t *self,
	   int character)
{
  assert(self);

  return trio_index(self->content, character);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_index_last
 */
TRIO_STRING_PUBLIC char *
trio_string_index_last
TRIO_ARGS2((self, character),
	   trio_string_t *self,
	   int character)
{
  assert(self);

  return trio_index_last(self->content, character);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_length
 */
TRIO_STRING_PUBLIC int
trio_string_length
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  assert(self);

  if (self->length == 0)
    {
      self->length = trio_length(self->content);
    }
  return self->length;
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_lower
 */
TRIO_STRING_PUBLIC int
trio_string_lower
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  assert(self);

  return trio_lower(self->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_match
 */
TRIO_STRING_PUBLIC int
trio_string_match
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_match(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_match
 */
TRIO_STRING_PUBLIC int
trio_xstring_match
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_match(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_match_case
 */
TRIO_STRING_PUBLIC int
trio_string_match_case
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_match_case(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_match_case
 */
TRIO_STRING_PUBLIC int
trio_xstring_match_case
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_match_case(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_substring
 */
TRIO_STRING_PUBLIC char *
trio_string_substring
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   trio_string_t *other)
{
  assert(self);
  assert(other);

  return trio_substring(self->content, other->content);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_xstring_substring
 */
TRIO_STRING_PUBLIC char *
trio_xstring_substring
TRIO_ARGS2((self, other),
	   trio_string_t *self,
	   TRIO_CONST char *other)
{
  assert(self);
  assert(other);

  return trio_substring(self->content, other);
}
#endif /* !defined(TRIO_MINIMAL) */

#if !defined(TRIO_MINIMAL)
/*
 * trio_string_upper
 */
TRIO_STRING_PUBLIC int
trio_string_upper
TRIO_ARGS1((self),
	   trio_string_t *self)
{
  assert(self);

  return trio_upper(self->content);
}
#endif /* !defined(TRIO_MINIMAL) */

/** @} End of DynamicStrings */


code:
/*************************************************************************
 *
 * $Id$
 *
 * Copyright (C) 2001 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.
 *
 ************************************************************************/

#ifndef TRIO_TRIOSTR_H
#define TRIO_TRIOSTR_H

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "triodef.h"
#include "triop.h"

enum {
  TRIO_HASH_NONE = 0,
  TRIO_HASH_PLAIN,
  TRIO_HASH_TWOSIGNED
};

#if !defined(TRIO_STRING_PUBLIC)
# if !defined(TRIO_PUBLIC)
#  define TRIO_PUBLIC
# endif
# define TRIO_STRING_PUBLIC TRIO_PUBLIC
#endif

/*************************************************************************
 * String functions
 */

TRIO_STRING_PUBLIC int trio_copy_max TRIO_PROTO((char *target, size_t max, const char *source));
TRIO_STRING_PUBLIC char *trio_create TRIO_PROTO((size_t size));
TRIO_STRING_PUBLIC void trio_destroy TRIO_PROTO((char *string));
TRIO_STRING_PUBLIC char *trio_duplicate TRIO_PROTO((const char *source));
TRIO_STRING_PUBLIC int trio_equal TRIO_PROTO((const char *first, const char *second));
TRIO_STRING_PUBLIC int trio_equal_case TRIO_PROTO((const char *first, const char *second));
TRIO_STRING_PUBLIC int trio_equal_locale TRIO_PROTO((const char *first, const char *second));
TRIO_STRING_PUBLIC int trio_equal_max TRIO_PROTO((const char *first, size_t max, const char *second));
TRIO_STRING_PUBLIC TRIO_CONST char *trio_error TRIO_PROTO((int));
TRIO_STRING_PUBLIC size_t trio_length TRIO_PROTO((const char *string));
TRIO_STRING_PUBLIC double trio_to_double TRIO_PROTO((const char *source, char **endp));
TRIO_STRING_PUBLIC long trio_to_long TRIO_PROTO((const char *source, char **endp, int base));
TRIO_STRING_PUBLIC trio_long_double_t trio_to_long_double TRIO_PROTO((const char *source, char **endp));
TRIO_STRING_PUBLIC int trio_to_upper TRIO_PROTO((int source));

#if !defined(TRIO_MINIMAL)

TRIO_STRING_PUBLIC int trio_append TRIO_PROTO((char *target, const char *source));
TRIO_STRING_PUBLIC int trio_append_max TRIO_PROTO((char *target, size_t max, const char *source));
TRIO_STRING_PUBLIC int trio_contains TRIO_PROTO((const char *string, const char *substring));
TRIO_STRING_PUBLIC int trio_copy TRIO_PROTO((char *target, const char *source));
TRIO_STRING_PUBLIC char *trio_duplicate_max TRIO_PROTO((const char *source, size_t max));
TRIO_STRING_PUBLIC int trio_equal_case_max TRIO_PROTO((const char *first, size_t max, const char *second));
#if !defined(_WIN32_WCE)
TRIO_STRING_PUBLIC size_t trio_format_date_max TRIO_PROTO((char *target, size_t max, const char *format, const struct tm *datetime));
#endif
TRIO_STRING_PUBLIC unsigned long trio_hash TRIO_PROTO((const char *string, int type));
TRIO_STRING_PUBLIC char *trio_index TRIO_PROTO((const char *string, int character));
TRIO_STRING_PUBLIC char *trio_index_last TRIO_PROTO((const char *string, int character));
TRIO_STRING_PUBLIC int trio_lower TRIO_PROTO((char *target));
TRIO_STRING_PUBLIC int trio_match TRIO_PROTO((const char *string, const char *pattern));
TRIO_STRING_PUBLIC int trio_match_case TRIO_PROTO((const char *string, const char *pattern));
TRIO_STRING_PUBLIC size_t trio_span_function TRIO_PROTO((char *target, const char *source, int (*Function) TRIO_PROTO((int))));
TRIO_STRING_PUBLIC char *trio_substring TRIO_PROTO((const char *string, const char *substring));
TRIO_STRING_PUBLIC char *trio_substring_max TRIO_PROTO((const char *string, size_t max, const char *substring));
TRIO_STRING_PUBLIC float trio_to_float TRIO_PROTO((const char *source, char **endp));
TRIO_STRING_PUBLIC int trio_to_lower TRIO_PROTO((int source));
TRIO_STRING_PUBLIC unsigned long trio_to_unsigned_long TRIO_PROTO((const char *source, char **endp, int base));
TRIO_STRING_PUBLIC char *trio_tokenize TRIO_PROTO((char *string, const char *delimiters));
TRIO_STRING_PUBLIC int trio_upper TRIO_PROTO((char *target));

#endif /* !defined(TRIO_MINIMAL) */

/*************************************************************************
 * Dynamic string functions
 */

/*
 * Opaque type for dynamic strings
 */

typedef struct _trio_string_t trio_string_t;

TRIO_STRING_PUBLIC void trio_string_destroy TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC char *trio_string_extract TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC int trio_string_size TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC void trio_string_terminate TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC int trio_xstring_append_char TRIO_PROTO((trio_string_t *self, char character));
TRIO_STRING_PUBLIC trio_string_t *trio_xstring_duplicate TRIO_PROTO((const char *other));

#if !defined(TRIO_MINIMAL)

TRIO_STRING_PUBLIC trio_string_t *trio_string_create TRIO_PROTO((int initial_size));
TRIO_STRING_PUBLIC char *trio_string_get TRIO_PROTO((trio_string_t *self, int offset));
TRIO_STRING_PUBLIC void trio_xstring_set TRIO_PROTO((trio_string_t *self, char *buffer));

TRIO_STRING_PUBLIC int trio_string_append TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_contains TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_copy TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC trio_string_t *trio_string_duplicate TRIO_PROTO((trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_equal TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_equal_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *second));
TRIO_STRING_PUBLIC int trio_string_equal_case TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *other));
#if !defined(_WIN32_WCE)
TRIO_STRING_PUBLIC size_t trio_string_format_date_max TRIO_PROTO((trio_string_t *self, size_t max, const char *format, const struct tm *datetime));
#endif
TRIO_STRING_PUBLIC char *trio_string_index TRIO_PROTO((trio_string_t *self, int character));
TRIO_STRING_PUBLIC char *trio_string_index_last TRIO_PROTO((trio_string_t *self, int character));
TRIO_STRING_PUBLIC int trio_string_length TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC int trio_string_lower TRIO_PROTO((trio_string_t *self));
TRIO_STRING_PUBLIC int trio_string_match TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_match_case TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC char *trio_string_substring TRIO_PROTO((trio_string_t *self, trio_string_t *other));
TRIO_STRING_PUBLIC int trio_string_upper TRIO_PROTO((trio_string_t *self));

TRIO_STRING_PUBLIC int trio_xstring_append TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_contains TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_copy TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_equal TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_equal_max TRIO_PROTO((trio_string_t *self, size_t max, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_equal_case TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_match TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC int trio_xstring_match_case TRIO_PROTO((trio_string_t *self, const char *other));
TRIO_STRING_PUBLIC char *trio_xstring_substring TRIO_PROTO((trio_string_t *self, const char *other));

#endif /* !defined(TRIO_MINIMAL) */

#endif /* TRIO_TRIOSTR_H */