mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2024-12-27 03:21:26 +03:00
1754 lines
33 KiB
C
1754 lines
33 KiB
C
/*************************************************************************
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
|
|
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
|
|
*
|
|
************************************************************************/
|
|
|
|
static const char rcsid[] = "@(#)$Id$";
|
|
|
|
/*************************************************************************
|
|
* Include files
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include "triostr.h"
|
|
|
|
/*************************************************************************
|
|
* Definitions
|
|
*/
|
|
|
|
#ifndef NULL
|
|
# define NULL 0
|
|
#endif
|
|
#define NIL ((char)0)
|
|
#ifndef FALSE
|
|
# define FALSE (1 == 0)
|
|
# define TRUE (! FALSE)
|
|
#endif
|
|
#define BOOLEAN_T int
|
|
|
|
#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
|
|
# define USE_STRERROR
|
|
# 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
|
|
|
|
/*************************************************************************
|
|
* Structures
|
|
*/
|
|
|
|
struct _trio_string_t
|
|
{
|
|
char *content;
|
|
size_t length;
|
|
size_t allocated;
|
|
};
|
|
|
|
/*************************************************************************
|
|
* 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_PUBLIC TRIO_INLINE char *
|
|
trio_create(size_t size)
|
|
{
|
|
return (char *)TRIO_MALLOC(size);
|
|
}
|
|
|
|
|
|
/**
|
|
Destroy string.
|
|
|
|
@param string String to be freed.
|
|
*/
|
|
TRIO_PUBLIC TRIO_INLINE void
|
|
trio_destroy(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_PUBLIC TRIO_INLINE size_t
|
|
trio_length(const char *string)
|
|
{
|
|
return strlen(string);
|
|
}
|
|
|
|
|
|
/*
|
|
* TrioDuplicateMax
|
|
*/
|
|
TRIO_PRIVATE char *
|
|
TrioDuplicateMax(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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_append(char *target,
|
|
const char *source)
|
|
{
|
|
assert(target);
|
|
assert(source);
|
|
|
|
return (strcat(target, source) != NULL);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_append_max(char *target,
|
|
size_t max,
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE int
|
|
trio_contains(const char *string,
|
|
const char *substring)
|
|
{
|
|
assert(string);
|
|
assert(substring);
|
|
|
|
return (0 != strstr(string, substring));
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_copy(char *target,
|
|
const char *source)
|
|
{
|
|
assert(target);
|
|
assert(source);
|
|
|
|
(void)strcpy(target, source);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_copy_max(char *target,
|
|
size_t max,
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
Duplicate @p source.
|
|
|
|
@param source Source string.
|
|
@return A copy of the @p source string.
|
|
|
|
@post @p target will be zero terminated.
|
|
*/
|
|
TRIO_PUBLIC char *
|
|
trio_duplicate(const char *source)
|
|
{
|
|
return TrioDuplicateMax(source, trio_length(source));
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC char *
|
|
trio_duplicate_max(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);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_equal(const char *first,
|
|
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 (toupper(*first) != toupper(*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_PUBLIC int
|
|
trio_equal_case(const char *first,
|
|
const char *second)
|
|
{
|
|
assert(first);
|
|
assert(second);
|
|
|
|
if ((first != NULL) && (second != NULL))
|
|
{
|
|
return (0 == strcmp(first, second));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_equal_case_max(const char *first,
|
|
size_t max,
|
|
const char *second)
|
|
{
|
|
assert(first);
|
|
assert(second);
|
|
|
|
if ((first != NULL) && (second != NULL))
|
|
{
|
|
return (0 == strncmp(first, second, max));
|
|
}
|
|
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.
|
|
|
|
Collating characters are considered equal.
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_equal_locale(const char *first,
|
|
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_PUBLIC int
|
|
trio_equal_max(const char *first,
|
|
size_t max,
|
|
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 (toupper(*first) != toupper(*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_PUBLIC const char *
|
|
trio_error(int error_number)
|
|
{
|
|
#if defined(USE_STRERROR)
|
|
return strerror(error_number);
|
|
#else
|
|
return "unknown";
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC size_t
|
|
trio_format_date_max(char *target,
|
|
size_t max,
|
|
const char *format,
|
|
const struct tm *datetime)
|
|
{
|
|
assert(target);
|
|
assert(format);
|
|
assert(datetime);
|
|
assert(max > 0);
|
|
|
|
return strftime(target, max, format, datetime);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC unsigned long
|
|
trio_hash(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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE char *
|
|
trio_index(const char *string,
|
|
char character)
|
|
{
|
|
assert(string);
|
|
|
|
return strchr(string, character);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE char *
|
|
trio_index_last(const char *string,
|
|
char character)
|
|
{
|
|
assert(string);
|
|
|
|
return strchr(string, character);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE int
|
|
trio_lower(char *target)
|
|
{
|
|
assert(target);
|
|
|
|
return trio_span_function(target, target, tolower);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_match(const char *string,
|
|
const char *pattern)
|
|
{
|
|
assert(string);
|
|
assert(pattern);
|
|
|
|
for (; ('*' != *pattern); ++pattern, ++string)
|
|
{
|
|
if (NIL == *string)
|
|
{
|
|
return (NIL == *pattern);
|
|
}
|
|
if ((toupper((int)*string) != toupper((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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_match_case(const char *string,
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC size_t
|
|
trio_span_function(char *target,
|
|
const char *source,
|
|
int (*Function)(int))
|
|
{
|
|
size_t count = 0;
|
|
|
|
assert(target);
|
|
assert(source);
|
|
assert(Function);
|
|
|
|
while (*source != NIL)
|
|
{
|
|
*target++ = Function(*source++);
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE char *
|
|
trio_substring(const char *string,
|
|
const char *substring)
|
|
{
|
|
assert(string);
|
|
assert(substring);
|
|
|
|
return strstr(string, substring);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC char *
|
|
trio_substring_max(const char *string,
|
|
size_t max,
|
|
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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE char *
|
|
trio_tokenize(char *string, const char *delimiters)
|
|
{
|
|
assert(delimiters);
|
|
|
|
return strtok(string, delimiters);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC double
|
|
trio_to_double(const char *source,
|
|
const char **endp)
|
|
{
|
|
#if defined(USE_STRTOD)
|
|
return strtod(source, (char **)endp);
|
|
#else
|
|
/* Preliminary code */
|
|
int isNegative = FALSE;
|
|
int isExponentNegative = FALSE;
|
|
unsigned long integer = 0;
|
|
unsigned long fraction = 0;
|
|
unsigned long fracdiv = 1;
|
|
unsigned long exponent = 0;
|
|
double value = 0.0;
|
|
|
|
/* First try hex-floats */
|
|
if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
|
|
{
|
|
source += 2;
|
|
while (isxdigit((int)*source))
|
|
{
|
|
integer *= 16;
|
|
integer += (isdigit((int)*source)
|
|
? (*source - '0')
|
|
: 10 + (toupper((int)*source) - 'A'));
|
|
source++;
|
|
}
|
|
if (*source == '.')
|
|
{
|
|
source++;
|
|
while (isxdigit((int)*source))
|
|
{
|
|
fraction *= 16;
|
|
fraction += (isdigit((int)*source)
|
|
? (*source - '0')
|
|
: 10 + (toupper((int)*source) - 'A'));
|
|
fracdiv *= 16;
|
|
source++;
|
|
}
|
|
if ((*source == 'p') || (*source == 'P'))
|
|
{
|
|
source++;
|
|
if ((*source == '+') || (*source == '-'))
|
|
{
|
|
isExponentNegative = (*source == '-');
|
|
source++;
|
|
}
|
|
while (isdigit((int)*source))
|
|
{
|
|
exponent *= 10;
|
|
exponent += (*source - '0');
|
|
source++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else /* Then try normal decimal floats */
|
|
{
|
|
isNegative = (*source == '-');
|
|
/* Skip sign */
|
|
if ((*source == '+') || (*source == '-'))
|
|
source++;
|
|
|
|
/* Integer part */
|
|
while (isdigit((int)*source))
|
|
{
|
|
integer *= 10;
|
|
integer += (*source - '0');
|
|
source++;
|
|
}
|
|
|
|
if (*source == '.')
|
|
{
|
|
source++; /* skip decimal point */
|
|
while (isdigit((int)*source))
|
|
{
|
|
fraction *= 10;
|
|
fraction += (*source - '0');
|
|
fracdiv *= 10;
|
|
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 *= 10;
|
|
exponent += (*source - '0');
|
|
source++;
|
|
}
|
|
}
|
|
}
|
|
|
|
value = (double)integer;
|
|
if (fraction != 0)
|
|
{
|
|
value += (double)fraction / (double)fracdiv;
|
|
}
|
|
if (exponent != 0)
|
|
{
|
|
if (isExponentNegative)
|
|
value /= pow((double)10, (double)exponent);
|
|
else
|
|
value *= pow((double)10, (double)exponent);
|
|
}
|
|
if (isNegative)
|
|
value = -value;
|
|
|
|
if (endp)
|
|
*endp = 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_double.
|
|
*/
|
|
TRIO_PUBLIC TRIO_INLINE float
|
|
trio_to_float(const char *source,
|
|
const char **endp)
|
|
{
|
|
#if defined(USE_STRTOF)
|
|
return strtof(source, (char **)endp);
|
|
#else
|
|
return (float)trio_to_double(source, endp);
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE long
|
|
trio_to_long(const char *string,
|
|
char **endp,
|
|
int base)
|
|
{
|
|
assert(string);
|
|
assert((base >= 2) && (base <= 36));
|
|
|
|
return strtol(string, endp, base);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE unsigned long
|
|
trio_to_unsigned_long(const char *string,
|
|
char **endp,
|
|
int base)
|
|
{
|
|
assert(string);
|
|
assert((base >= 2) && (base <= 36));
|
|
|
|
return strtoul(string, endp, base);
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC TRIO_INLINE int
|
|
trio_upper(char *target)
|
|
{
|
|
assert(target);
|
|
|
|
return trio_span_function(target, target, toupper);
|
|
}
|
|
|
|
|
|
/** @} End of StaticStrings */
|
|
|
|
|
|
/*************************************************************************
|
|
* Dynamic String Functions
|
|
*/
|
|
|
|
#if defined(TRIO_DOCUMENTATION)
|
|
# include "doc/doc_dynamic.h"
|
|
#endif
|
|
/** @addtogroup DynamicStrings
|
|
@{
|
|
*/
|
|
|
|
/*
|
|
* TrioStringAlloc
|
|
*/
|
|
TRIO_PRIVATE trio_string_t *
|
|
TrioStringAlloc(void)
|
|
{
|
|
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_PRIVATE BOOLEAN_T
|
|
TrioStringGrow(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;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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_PRIVATE BOOLEAN_T
|
|
TrioStringGrowTo(trio_string_t *self,
|
|
size_t length)
|
|
{
|
|
length++; /* Room for terminating zero */
|
|
return (self->allocated < length)
|
|
? TrioStringGrow(self, length - self->allocated)
|
|
: TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC trio_string_t *
|
|
trio_string_create(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;
|
|
}
|
|
|
|
|
|
/**
|
|
Deallocate the dynamic string and its contents.
|
|
|
|
@param self Dynamic string
|
|
*/
|
|
TRIO_PUBLIC void
|
|
trio_string_destroy(trio_string_t *self)
|
|
{
|
|
assert(self);
|
|
|
|
if (self)
|
|
{
|
|
trio_destroy(self->content);
|
|
TRIO_FREE(self);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC char *
|
|
trio_string_get(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 > self->length)
|
|
{
|
|
offset = self->length;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
offset += self->length + 1;
|
|
if (offset < 0)
|
|
{
|
|
offset = 0;
|
|
}
|
|
}
|
|
result = &(self->content[offset]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC char *
|
|
trio_string_extract(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;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC void
|
|
trio_xstring_set(trio_string_t *self,
|
|
char *buffer)
|
|
{
|
|
assert(self);
|
|
|
|
trio_destroy(self->content);
|
|
self->content = trio_duplicate(buffer);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_size
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_size(trio_string_t *self)
|
|
{
|
|
assert(self);
|
|
|
|
return self->allocated;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_terminate
|
|
*/
|
|
TRIO_PUBLIC void
|
|
trio_string_terminate(trio_string_t *self)
|
|
{
|
|
char *end;
|
|
|
|
assert(self);
|
|
|
|
end = trio_string_get(self, -1);
|
|
if (end)
|
|
{
|
|
*end = NIL;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_string_append(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;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_append
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_append(trio_string_t *self,
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_append_char
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_append_char(trio_string_t *self,
|
|
char character)
|
|
{
|
|
assert(self);
|
|
|
|
if (self->length >= trio_string_size(self))
|
|
{
|
|
if (!TrioStringGrow(self, 0))
|
|
goto error;
|
|
}
|
|
self->content[self->length] = character;
|
|
self->length++;
|
|
return TRUE;
|
|
|
|
error:
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
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_PUBLIC int
|
|
trio_string_contains(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_contains(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_contains
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_contains(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_contains(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_copy
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_copy(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
self->length = 0;
|
|
return trio_string_append(self, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_copy
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_copy(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
self->length = 0;
|
|
return trio_xstring_append(self, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_duplicate
|
|
*/
|
|
TRIO_PUBLIC trio_string_t *
|
|
trio_string_duplicate(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;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_duplicate
|
|
*/
|
|
TRIO_PUBLIC trio_string_t *
|
|
trio_xstring_duplicate(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;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_equal
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_equal(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_equal
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_equal(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_equal_max
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_equal_max(trio_string_t *self,
|
|
size_t max,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal_max(self->content, max, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_equal_max
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_equal_max(trio_string_t *self,
|
|
size_t max,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal_max(self->content, max, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_equal_case
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_equal_case(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal_case(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_equal_case
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_equal_case(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal_case(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_equal_case_max
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_equal_case_max(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);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_equal_case_max
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_equal_case_max(trio_string_t *self,
|
|
size_t max,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_equal_case_max(self->content, max, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_format_data_max
|
|
*/
|
|
TRIO_PUBLIC size_t
|
|
trio_string_format_date_max(trio_string_t *self,
|
|
size_t max,
|
|
const char *format,
|
|
const struct tm *datetime)
|
|
{
|
|
assert(self);
|
|
|
|
return trio_format_date_max(self->content, max, format, datetime);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_index
|
|
*/
|
|
TRIO_PUBLIC char *
|
|
trio_string_index(trio_string_t *self,
|
|
int character)
|
|
{
|
|
assert(self);
|
|
|
|
return trio_index(self->content, character);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_index_last
|
|
*/
|
|
TRIO_PUBLIC char *
|
|
trio_string_index_last(trio_string_t *self,
|
|
int character)
|
|
{
|
|
assert(self);
|
|
|
|
return trio_index_last(self->content, character);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_length
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_length(trio_string_t *self)
|
|
{
|
|
assert(self);
|
|
|
|
if (self->length == 0)
|
|
{
|
|
self->length = trio_length(self->content);
|
|
}
|
|
return self->length;
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_lower
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_lower(trio_string_t *self)
|
|
{
|
|
assert(self);
|
|
|
|
return trio_lower(self->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_match
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_match(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_match(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_match
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_match(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_match(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_match_case
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_match_case(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_match_case(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_match_case
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_xstring_match_case(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_match_case(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_substring
|
|
*/
|
|
TRIO_PUBLIC char *
|
|
trio_string_substring(trio_string_t *self,
|
|
trio_string_t *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_substring(self->content, other->content);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_xstring_substring
|
|
*/
|
|
TRIO_PUBLIC char *
|
|
trio_xstring_substring(trio_string_t *self,
|
|
const char *other)
|
|
{
|
|
assert(self);
|
|
assert(other);
|
|
|
|
return trio_substring(self->content, other);
|
|
}
|
|
|
|
|
|
/*
|
|
* trio_string_upper
|
|
*/
|
|
TRIO_PUBLIC int
|
|
trio_string_upper(trio_string_t *self)
|
|
{
|
|
assert(self);
|
|
|
|
return trio_upper(self->content);
|
|
}
|
|
|
|
/** @} End of DynamicStrings */
|