2001-03-27 16:47:33 +04:00
/*************************************************************************
*
* $ Id $
*
* Copyright ( C ) 1998 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-04-21 20:57:29 +04:00
/*
* TODO
* - StrToLongDouble
2001-03-27 16:47:33 +04:00
*/
static const char rcsid [ ] = " @(#)$Id$ " ;
2001-06-05 16:46:33 +04:00
# if defined(unix) || defined(__xlC__) || defined(__QNX__)
2001-03-27 16:47:33 +04:00
# define PLATFORM_UNIX
# elif defined(WIN32) || defined(_WIN32)
# define PLATFORM_WIN32
# elif defined(AMIGA) && defined(__GNUC__)
# define PLATFORM_UNIX
# endif
# if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
# define TRIO_C99
# endif
# include "strio.h"
# include <string.h>
2001-06-05 16:46:33 +04:00
# include <locale.h>
2001-03-27 16:47:33 +04:00
# include <ctype.h>
# include <stdarg.h>
# include <time.h>
# include <math.h>
# ifndef DEBUG
# define NDEBUG
# endif
# include <assert.h>
# ifndef NULL
# define NULL 0
# endif
# define NIL ((char)0)
# ifndef FALSE
# define FALSE (1 == 0)
# define TRUE (! FALSE)
# endif
# define VALID(x) (NULL != (x))
# define INVALID(x) (NULL == (x))
# if defined(PLATFORM_UNIX)
# define USE_STRCASECMP
# define USE_STRNCASECMP
# define USE_STRERROR
2001-06-05 16:46:33 +04:00
# if defined(__QNX__)
# define strcasecmp(x,y) stricmp(x,y)
# define strncasecmp(x,y,n) strnicmp(x,y,n)
# endif
2001-03-27 16:47:33 +04:00
# elif defined(PLATFORM_WIN32)
2001-06-05 16:46:33 +04:00
# define USE_STRCASECMP
# define strcasecmp(x,y) strcmpi(x,y)
2001-03-27 16:47:33 +04:00
# endif
/*************************************************************************
* StrAppendMax
*/
char * StrAppendMax ( char * target , size_t max , const char * source )
{
assert ( VALID ( target ) ) ;
assert ( VALID ( source ) ) ;
assert ( max > 0 ) ;
max - = StrLength ( target ) + 1 ;
return ( max > 0 ) ? strncat ( target , source , max ) : target ;
}
/*************************************************************************
* StrCopyMax
*/
char * StrCopyMax ( char * target , size_t max , const char * source )
{
assert ( VALID ( target ) ) ;
assert ( VALID ( source ) ) ;
assert ( max > 0 ) ; /* Includes != 0 */
target = strncpy ( target , source , max - 1 ) ;
target [ max - 1 ] = ( char ) 0 ;
return target ;
}
/*************************************************************************
* StrDuplicate
*/
char * StrDuplicate ( const char * source )
{
char * target ;
assert ( VALID ( source ) ) ;
2001-06-05 16:46:33 +04:00
target = StrAlloc ( StrLength ( source ) + 1 ) ;
2001-03-27 16:47:33 +04:00
if ( target )
{
StrCopy ( target , source ) ;
}
return target ;
}
/*************************************************************************
* StrDuplicateMax
*/
char * StrDuplicateMax ( const char * source , size_t max )
{
char * target ;
size_t len ;
assert ( VALID ( source ) ) ;
assert ( max > 0 ) ;
/* Make room for string plus a terminating zero */
len = StrLength ( source ) + 1 ;
if ( len > max )
{
len = max ;
}
2001-06-05 16:46:33 +04:00
target = StrAlloc ( len ) ;
2001-03-27 16:47:33 +04:00
if ( target )
{
StrCopyMax ( target , len , source ) ;
}
return target ;
}
/*************************************************************************
* StrEqual
*/
int StrEqual ( const char * first , const char * second )
{
assert ( VALID ( first ) ) ;
assert ( VALID ( second ) ) ;
if ( VALID ( first ) & & VALID ( second ) )
{
# 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 ;
}
/*************************************************************************
* StrEqualCase
*/
int StrEqualCase ( const char * first , const char * second )
{
assert ( VALID ( first ) ) ;
assert ( VALID ( second ) ) ;
if ( VALID ( first ) & & VALID ( second ) )
{
return ( 0 = = strcmp ( first , second ) ) ;
}
return FALSE ;
}
/*************************************************************************
* StrEqualCaseMax
*/
int StrEqualCaseMax ( const char * first , size_t max , const char * second )
{
assert ( VALID ( first ) ) ;
assert ( VALID ( second ) ) ;
if ( VALID ( first ) & & VALID ( second ) )
{
return ( 0 = = strncmp ( first , second , max ) ) ;
}
return FALSE ;
}
2001-06-05 16:46:33 +04:00
/*************************************************************************
* StrEqualLocale
*/
int StrEqualLocale ( const char * first , const char * second )
{
assert ( VALID ( first ) ) ;
assert ( VALID ( second ) ) ;
# if defined(LC_COLLATE)
return ( strcoll ( first , second ) = = 0 ) ;
# else
return StrEqual ( first , second ) ;
# endif
}
2001-03-27 16:47:33 +04:00
/*************************************************************************
* StrEqualMax
*/
int StrEqualMax ( const char * first , size_t max , const char * second )
{
assert ( VALID ( first ) ) ;
assert ( VALID ( second ) ) ;
if ( VALID ( first ) & & VALID ( second ) )
{
# 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 ;
}
/*************************************************************************
* StrError
*/
const char * StrError ( int errorNumber )
{
# if defined(USE_STRERROR)
return strerror ( errorNumber ) ;
# else
return " unknown " ;
# endif
}
/*************************************************************************
* StrFormatDate
*/
size_t StrFormatDateMax ( char * target ,
size_t max ,
const char * format ,
const struct tm * datetime )
{
assert ( VALID ( target ) ) ;
assert ( VALID ( format ) ) ;
assert ( VALID ( datetime ) ) ;
assert ( max > 0 ) ;
return strftime ( target , max , format , datetime ) ;
}
/*************************************************************************
* StrHash
*/
unsigned long StrHash ( const char * string , int type )
{
unsigned long value = 0L ;
char ch ;
assert ( VALID ( string ) ) ;
switch ( type )
{
case STRIO_HASH_PLAIN :
while ( ( ch = * string + + ) ! = NIL )
{
value * = 31 ;
value + = ( unsigned long ) ch ;
}
break ;
default :
assert ( FALSE ) ;
break ;
}
return value ;
}
/*************************************************************************
* StrMatch
*/
int StrMatch ( char * string , char * pattern )
{
assert ( VALID ( string ) ) ;
assert ( VALID ( pattern ) ) ;
for ( ; ( ' * ' ! = * pattern ) ; + + pattern , + + string )
{
if ( NIL = = * string )
{
return ( NIL = = * pattern ) ;
}
2001-06-05 16:46:33 +04:00
if ( ( toupper ( ( int ) * string ) ! = toupper ( ( int ) * pattern ) )
2001-03-27 16:47:33 +04:00
& & ( ' ? ' ! = * pattern ) )
{
return FALSE ;
}
}
/* two-line patch to prevent *too* much recursiveness: */
while ( ' * ' = = pattern [ 1 ] )
pattern + + ;
do
{
if ( StrMatch ( string , & pattern [ 1 ] ) )
{
return TRUE ;
}
}
while ( * string + + ) ;
return FALSE ;
}
/*************************************************************************
* StrMatchCase
*/
int StrMatchCase ( char * string , char * pattern )
{
assert ( VALID ( string ) ) ;
assert ( VALID ( 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 ( StrMatchCase ( string , & pattern [ 1 ] ) )
{
return TRUE ;
}
}
while ( * string + + ) ;
return FALSE ;
}
/*************************************************************************
* StrSpanFunction
*
* Untested
*/
size_t StrSpanFunction ( char * source , int ( * Function ) ( int ) )
{
size_t count = 0 ;
assert ( VALID ( source ) ) ;
assert ( VALID ( Function ) ) ;
while ( * source ! = NIL )
{
if ( Function ( * source ) )
break ; /* while */
source + + ;
count + + ;
}
return count ;
}
/*************************************************************************
* StrSubstringMax
*/
char * StrSubstringMax ( const char * string , size_t max , const char * find )
{
size_t count ;
size_t size ;
char * result = NULL ;
assert ( VALID ( string ) ) ;
assert ( VALID ( find ) ) ;
size = StrLength ( find ) ;
2001-04-21 20:57:29 +04:00
if ( size < = max )
2001-03-27 16:47:33 +04:00
{
2001-04-21 20:57:29 +04:00
for ( count = 0 ; count < = max - size ; count + + )
2001-03-27 16:47:33 +04:00
{
if ( StrEqualMax ( find , size , & string [ count ] ) )
{
result = ( char * ) & string [ count ] ;
break ;
}
}
}
return result ;
}
/*************************************************************************
* StrToDouble
*
* 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 : : = ' . '
*/
double StrToDouble ( const char * source , const char * * endp )
{
# if defined(TRIO_C99)
return strtod ( source , 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 ;
2001-06-05 16:46:33 +04:00
integer + = ( isdigit ( ( int ) * source )
? ( * source - ' 0 ' )
: 10 + ( toupper ( ( int ) * source ) - ' A ' ) ) ;
2001-03-27 16:47:33 +04:00
source + + ;
}
if ( * source = = ' . ' )
{
source + + ;
while ( isxdigit ( ( int ) * source ) )
{
fraction * = 16 ;
2001-06-05 16:46:33 +04:00
fraction + = ( isdigit ( ( int ) * source )
? ( * source - ' 0 ' )
: 10 + ( toupper ( ( int ) * source ) - ' A ' ) ) ;
2001-03-27 16:47:33 +04:00
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 ' ) )
{
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
}
/*************************************************************************
* StrToFloat
*/
float StrToFloat ( const char * source , const char * * endp )
{
# if defined(TRIO_C99)
return strtof ( source , endp ) ;
# else
return ( float ) StrToDouble ( source , endp ) ;
# endif
}
/*************************************************************************
* StrToUpper
*/
int StrToUpper ( char * target )
{
int i = 0 ;
assert ( VALID ( target ) ) ;
while ( NIL ! = * target )
{
2001-06-05 16:46:33 +04:00
* target = toupper ( ( int ) * target ) ;
2001-03-27 16:47:33 +04:00
target + + ;
i + + ;
}
return i ;
}