| /************************************************************************* |
| * |
| * $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 |
| # 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$"; |
| #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 */ |