aboutsummaryrefslogtreecommitdiffstats
path: root/trio/triostr.c
diff options
context:
space:
mode:
authorMatthias Andree <matthias.andree@gmx.de>2004-11-10 19:04:29 +0000
committerMatthias Andree <matthias.andree@gmx.de>2004-11-10 19:04:29 +0000
commit13c27199231cbc2cc83969ada741b95be1cca4d3 (patch)
tree58c32705247dcf031d6f17d8bc8ef78557d74113 /trio/triostr.c
parent486bdc6d20c7e7d8c6eeb3124cf845abefcd7d11 (diff)
downloadfetchmail-13c27199231cbc2cc83969ada741b95be1cca4d3.tar.gz
fetchmail-13c27199231cbc2cc83969ada741b95be1cca4d3.tar.bz2
fetchmail-13c27199231cbc2cc83969ada741b95be1cca4d3.zip
Import Trio 1.10 into fetchmail's trunk.
svn path=/trunk/; revision=3995
Diffstat (limited to 'trio/triostr.c')
-rw-r--r--trio/triostr.c2102
1 files changed, 2102 insertions, 0 deletions
diff --git a/trio/triostr.c b/trio/triostr.c
new file mode 100644
index 00000000..199429e4
--- /dev/null
+++ b/trio/triostr.c
@@ -0,0 +1,2102 @@
+/*************************************************************************
+ *
+ * $Id: triostr.c,v 1.19 2003/03/01 15:34:02 breese Exp $
+ *
+ * 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
+# define strcasecmp(x,y) strcmpi(x,y)
+#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: triostr.c,v 1.19 2003/03/01 15:34:02 breese Exp $";
+#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)
+/**
+ 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)
+/*
+ * 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 */