|  | /************************************************************************* | 
|  | * | 
|  | * $Id$ | 
|  | * | 
|  | * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg. | 
|  | * | 
|  | * Permission to use, copy, modify, and distribute this software for any | 
|  | * purpose with or without fee is hereby granted, provided that the above | 
|  | * copyright notice and this permission notice appear in all copies. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | 
|  | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 
|  | * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND | 
|  | * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. | 
|  | * | 
|  | ************************************************************************/ | 
|  |  | 
|  | /************************************************************************* | 
|  | * Include files | 
|  | */ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <ctype.h> | 
|  | #include <math.h> | 
|  | #include "triodef.h" | 
|  | #include "triostr.h" | 
|  |  | 
|  | /************************************************************************* | 
|  | * Definitions | 
|  | */ | 
|  |  | 
|  | #if !defined(TRIO_STRING_PUBLIC) | 
|  | # define TRIO_STRING_PUBLIC TRIO_PUBLIC | 
|  | #endif | 
|  | #if !defined(TRIO_STRING_PRIVATE) | 
|  | # define TRIO_STRING_PRIVATE TRIO_PRIVATE | 
|  | #endif | 
|  |  | 
|  | #if !defined(NULL) | 
|  | # define NULL 0 | 
|  | #endif | 
|  | #if !defined(NIL) | 
|  | # define NIL ((char)0) | 
|  | #endif | 
|  | #if !defined(FALSE) | 
|  | # define FALSE (1 == 0) | 
|  | # define TRUE (! FALSE) | 
|  | #endif | 
|  | #if !defined(BOOLEAN_T) | 
|  | # define BOOLEAN_T int | 
|  | #endif | 
|  |  | 
|  | #if defined(TRIO_COMPILER_SUPPORTS_C99) | 
|  | # define USE_STRTOD | 
|  | # define USE_STRTOF | 
|  | #elif defined(TRIO_COMPILER_MSVC) | 
|  | # define USE_STRTOD | 
|  | #endif | 
|  |  | 
|  | #if defined(TRIO_PLATFORM_UNIX) | 
|  | # define USE_STRCASECMP | 
|  | # define USE_STRNCASECMP | 
|  | # if defined(TRIO_PLATFORM_SUNOS) | 
|  | #  define USE_SYS_ERRLIST | 
|  | # else | 
|  | #  define USE_STRERROR | 
|  | # endif | 
|  | # if defined(TRIO_PLATFORM_QNX) | 
|  | #  define strcasecmp(x,y) stricmp(x,y) | 
|  | #  define strncasecmp(x,y,n) strnicmp(x,y,n) | 
|  | # endif | 
|  | #elif defined(TRIO_PLATFORM_WIN32) | 
|  | # define USE_STRCASECMP | 
|  | # if defined(_WIN32_WCE) | 
|  | #  define strcasecmp(x,y) _stricmp(x,y) | 
|  | # else | 
|  | #  define strcasecmp(x,y) strcmpi(x,y) | 
|  | # endif | 
|  | #endif | 
|  |  | 
|  | #if !(defined(TRIO_PLATFORM_SUNOS)) | 
|  | # define USE_TOLOWER | 
|  | # define USE_TOUPPER | 
|  | #endif | 
|  |  | 
|  | /************************************************************************* | 
|  | * Structures | 
|  | */ | 
|  |  | 
|  | struct _trio_string_t | 
|  | { | 
|  | char *content; | 
|  | size_t length; | 
|  | size_t allocated; | 
|  | }; | 
|  |  | 
|  | /************************************************************************* | 
|  | * Constants | 
|  | */ | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | static TRIO_CONST char rcsid[] = "@(#)$Id$"; | 
|  | #endif | 
|  |  | 
|  | /************************************************************************* | 
|  | * Static String Functions | 
|  | */ | 
|  |  | 
|  | #if defined(TRIO_DOCUMENTATION) | 
|  | # include "doc/doc_static.h" | 
|  | #endif | 
|  | /** @addtogroup StaticStrings | 
|  | @{ | 
|  | */ | 
|  |  | 
|  | /** | 
|  | Create new string. | 
|  |  | 
|  | @param size Size of new string. | 
|  | @return Pointer to string, or NULL if allocation failed. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_create | 
|  | TRIO_ARGS1((size), | 
|  | size_t size) | 
|  | { | 
|  | return (char *)TRIO_MALLOC(size); | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Destroy string. | 
|  |  | 
|  | @param string String to be freed. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC void | 
|  | trio_destroy | 
|  | TRIO_ARGS1((string), | 
|  | char *string) | 
|  | { | 
|  | if (string) | 
|  | { | 
|  | TRIO_FREE(string); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Count the number of characters in a string. | 
|  |  | 
|  | @param string String to measure. | 
|  | @return Number of characters in @string. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC size_t | 
|  | trio_length | 
|  | TRIO_ARGS1((string), | 
|  | TRIO_CONST char *string) | 
|  | { | 
|  | return strlen(string); | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Append @p source at the end of @p target. | 
|  |  | 
|  | @param target Target string. | 
|  | @param source Source string. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | @pre @p target must point to a memory chunk with sufficient room to | 
|  | contain the @p target string and @p source string. | 
|  | @pre No boundary checking is performed, so insufficient memory will | 
|  | result in a buffer overrun. | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_append | 
|  | TRIO_ARGS2((target, source), | 
|  | char *target, | 
|  | TRIO_CONST char *source) | 
|  | { | 
|  | assert(target); | 
|  | assert(source); | 
|  |  | 
|  | return (strcat(target, source) != NULL); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Append at most @p max characters from @p source to @p target. | 
|  |  | 
|  | @param target Target string. | 
|  | @param max Maximum number of characters to append. | 
|  | @param source Source string. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | @pre @p target must point to a memory chuck with sufficient room to | 
|  | contain the @p target string and the @p source string (at most @p max | 
|  | characters). | 
|  | @pre No boundary checking is performed, so insufficient memory will | 
|  | result in a buffer overrun. | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_append_max | 
|  | TRIO_ARGS3((target, max, source), | 
|  | char *target, | 
|  | size_t max, | 
|  | TRIO_CONST char *source) | 
|  | { | 
|  | size_t length; | 
|  |  | 
|  | assert(target); | 
|  | assert(source); | 
|  |  | 
|  | length = trio_length(target); | 
|  |  | 
|  | if (max > length) | 
|  | { | 
|  | strncat(target, source, max - length - 1); | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Determine if a string contains a substring. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param substring String to be found. | 
|  | @return Boolean value indicating success or failure. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_contains | 
|  | TRIO_ARGS2((string, substring), | 
|  | TRIO_CONST char *string, | 
|  | TRIO_CONST char *substring) | 
|  | { | 
|  | assert(string); | 
|  | assert(substring); | 
|  |  | 
|  | return (0 != strstr(string, substring)); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Copy @p source to @p target. | 
|  |  | 
|  | @param target Target string. | 
|  | @param source Source string. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | @pre @p target must point to a memory chunk with sufficient room to | 
|  | contain the @p source string. | 
|  | @pre No boundary checking is performed, so insufficient memory will | 
|  | result in a buffer overrun. | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_copy | 
|  | TRIO_ARGS2((target, source), | 
|  | char *target, | 
|  | TRIO_CONST char *source) | 
|  | { | 
|  | assert(target); | 
|  | assert(source); | 
|  |  | 
|  | (void)strcpy(target, source); | 
|  | return TRUE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Copy at most @p max characters from @p source to @p target. | 
|  |  | 
|  | @param target Target string. | 
|  | @param max Maximum number of characters to append. | 
|  | @param source Source string. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | @pre @p target must point to a memory chunk with sufficient room to | 
|  | contain the @p source string (at most @p max characters). | 
|  | @pre No boundary checking is performed, so insufficient memory will | 
|  | result in a buffer overrun. | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_copy_max | 
|  | TRIO_ARGS3((target, max, source), | 
|  | char *target, | 
|  | size_t max, | 
|  | TRIO_CONST char *source) | 
|  | { | 
|  | assert(target); | 
|  | assert(source); | 
|  | assert(max > 0); /* Includes != 0 */ | 
|  |  | 
|  | (void)strncpy(target, source, max - 1); | 
|  | target[max - 1] = (char)0; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * TrioDuplicateMax | 
|  | */ | 
|  | TRIO_STRING_PRIVATE char * | 
|  | TrioDuplicateMax | 
|  | TRIO_ARGS2((source, size), | 
|  | TRIO_CONST char *source, | 
|  | size_t size) | 
|  | { | 
|  | char *target; | 
|  |  | 
|  | assert(source); | 
|  |  | 
|  | /* Make room for string plus a terminating zero */ | 
|  | size++; | 
|  | target = trio_create(size); | 
|  | if (target) | 
|  | { | 
|  | trio_copy_max(target, size, source); | 
|  | } | 
|  | return target; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Duplicate @p source. | 
|  |  | 
|  | @param source Source string. | 
|  | @return A copy of the @p source string. | 
|  |  | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_duplicate | 
|  | TRIO_ARGS1((source), | 
|  | TRIO_CONST char *source) | 
|  | { | 
|  | return TrioDuplicateMax(source, trio_length(source)); | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Duplicate at most @p max characters of @p source. | 
|  |  | 
|  | @param source Source string. | 
|  | @param max Maximum number of characters to duplicate. | 
|  | @return A copy of the @p source string. | 
|  |  | 
|  | @post @p target will be zero terminated. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_duplicate_max TRIO_ARGS2((source, max), | 
|  | TRIO_CONST char *source, | 
|  | size_t max) | 
|  | { | 
|  | size_t length; | 
|  |  | 
|  | assert(source); | 
|  | assert(max > 0); | 
|  |  | 
|  | length = trio_length(source); | 
|  | if (length > max) | 
|  | { | 
|  | length = max; | 
|  | } | 
|  | return TrioDuplicateMax(source, length); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Compare if two strings are equal. | 
|  |  | 
|  | @param first First string. | 
|  | @param second Second string. | 
|  | @return Boolean indicating whether the two strings are equal or not. | 
|  |  | 
|  | Case-insensitive comparison. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_equal | 
|  | TRIO_ARGS2((first, second), | 
|  | TRIO_CONST char *first, | 
|  | TRIO_CONST char *second) | 
|  | { | 
|  | assert(first); | 
|  | assert(second); | 
|  |  | 
|  | if ((first != NULL) && (second != NULL)) | 
|  | { | 
|  | #if defined(USE_STRCASECMP) | 
|  | return (0 == strcasecmp(first, second)); | 
|  | #else | 
|  | while ((*first != NIL) && (*second != NIL)) | 
|  | { | 
|  | if (trio_to_upper(*first) != trio_to_upper(*second)) | 
|  | { | 
|  | break; | 
|  | } | 
|  | first++; | 
|  | second++; | 
|  | } | 
|  | return ((*first == NIL) && (*second == NIL)); | 
|  | #endif | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Compare if two strings are equal. | 
|  |  | 
|  | @param first First string. | 
|  | @param second Second string. | 
|  | @return Boolean indicating whether the two strings are equal or not. | 
|  |  | 
|  | Case-sensitive comparison. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_equal_case | 
|  | TRIO_ARGS2((first, second), | 
|  | TRIO_CONST char *first, | 
|  | TRIO_CONST char *second) | 
|  | { | 
|  | assert(first); | 
|  | assert(second); | 
|  |  | 
|  | if ((first != NULL) && (second != NULL)) | 
|  | { | 
|  | return (0 == strcmp(first, second)); | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Compare if two strings up until the first @p max characters are equal. | 
|  |  | 
|  | @param first First string. | 
|  | @param max Maximum number of characters to compare. | 
|  | @param second Second string. | 
|  | @return Boolean indicating whether the two strings are equal or not. | 
|  |  | 
|  | Case-sensitive comparison. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_equal_case_max | 
|  | TRIO_ARGS3((first, max, second), | 
|  | TRIO_CONST char *first, | 
|  | size_t max, | 
|  | TRIO_CONST char *second) | 
|  | { | 
|  | assert(first); | 
|  | assert(second); | 
|  |  | 
|  | if ((first != NULL) && (second != NULL)) | 
|  | { | 
|  | return (0 == strncmp(first, second, max)); | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Compare if two strings are equal. | 
|  |  | 
|  | @param first First string. | 
|  | @param second Second string. | 
|  | @return Boolean indicating whether the two strings are equal or not. | 
|  |  | 
|  | Collating characters are considered equal. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_equal_locale | 
|  | TRIO_ARGS2((first, second), | 
|  | TRIO_CONST char *first, | 
|  | TRIO_CONST char *second) | 
|  | { | 
|  | assert(first); | 
|  | assert(second); | 
|  |  | 
|  | #if defined(LC_COLLATE) | 
|  | return (strcoll(first, second) == 0); | 
|  | #else | 
|  | return trio_equal(first, second); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Compare if two strings up until the first @p max characters are equal. | 
|  |  | 
|  | @param first First string. | 
|  | @param max Maximum number of characters to compare. | 
|  | @param second Second string. | 
|  | @return Boolean indicating whether the two strings are equal or not. | 
|  |  | 
|  | Case-insensitive comparison. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_equal_max | 
|  | TRIO_ARGS3((first, max, second), | 
|  | TRIO_CONST char *first, | 
|  | size_t max, | 
|  | TRIO_CONST char *second) | 
|  | { | 
|  | assert(first); | 
|  | assert(second); | 
|  |  | 
|  | if ((first != NULL) && (second != NULL)) | 
|  | { | 
|  | #if defined(USE_STRNCASECMP) | 
|  | return (0 == strncasecmp(first, second, max)); | 
|  | #else | 
|  | /* Not adequately tested yet */ | 
|  | size_t cnt = 0; | 
|  | while ((*first != NIL) && (*second != NIL) && (cnt <= max)) | 
|  | { | 
|  | if (trio_to_upper(*first) != trio_to_upper(*second)) | 
|  | { | 
|  | break; | 
|  | } | 
|  | first++; | 
|  | second++; | 
|  | cnt++; | 
|  | } | 
|  | return ((cnt == max) || ((*first == NIL) && (*second == NIL))); | 
|  | #endif | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Provide a textual description of an error code (errno). | 
|  |  | 
|  | @param error_number Error number. | 
|  | @return Textual description of @p error_number. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC TRIO_CONST char * | 
|  | trio_error | 
|  | TRIO_ARGS1((error_number), | 
|  | int error_number) | 
|  | { | 
|  | #if defined(USE_STRERROR) | 
|  |  | 
|  | return strerror(error_number); | 
|  |  | 
|  | #elif defined(USE_SYS_ERRLIST) | 
|  |  | 
|  | extern char *sys_errlist[]; | 
|  | extern int sys_nerr; | 
|  |  | 
|  | return ((error_number < 0) || (error_number >= sys_nerr)) | 
|  | ? "unknown" | 
|  | : sys_errlist[error_number]; | 
|  |  | 
|  | #else | 
|  |  | 
|  | return "unknown"; | 
|  |  | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE) | 
|  | /** | 
|  | Format the date/time according to @p format. | 
|  |  | 
|  | @param target Target string. | 
|  | @param max Maximum number of characters to format. | 
|  | @param format Formatting string. | 
|  | @param datetime Date/time structure. | 
|  | @return Number of formatted characters. | 
|  |  | 
|  | The formatting string accepts the same specifiers as the standard C | 
|  | function strftime. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC size_t | 
|  | trio_format_date_max | 
|  | TRIO_ARGS4((target, max, format, datetime), | 
|  | char *target, | 
|  | size_t max, | 
|  | TRIO_CONST char *format, | 
|  | TRIO_CONST struct tm *datetime) | 
|  | { | 
|  | assert(target); | 
|  | assert(format); | 
|  | assert(datetime); | 
|  | assert(max > 0); | 
|  |  | 
|  | return strftime(target, max, format, datetime); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Calculate a hash value for a string. | 
|  |  | 
|  | @param string String to be calculated on. | 
|  | @param type Hash function. | 
|  | @return Calculated hash value. | 
|  |  | 
|  | @p type can be one of the following | 
|  | @li @c TRIO_HASH_PLAIN Plain hash function. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC unsigned long | 
|  | trio_hash | 
|  | TRIO_ARGS2((string, type), | 
|  | TRIO_CONST char *string, | 
|  | int type) | 
|  | { | 
|  | unsigned long value = 0L; | 
|  | char ch; | 
|  |  | 
|  | assert(string); | 
|  |  | 
|  | switch (type) | 
|  | { | 
|  | case TRIO_HASH_PLAIN: | 
|  | while ( (ch = *string++) != NIL ) | 
|  | { | 
|  | value *= 31; | 
|  | value += (unsigned long)ch; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | assert(FALSE); | 
|  | break; | 
|  | } | 
|  | return value; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Find first occurrence of a character in a string. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param character Character to be found. | 
|  | @param A pointer to the found character, or NULL if character was not found. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_index | 
|  | TRIO_ARGS2((string, character), | 
|  | TRIO_CONST char *string, | 
|  | int character) | 
|  | { | 
|  | assert(string); | 
|  |  | 
|  | return strchr(string, character); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Find last occurrence of a character in a string. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param character Character to be found. | 
|  | @param A pointer to the found character, or NULL if character was not found. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_index_last | 
|  | TRIO_ARGS2((string, character), | 
|  | TRIO_CONST char *string, | 
|  | int character) | 
|  | { | 
|  | assert(string); | 
|  |  | 
|  | return strchr(string, character); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Convert the alphabetic letters in the string to lower-case. | 
|  |  | 
|  | @param target String to be converted. | 
|  | @return Number of processed characters (converted or not). | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_lower | 
|  | TRIO_ARGS1((target), | 
|  | char *target) | 
|  | { | 
|  | assert(target); | 
|  |  | 
|  | return trio_span_function(target, target, trio_to_lower); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Compare two strings using wildcards. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param pattern Pattern, including wildcards, to search for. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | Case-insensitive comparison. | 
|  |  | 
|  | The following wildcards can be used | 
|  | @li @c * Match any number of characters. | 
|  | @li @c ? Match a single character. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_match | 
|  | TRIO_ARGS2((string, pattern), | 
|  | TRIO_CONST char *string, | 
|  | TRIO_CONST char *pattern) | 
|  | { | 
|  | assert(string); | 
|  | assert(pattern); | 
|  |  | 
|  | for (; ('*' != *pattern); ++pattern, ++string) | 
|  | { | 
|  | if (NIL == *string) | 
|  | { | 
|  | return (NIL == *pattern); | 
|  | } | 
|  | if ((trio_to_upper((int)*string) != trio_to_upper((int)*pattern)) | 
|  | && ('?' != *pattern)) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  | /* two-line patch to prevent *too* much recursiveness: */ | 
|  | while ('*' == pattern[1]) | 
|  | pattern++; | 
|  |  | 
|  | do | 
|  | { | 
|  | if ( trio_match(string, &pattern[1]) ) | 
|  | { | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  | while (*string++); | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Compare two strings using wildcards. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param pattern Pattern, including wildcards, to search for. | 
|  | @return Boolean value indicating success or failure. | 
|  |  | 
|  | Case-sensitive comparison. | 
|  |  | 
|  | The following wildcards can be used | 
|  | @li @c * Match any number of characters. | 
|  | @li @c ? Match a single character. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_match_case | 
|  | TRIO_ARGS2((string, pattern), | 
|  | TRIO_CONST char *string, | 
|  | TRIO_CONST char *pattern) | 
|  | { | 
|  | assert(string); | 
|  | assert(pattern); | 
|  |  | 
|  | for (; ('*' != *pattern); ++pattern, ++string) | 
|  | { | 
|  | if (NIL == *string) | 
|  | { | 
|  | return (NIL == *pattern); | 
|  | } | 
|  | if ((*string != *pattern) | 
|  | && ('?' != *pattern)) | 
|  | { | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  | /* two-line patch to prevent *too* much recursiveness: */ | 
|  | while ('*' == pattern[1]) | 
|  | pattern++; | 
|  |  | 
|  | do | 
|  | { | 
|  | if ( trio_match_case(string, &pattern[1]) ) | 
|  | { | 
|  | return TRUE; | 
|  | } | 
|  | } | 
|  | while (*string++); | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Execute a function on each character in string. | 
|  |  | 
|  | @param target Target string. | 
|  | @param source Source string. | 
|  | @param Function Function to be executed. | 
|  | @return Number of processed characters. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC size_t | 
|  | trio_span_function | 
|  | TRIO_ARGS3((target, source, Function), | 
|  | char *target, | 
|  | TRIO_CONST char *source, | 
|  | int (*Function) TRIO_PROTO((int))) | 
|  | { | 
|  | size_t count = 0; | 
|  |  | 
|  | assert(target); | 
|  | assert(source); | 
|  | assert(Function); | 
|  |  | 
|  | while (*source != NIL) | 
|  | { | 
|  | *target++ = Function(*source++); | 
|  | count++; | 
|  | } | 
|  | return count; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Search for a substring in a string. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param substring String to be found. | 
|  | @return Pointer to first occurrence of @p substring in @p string, or NULL | 
|  | if no match was found. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_substring | 
|  | TRIO_ARGS2((string, substring), | 
|  | TRIO_CONST char *string, | 
|  | TRIO_CONST char *substring) | 
|  | { | 
|  | assert(string); | 
|  | assert(substring); | 
|  |  | 
|  | return strstr(string, substring); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Search for a substring in the first @p max characters of a string. | 
|  |  | 
|  | @param string String to be searched. | 
|  | @param max Maximum characters to be searched. | 
|  | @param substring String to be found. | 
|  | @return Pointer to first occurrence of @p substring in @p string, or NULL | 
|  | if no match was found. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_substring_max | 
|  | TRIO_ARGS3((string, max, substring), | 
|  | TRIO_CONST char *string, | 
|  | size_t max, | 
|  | TRIO_CONST char *substring) | 
|  | { | 
|  | size_t count; | 
|  | size_t size; | 
|  | char *result = NULL; | 
|  |  | 
|  | assert(string); | 
|  | assert(substring); | 
|  |  | 
|  | size = trio_length(substring); | 
|  | if (size <= max) | 
|  | { | 
|  | for (count = 0; count <= max - size; count++) | 
|  | { | 
|  | if (trio_equal_max(substring, size, &string[count])) | 
|  | { | 
|  | result = (char *)&string[count]; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Tokenize string. | 
|  |  | 
|  | @param string String to be tokenized. | 
|  | @param tokens String containing list of delimiting characters. | 
|  | @return Start of new token. | 
|  |  | 
|  | @warning @p string will be destroyed. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_tokenize | 
|  | TRIO_ARGS2((string, delimiters), | 
|  | char *string, | 
|  | TRIO_CONST char *delimiters) | 
|  | { | 
|  | assert(delimiters); | 
|  |  | 
|  | return strtok(string, delimiters); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Convert string to floating-point number. | 
|  |  | 
|  | @param source String to be converted. | 
|  | @param endp Pointer to end of the converted string. | 
|  | @return A floating-point number. | 
|  |  | 
|  | The following Extended Backus-Naur form is used | 
|  | @verbatim | 
|  | double        ::= [ <sign> ] | 
|  | ( <number> | | 
|  | <number> <decimal_point> <number> | | 
|  | <decimal_point> <number> ) | 
|  | [ <exponential> [ <sign> ] <number> ] | 
|  | number        ::= 1*( <digit> ) | 
|  | digit         ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) | 
|  | exponential   ::= ( 'e' | 'E' ) | 
|  | sign          ::= ( '-' | '+' ) | 
|  | decimal_point ::= '.' | 
|  | @endverbatim | 
|  | */ | 
|  | /* FIXME: Add EBNF for hex-floats */ | 
|  | TRIO_STRING_PUBLIC trio_long_double_t | 
|  | trio_to_long_double | 
|  | TRIO_ARGS2((source, endp), | 
|  | TRIO_CONST char *source, | 
|  | char **endp) | 
|  | { | 
|  | #if defined(USE_STRTOLD) | 
|  | return strtold(source, endp); | 
|  | #else | 
|  | int isNegative = FALSE; | 
|  | int isExponentNegative = FALSE; | 
|  | trio_long_double_t integer = 0.0; | 
|  | trio_long_double_t fraction = 0.0; | 
|  | unsigned long exponent = 0; | 
|  | trio_long_double_t base; | 
|  | trio_long_double_t fracdiv = 1.0; | 
|  | trio_long_double_t value = 0.0; | 
|  |  | 
|  | /* First try hex-floats */ | 
|  | if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X'))) | 
|  | { | 
|  | base = 16.0; | 
|  | source += 2; | 
|  | while (isxdigit((int)*source)) | 
|  | { | 
|  | integer *= base; | 
|  | integer += (isdigit((int)*source) | 
|  | ? (*source - '0') | 
|  | : 10 + (trio_to_upper((int)*source) - 'A')); | 
|  | source++; | 
|  | } | 
|  | if (*source == '.') | 
|  | { | 
|  | source++; | 
|  | while (isxdigit((int)*source)) | 
|  | { | 
|  | fracdiv /= base; | 
|  | fraction += fracdiv * (isdigit((int)*source) | 
|  | ? (*source - '0') | 
|  | : 10 + (trio_to_upper((int)*source) - 'A')); | 
|  | source++; | 
|  | } | 
|  | if ((*source == 'p') || (*source == 'P')) | 
|  | { | 
|  | source++; | 
|  | if ((*source == '+') || (*source == '-')) | 
|  | { | 
|  | isExponentNegative = (*source == '-'); | 
|  | source++; | 
|  | } | 
|  | while (isdigit((int)*source)) | 
|  | { | 
|  | exponent *= 10; | 
|  | exponent += (*source - '0'); | 
|  | source++; | 
|  | } | 
|  | } | 
|  | } | 
|  | /* For later use with exponent */ | 
|  | base = 2.0; | 
|  | } | 
|  | else /* Then try normal decimal floats */ | 
|  | { | 
|  | base = 10.0; | 
|  | isNegative = (*source == '-'); | 
|  | /* Skip sign */ | 
|  | if ((*source == '+') || (*source == '-')) | 
|  | source++; | 
|  |  | 
|  | /* Integer part */ | 
|  | while (isdigit((int)*source)) | 
|  | { | 
|  | integer *= base; | 
|  | integer += (*source - '0'); | 
|  | source++; | 
|  | } | 
|  |  | 
|  | if (*source == '.') | 
|  | { | 
|  | source++; /* skip decimal point */ | 
|  | while (isdigit((int)*source)) | 
|  | { | 
|  | fracdiv /= base; | 
|  | fraction += (*source - '0') * fracdiv; | 
|  | source++; | 
|  | } | 
|  | } | 
|  | if ((*source == 'e') | 
|  | || (*source == 'E') | 
|  | #if TRIO_MICROSOFT | 
|  | || (*source == 'd') | 
|  | || (*source == 'D') | 
|  | #endif | 
|  | ) | 
|  | { | 
|  | source++; /* Skip exponential indicator */ | 
|  | isExponentNegative = (*source == '-'); | 
|  | if ((*source == '+') || (*source == '-')) | 
|  | source++; | 
|  | while (isdigit((int)*source)) | 
|  | { | 
|  | exponent *= (int)base; | 
|  | exponent += (*source - '0'); | 
|  | source++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | value = integer + fraction; | 
|  | if (exponent != 0) | 
|  | { | 
|  | if (isExponentNegative) | 
|  | value /= pow(base, (double)exponent); | 
|  | else | 
|  | value *= pow(base, (double)exponent); | 
|  | } | 
|  | if (isNegative) | 
|  | value = -value; | 
|  |  | 
|  | if (endp) | 
|  | *endp = (char *)source; | 
|  | return value; | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | /** | 
|  | Convert string to floating-point number. | 
|  |  | 
|  | @param source String to be converted. | 
|  | @param endp Pointer to end of the converted string. | 
|  | @return A floating-point number. | 
|  |  | 
|  | See @ref trio_to_long_double. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC double | 
|  | trio_to_double | 
|  | TRIO_ARGS2((source, endp), | 
|  | TRIO_CONST char *source, | 
|  | char **endp) | 
|  | { | 
|  | #if defined(USE_STRTOD) | 
|  | return strtod(source, endp); | 
|  | #else | 
|  | return (double)trio_to_long_double(source, endp); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Convert string to floating-point number. | 
|  |  | 
|  | @param source String to be converted. | 
|  | @param endp Pointer to end of the converted string. | 
|  | @return A floating-point number. | 
|  |  | 
|  | See @ref trio_to_long_double. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC float | 
|  | trio_to_float | 
|  | TRIO_ARGS2((source, endp), | 
|  | TRIO_CONST char *source, | 
|  | char **endp) | 
|  | { | 
|  | #if defined(USE_STRTOF) | 
|  | return strtof(source, endp); | 
|  | #else | 
|  | return (float)trio_to_long_double(source, endp); | 
|  | #endif | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Convert string to signed integer. | 
|  |  | 
|  | @param string String to be converted. | 
|  | @param endp Pointer to end of converted string. | 
|  | @param base Radix number of number. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC long | 
|  | trio_to_long | 
|  | TRIO_ARGS3((string, endp, base), | 
|  | TRIO_CONST char *string, | 
|  | char **endp, | 
|  | int base) | 
|  | { | 
|  | assert(string); | 
|  | assert((base >= 2) && (base <= 36)); | 
|  |  | 
|  | return strtol(string, endp, base); | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Convert one alphabetic letter to lower-case. | 
|  |  | 
|  | @param source The letter to be converted. | 
|  | @return The converted letter. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_to_lower | 
|  | TRIO_ARGS1((source), | 
|  | int source) | 
|  | { | 
|  | #if defined(USE_TOLOWER) | 
|  |  | 
|  | return tolower(source); | 
|  |  | 
|  | #else | 
|  |  | 
|  | /* Does not handle locales or non-contiguous alphabetic characters */ | 
|  | return ((source >= (int)'A') && (source <= (int)'Z')) | 
|  | ? source - 'A' + 'a' | 
|  | : source; | 
|  |  | 
|  | #endif | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Convert string to unsigned integer. | 
|  |  | 
|  | @param string String to be converted. | 
|  | @param endp Pointer to end of converted string. | 
|  | @param base Radix number of number. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC unsigned long | 
|  | trio_to_unsigned_long | 
|  | TRIO_ARGS3((string, endp, base), | 
|  | TRIO_CONST char *string, | 
|  | char **endp, | 
|  | int base) | 
|  | { | 
|  | assert(string); | 
|  | assert((base >= 2) && (base <= 36)); | 
|  |  | 
|  | return strtoul(string, endp, base); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Convert one alphabetic letter to upper-case. | 
|  |  | 
|  | @param source The letter to be converted. | 
|  | @return The converted letter. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_to_upper | 
|  | TRIO_ARGS1((source), | 
|  | int source) | 
|  | { | 
|  | #if defined(USE_TOUPPER) | 
|  |  | 
|  | return toupper(source); | 
|  |  | 
|  | #else | 
|  |  | 
|  | /* Does not handle locales or non-contiguous alphabetic characters */ | 
|  | return ((source >= (int)'a') && (source <= (int)'z')) | 
|  | ? source - 'a' + 'A' | 
|  | : source; | 
|  |  | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Convert the alphabetic letters in the string to upper-case. | 
|  |  | 
|  | @param target The string to be converted. | 
|  | @return The number of processed characters (converted or not). | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_upper | 
|  | TRIO_ARGS1((target), | 
|  | char *target) | 
|  | { | 
|  | assert(target); | 
|  |  | 
|  | return trio_span_function(target, target, trio_to_upper); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** @} End of StaticStrings */ | 
|  |  | 
|  |  | 
|  | /************************************************************************* | 
|  | * Dynamic String Functions | 
|  | */ | 
|  |  | 
|  | #if defined(TRIO_DOCUMENTATION) | 
|  | # include "doc/doc_dynamic.h" | 
|  | #endif | 
|  | /** @addtogroup DynamicStrings | 
|  | @{ | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * TrioStringAlloc | 
|  | */ | 
|  | TRIO_STRING_PRIVATE trio_string_t * | 
|  | TrioStringAlloc(TRIO_NOARGS) | 
|  | { | 
|  | trio_string_t *self; | 
|  |  | 
|  | self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t)); | 
|  | if (self) | 
|  | { | 
|  | self->content = NULL; | 
|  | self->length = 0; | 
|  | self->allocated = 0; | 
|  | } | 
|  | return self; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * TrioStringGrow | 
|  | * | 
|  | * The size of the string will be increased by 'delta' characters. If | 
|  | * 'delta' is zero, the size will be doubled. | 
|  | */ | 
|  | TRIO_STRING_PRIVATE BOOLEAN_T | 
|  | TrioStringGrow | 
|  | TRIO_ARGS2((self, delta), | 
|  | trio_string_t *self, | 
|  | size_t delta) | 
|  | { | 
|  | BOOLEAN_T status = FALSE; | 
|  | char *new_content; | 
|  | size_t new_size; | 
|  |  | 
|  | new_size = (delta == 0) | 
|  | ? ( (self->allocated == 0) ? 1 : self->allocated * 2 ) | 
|  | : self->allocated + delta; | 
|  |  | 
|  | new_content = (char *)TRIO_REALLOC(self->content, new_size); | 
|  | if (new_content) | 
|  | { | 
|  | self->content = new_content; | 
|  | self->allocated = new_size; | 
|  | status = TRUE; | 
|  | } | 
|  | return status; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * TrioStringGrowTo | 
|  | * | 
|  | * The size of the string will be increased to 'length' plus one characters. | 
|  | * If 'length' is less than the original size, the original size will be | 
|  | * used (that is, the size of the string is never decreased). | 
|  | */ | 
|  | TRIO_STRING_PRIVATE BOOLEAN_T | 
|  | TrioStringGrowTo | 
|  | TRIO_ARGS2((self, length), | 
|  | trio_string_t *self, | 
|  | size_t length) | 
|  | { | 
|  | length++; /* Room for terminating zero */ | 
|  | return (self->allocated < length) | 
|  | ? TrioStringGrow(self, length - self->allocated) | 
|  | : TRUE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Create a new dynamic string. | 
|  |  | 
|  | @param initial_size Initial size of the buffer. | 
|  | @return Newly allocated dynamic string, or NULL if memory allocation failed. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC trio_string_t * | 
|  | trio_string_create | 
|  | TRIO_ARGS1((initial_size), | 
|  | int initial_size) | 
|  | { | 
|  | trio_string_t *self; | 
|  |  | 
|  | self = TrioStringAlloc(); | 
|  | if (self) | 
|  | { | 
|  | if (TrioStringGrow(self, | 
|  | (size_t)((initial_size > 0) ? initial_size : 1))) | 
|  | { | 
|  | self->content[0] = (char)0; | 
|  | self->allocated = initial_size; | 
|  | } | 
|  | else | 
|  | { | 
|  | trio_string_destroy(self); | 
|  | self = NULL; | 
|  | } | 
|  | } | 
|  | return self; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Deallocate the dynamic string and its contents. | 
|  |  | 
|  | @param self Dynamic string | 
|  | */ | 
|  | TRIO_STRING_PUBLIC void | 
|  | trio_string_destroy | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | if (self) | 
|  | { | 
|  | trio_destroy(self->content); | 
|  | TRIO_FREE(self); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Get a pointer to the content. | 
|  |  | 
|  | @param self Dynamic string. | 
|  | @param offset Offset into content. | 
|  | @return Pointer to the content. | 
|  |  | 
|  | @p Offset can be zero, positive, or negative. If @p offset is zero, | 
|  | then the start of the content will be returned. If @p offset is positive, | 
|  | then a pointer to @p offset number of characters from the beginning of the | 
|  | content is returned. If @p offset is negative, then a pointer to @p offset | 
|  | number of characters from the ending of the string, starting at the | 
|  | terminating zero, is returned. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_string_get | 
|  | TRIO_ARGS2((self, offset), | 
|  | trio_string_t *self, | 
|  | int offset) | 
|  | { | 
|  | char *result = NULL; | 
|  |  | 
|  | assert(self); | 
|  |  | 
|  | if (self->content != NULL) | 
|  | { | 
|  | if (self->length == 0) | 
|  | { | 
|  | (void)trio_string_length(self); | 
|  | } | 
|  | if (offset >= 0) | 
|  | { | 
|  | if (offset > (int)self->length) | 
|  | { | 
|  | offset = self->length; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | offset += self->length + 1; | 
|  | if (offset < 0) | 
|  | { | 
|  | offset = 0; | 
|  | } | 
|  | } | 
|  | result = &(self->content[offset]); | 
|  | } | 
|  | return result; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /** | 
|  | Extract the content. | 
|  |  | 
|  | @param self Dynamic String | 
|  | @return Content of dynamic string. | 
|  |  | 
|  | The content is removed from the dynamic string. This enables destruction | 
|  | of the dynamic string without deallocation of the content. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_string_extract | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | char *result; | 
|  |  | 
|  | assert(self); | 
|  |  | 
|  | result = self->content; | 
|  | /* FIXME: Allocate new empty buffer? */ | 
|  | self->content = NULL; | 
|  | self->length = self->allocated = 0; | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Set the content of the dynamic string. | 
|  |  | 
|  | @param self Dynamic String | 
|  | @param buffer The new content. | 
|  |  | 
|  | Sets the content of the dynamic string to a copy @p buffer. | 
|  | An existing content will be deallocated first, if necessary. | 
|  |  | 
|  | @remark | 
|  | This function will make a copy of @p buffer. | 
|  | You are responsible for deallocating @p buffer yourself. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC void | 
|  | trio_xstring_set | 
|  | TRIO_ARGS2((self, buffer), | 
|  | trio_string_t *self, | 
|  | char *buffer) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | trio_destroy(self->content); | 
|  | self->content = trio_duplicate(buffer); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * trio_string_size | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_size | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return self->allocated; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * trio_string_terminate | 
|  | */ | 
|  | TRIO_STRING_PUBLIC void | 
|  | trio_string_terminate | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | trio_xstring_append_char(self, 0); | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Append the second string to the first. | 
|  |  | 
|  | @param self Dynamic string to be modified. | 
|  | @param other Dynamic string to copy from. | 
|  | @return Boolean value indicating success or failure. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_append | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | size_t length; | 
|  |  | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | length = self->length + other->length; | 
|  | if (!TrioStringGrowTo(self, length)) | 
|  | goto error; | 
|  | trio_copy(&self->content[self->length], other->content); | 
|  | self->length = length; | 
|  | return TRUE; | 
|  |  | 
|  | error: | 
|  | return FALSE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_append | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_append | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | size_t length; | 
|  |  | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | length = self->length + trio_length(other); | 
|  | if (!TrioStringGrowTo(self, length)) | 
|  | goto error; | 
|  | trio_copy(&self->content[self->length], other); | 
|  | self->length = length; | 
|  | return TRUE; | 
|  |  | 
|  | error: | 
|  | return FALSE; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * trio_xstring_append_char | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_append_char | 
|  | TRIO_ARGS2((self, character), | 
|  | trio_string_t *self, | 
|  | char character) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | if ((int)self->length >= trio_string_size(self)) | 
|  | { | 
|  | if (!TrioStringGrow(self, 0)) | 
|  | goto error; | 
|  | } | 
|  | self->content[self->length] = character; | 
|  | self->length++; | 
|  | return TRUE; | 
|  |  | 
|  | error: | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /** | 
|  | Search for the first occurrence of second parameter in the first. | 
|  |  | 
|  | @param self Dynamic string to be modified. | 
|  | @param other Dynamic string to copy from. | 
|  | @return Boolean value indicating success or failure. | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_contains | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_contains(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_contains | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_contains | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_contains(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_copy | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_copy | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | self->length = 0; | 
|  | return trio_string_append(self, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_copy | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_copy | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | self->length = 0; | 
|  | return trio_xstring_append(self, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_duplicate | 
|  | */ | 
|  | TRIO_STRING_PUBLIC trio_string_t * | 
|  | trio_string_duplicate | 
|  | TRIO_ARGS1((other), | 
|  | trio_string_t *other) | 
|  | { | 
|  | trio_string_t *self; | 
|  |  | 
|  | assert(other); | 
|  |  | 
|  | self = TrioStringAlloc(); | 
|  | if (self) | 
|  | { | 
|  | self->content = TrioDuplicateMax(other->content, other->length); | 
|  | if (self->content) | 
|  | { | 
|  | self->length = other->length; | 
|  | self->allocated = self->length + 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | self->length = self->allocated = 0; | 
|  | } | 
|  | } | 
|  | return self; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | /* | 
|  | * trio_xstring_duplicate | 
|  | */ | 
|  | TRIO_STRING_PUBLIC trio_string_t * | 
|  | trio_xstring_duplicate | 
|  | TRIO_ARGS1((other), | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | trio_string_t *self; | 
|  |  | 
|  | assert(other); | 
|  |  | 
|  | self = TrioStringAlloc(); | 
|  | if (self) | 
|  | { | 
|  | self->content = TrioDuplicateMax(other, trio_length(other)); | 
|  | if (self->content) | 
|  | { | 
|  | self->length = trio_length(self->content); | 
|  | self->allocated = self->length + 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | self->length = self->allocated = 0; | 
|  | } | 
|  | } | 
|  | return self; | 
|  | } | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_equal | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_equal | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_equal | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_equal | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_equal_max | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_equal_max | 
|  | TRIO_ARGS3((self, max, other), | 
|  | trio_string_t *self, | 
|  | size_t max, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_max(self->content, max, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_equal_max | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_equal_max | 
|  | TRIO_ARGS3((self, max, other), | 
|  | trio_string_t *self, | 
|  | size_t max, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_max(self->content, max, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_equal_case | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_equal_case | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_case(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_equal_case | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_equal_case | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_case(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_equal_case_max | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_equal_case_max | 
|  | TRIO_ARGS3((self, max, other), | 
|  | trio_string_t *self, | 
|  | size_t max, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_case_max(self->content, max, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_equal_case_max | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_equal_case_max | 
|  | TRIO_ARGS3((self, max, other), | 
|  | trio_string_t *self, | 
|  | size_t max, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_equal_case_max(self->content, max, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE) | 
|  | /* | 
|  | * trio_string_format_data_max | 
|  | */ | 
|  | TRIO_STRING_PUBLIC size_t | 
|  | trio_string_format_date_max | 
|  | TRIO_ARGS4((self, max, format, datetime), | 
|  | trio_string_t *self, | 
|  | size_t max, | 
|  | TRIO_CONST char *format, | 
|  | TRIO_CONST struct tm *datetime) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return trio_format_date_max(self->content, max, format, datetime); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_index | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_string_index | 
|  | TRIO_ARGS2((self, character), | 
|  | trio_string_t *self, | 
|  | int character) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return trio_index(self->content, character); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_index_last | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_string_index_last | 
|  | TRIO_ARGS2((self, character), | 
|  | trio_string_t *self, | 
|  | int character) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return trio_index_last(self->content, character); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_length | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_length | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | if (self->length == 0) | 
|  | { | 
|  | self->length = trio_length(self->content); | 
|  | } | 
|  | return self->length; | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_lower | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_lower | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return trio_lower(self->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_match | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_match | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_match(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_match | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_match | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_match(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_match_case | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_match_case | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_match_case(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_match_case | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_xstring_match_case | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_match_case(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_substring | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_string_substring | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | trio_string_t *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_substring(self->content, other->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_xstring_substring | 
|  | */ | 
|  | TRIO_STRING_PUBLIC char * | 
|  | trio_xstring_substring | 
|  | TRIO_ARGS2((self, other), | 
|  | trio_string_t *self, | 
|  | TRIO_CONST char *other) | 
|  | { | 
|  | assert(self); | 
|  | assert(other); | 
|  |  | 
|  | return trio_substring(self->content, other); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  |  | 
|  | #if !defined(TRIO_MINIMAL) | 
|  | /* | 
|  | * trio_string_upper | 
|  | */ | 
|  | TRIO_STRING_PUBLIC int | 
|  | trio_string_upper | 
|  | TRIO_ARGS1((self), | 
|  | trio_string_t *self) | 
|  | { | 
|  | assert(self); | 
|  |  | 
|  | return trio_upper(self->content); | 
|  | } | 
|  | #endif /* !defined(TRIO_MINIMAL) */ | 
|  |  | 
|  | /** @} End of DynamicStrings */ |