Edit

kc3-lang/libxml2/triostr.c

Branch :

  • Show log

    Commit

  • Author : Jacob (Jouk) Jansen
    Date : 2013-12-17 15:32:57
    Hash : 4d041a2e
    Message : Various portability patches for OpenVMS Available from http://nchrem.tnw.tudelft.nl/openvms/software2.html

  • triostr.c
  • /*************************************************************************
     *
     * $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
    
    #ifdef __VMS
    # define USE_STRTOD
    #elif 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
    #elif defined(TRIO_PLATFORM_OS400)
    # define USE_STRCASECMP
    # define USE_STRNCASECMP
    # include <strings.h>
    #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 */