2021-03-19 20:57:07 +01:00
#include "FFstrbuf.h"
2021-04-09 19:21:56 +02:00
#include <ctype.h>
2022-09-04 22:20:12 +02:00
#include <inttypes.h>
2021-03-19 20:57:07 +01:00
2023-03-22 15:32:25 +08:00
char * CHAR_NULL_PTR = "" ;
2021-11-16 12:54:49 +01:00
2021-03-19 20:57:07 +01:00
void ffStrbufInitA ( FFstrbuf * strbuf , uint32_t allocate )
{
strbuf -> allocated = allocate ;
2021-03-27 18:14:19 +01:00
2021-11-16 12:54:49 +01:00
if ( strbuf -> allocated > 0 )
strbuf -> chars = ( char * ) malloc ( sizeof ( char ) * strbuf -> allocated );
//This will set the length to zero and the null byte.
2021-03-19 20:57:07 +01:00
ffStrbufClear ( strbuf );
}
2022-01-12 01:02:14 +01:00
void ffStrbufInitCopy ( FFstrbuf * strbuf , const FFstrbuf * src )
2021-03-19 20:57:07 +01:00
{
2022-01-12 01:02:14 +01:00
ffStrbufInitA ( strbuf , src -> allocated );
ffStrbufAppend ( strbuf , src );
2021-03-19 20:57:07 +01:00
}
2022-12-06 16:26:51 +08:00
void ffStrbufInitVF ( FFstrbuf * strbuf , const char * format , va_list arguments )
{
assert ( format != NULL );
int len = vasprintf ( & strbuf -> chars , format , arguments );
assert ( len >= 0 );
strbuf -> allocated = ( uint32_t )( len + 1 );
strbuf -> length = ( uint32_t ) len ;
}
2022-06-08 17:14:11 +02:00
uint32_t ffStrbufGetFree ( const FFstrbuf * strbuf )
2021-03-19 20:57:07 +01:00
{
2022-09-24 19:22:33 +08:00
assert ( strbuf != NULL );
2021-11-16 12:54:49 +01:00
if ( strbuf -> allocated == 0 )
2022-06-08 17:14:11 +02:00
return 0 ;
2021-11-17 12:07:08 +01:00
2022-06-08 17:14:11 +02:00
return strbuf -> allocated - strbuf -> length - 1 ; // - 1 for the null byte
2021-03-19 20:57:07 +01:00
}
void ffStrbufEnsureFree ( FFstrbuf * strbuf , uint32_t free )
{
2021-11-17 10:59:31 +01:00
if ( ffStrbufGetFree ( strbuf ) >= free )
2021-11-16 12:54:49 +01:00
return ;
2021-03-19 20:57:07 +01:00
uint32_t allocate = strbuf -> allocated ;
2021-04-03 11:39:59 +02:00
if ( allocate < 2 )
2022-09-23 19:54:18 +02:00
allocate = FASTFETCH_STRBUF_DEFAULT_ALLOC ;
2021-11-16 12:54:49 +01:00
2021-11-17 10:59:31 +01:00
while (( strbuf -> length + free + 1 ) > allocate ) // + 1 for the null byte
2021-03-19 20:57:07 +01:00
allocate *= 2 ;
2021-11-16 12:54:49 +01:00
2021-11-17 10:59:31 +01:00
if ( strbuf -> allocated == 0 )
2022-06-08 17:14:11 +02:00
{
strbuf -> chars = malloc ( sizeof ( * strbuf -> chars ) * allocate );
strbuf -> chars [ 0 ] = '\0' ;
}
else
strbuf -> chars = realloc ( strbuf -> chars , sizeof ( * strbuf -> chars ) * allocate );
2021-11-17 10:59:31 +01:00
2022-06-08 17:14:11 +02:00
strbuf -> allocated = allocate ;
2021-03-19 20:57:07 +01:00
}
void ffStrbufClear ( FFstrbuf * strbuf )
{
2022-09-24 19:22:33 +08:00
assert ( strbuf != NULL );
2021-11-16 12:54:49 +01:00
if ( strbuf -> allocated == 0 )
strbuf -> chars = CHAR_NULL_PTR ;
else
strbuf -> chars [ 0 ] = '\0' ;
2021-03-19 20:57:07 +01:00
strbuf -> length = 0 ;
}
2022-01-12 01:02:14 +01:00
void ffStrbufAppendC ( FFstrbuf * strbuf , char c )
2021-04-18 15:19:21 +02:00
{
2022-01-12 01:02:14 +01:00
ffStrbufEnsureFree ( strbuf , 1 );
strbuf -> chars [ strbuf -> length ++ ] = c ;
2021-04-18 15:19:21 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
}
2021-03-19 20:57:07 +01:00
void ffStrbufAppendNS ( FFstrbuf * strbuf , uint32_t length , const char * value )
{
2022-09-24 19:22:33 +08:00
if ( value == NULL || length == 0 )
2021-03-19 20:57:07 +01:00
return ;
ffStrbufEnsureFree ( strbuf , length );
2022-09-20 21:50:50 +08:00
memcpy ( & strbuf -> chars [ strbuf -> length ], value , length );
strbuf -> length += length ;
2021-05-23 19:40:34 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
}
void ffStrbufAppendNSExludingC ( FFstrbuf * strbuf , uint32_t length , const char * value , char exclude )
{
2022-09-24 19:22:33 +08:00
if ( value == NULL || length == 0 )
2021-05-23 19:40:34 +02:00
return ;
ffStrbufEnsureFree ( strbuf , length );
for ( uint32_t i = 0 ; i < length ; i ++ )
{
if ( value [ i ] != exclude )
strbuf -> chars [ strbuf -> length ++ ] = value [ i ];
}
2021-03-19 20:57:07 +01:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
}
2022-01-12 01:02:14 +01:00
void ffStrbufAppendTransformS ( FFstrbuf * strbuf , const char * value , int ( * transformFunc )( int ))
2021-03-19 20:57:07 +01:00
{
2022-01-12 01:02:14 +01:00
if ( value == NULL )
2021-03-19 20:57:07 +01:00
return ;
2022-09-24 19:22:33 +08:00
//Ensure capacity > 0 or the modification below will fail
uint32_t length = ( uint32_t ) strlen ( value );
if ( length == 0 )
return ;
ffStrbufEnsureFree ( strbuf , length );
2022-01-12 01:02:14 +01:00
for ( uint32_t i = 0 ; value [ i ] != '\0' ; i ++ )
{
strbuf -> chars [ strbuf -> length ++ ] = ( char ) transformFunc ( value [ i ]);
}
strbuf -> chars [ strbuf -> length ] = '\0' ;
2021-03-19 20:57:07 +01:00
}
void ffStrbufAppendVF ( FFstrbuf * strbuf , const char * format , va_list arguments )
{
2022-09-24 19:22:33 +08:00
assert ( format != NULL );
2021-03-19 20:57:07 +01:00
2022-01-12 18:57:35 +01:00
va_list copy ;
va_copy ( copy , arguments );
2021-11-17 11:41:17 +01:00
uint32_t free = ffStrbufGetFree ( strbuf );
2022-12-02 22:20:01 +08:00
int written = vsnprintf ( strbuf -> chars + strbuf -> length , strbuf -> allocated > 0 ? free + 1 : 0 , format , arguments );
2021-03-19 20:57:07 +01:00
2022-12-02 22:20:01 +08:00
if ( written > 0 && strbuf -> length + ( uint32_t ) written > free )
2021-03-19 20:57:07 +01:00
{
2022-12-02 22:20:01 +08:00
ffStrbufEnsureFree ( strbuf , ( uint32_t ) written );
written = vsnprintf ( strbuf -> chars + strbuf -> length , ( uint32_t ) written + 1 , format , copy );
2021-03-19 20:57:07 +01:00
}
2021-11-17 11:41:17 +01:00
2022-01-12 18:57:35 +01:00
va_end ( copy );
2022-12-02 22:20:01 +08:00
if ( written > 0 )
strbuf -> length += ( uint32_t ) written ;
2021-03-19 20:57:07 +01:00
}
2022-10-17 13:19:48 +02:00
void ffStrbufAppendSUntilC ( FFstrbuf * strbuf , const char * value , char until )
{
if ( value == NULL )
return ;
char * end = strchr ( value , until );
if ( end == NULL )
ffStrbufAppendS ( strbuf , value );
else
ffStrbufAppendNS ( strbuf , ( uint32_t ) ( end - value ), value );
}
2022-09-24 19:22:33 +08:00
void ffStrbufSetF ( FFstrbuf * strbuf , const char * format , ...)
2021-03-19 20:57:07 +01:00
{
2022-09-24 19:22:33 +08:00
assert ( format != NULL );
2022-01-12 01:02:14 +01:00
va_list arguments ;
va_start ( arguments , format );
2022-12-06 16:26:51 +08:00
if ( strbuf -> allocated == 0 )
return ffStrbufInitVF ( strbuf , format , arguments );
ffStrbufClear ( strbuf );
2022-01-12 01:02:14 +01:00
ffStrbufAppendVF ( strbuf , format , arguments );
va_end ( arguments );
2021-03-19 20:57:07 +01:00
}
2022-09-24 19:22:33 +08:00
void ffStrbufAppendF ( FFstrbuf * strbuf , const char * format , ...)
2022-09-04 12:43:30 +02:00
{
2022-09-24 19:22:33 +08:00
assert ( format != NULL );
va_list arguments ;
va_start ( arguments , format );
ffStrbufAppendVF ( strbuf , format , arguments );
va_end ( arguments );
2022-09-04 12:43:30 +02:00
}
void ffStrbufPrependNS ( FFstrbuf * strbuf , uint32_t length , const char * value )
{
2022-09-24 19:22:33 +08:00
if ( value == NULL || length == 0 )
return ;
2022-09-04 12:43:30 +02:00
ffStrbufEnsureFree ( strbuf , length );
memmove ( strbuf -> chars + length , strbuf -> chars , strbuf -> length + 1 ); // + 1 for the null byte
memcpy ( strbuf -> chars , value , length );
strbuf -> length += length ;
}
2022-09-23 00:10:48 +02:00
void ffStrbufSetNS ( FFstrbuf * strbuf , uint32_t length , const char * value )
2021-03-19 20:57:07 +01:00
{
2022-01-12 01:02:14 +01:00
ffStrbufClear ( strbuf );
2022-09-23 00:10:48 +02:00
ffStrbufAppendNS ( strbuf , length , value );
2021-03-19 20:57:07 +01:00
}
2022-09-23 00:10:48 +02:00
void ffStrbufSet ( FFstrbuf * strbuf , const FFstrbuf * value )
2021-03-22 20:02:32 +01:00
{
2022-01-12 01:02:14 +01:00
ffStrbufClear ( strbuf );
2022-09-23 00:10:48 +02:00
ffStrbufAppendNS ( strbuf , value -> length , value -> chars );
2021-03-22 20:02:32 +01:00
}
2021-03-21 16:52:17 +01:00
void ffStrbufTrimLeft ( FFstrbuf * strbuf , char c )
{
2022-09-24 19:22:33 +08:00
if ( strbuf -> length == 0 ) //`allocated == 0` implies `length == 0`
2022-09-06 13:24:57 +02:00
return ;
2021-03-21 16:52:17 +01:00
uint32_t index = 0 ;
2021-05-13 12:27:44 +02:00
while ( index < strbuf -> length && strbuf -> chars [ index ] == c )
2021-03-21 16:52:17 +01:00
++ index ;
if ( index == 0 )
return ;
2021-04-25 19:12:05 +02:00
memmove ( strbuf -> chars , strbuf -> chars + index , strbuf -> length - index );
2021-03-21 16:52:17 +01:00
strbuf -> length -= index ;
2021-04-25 19:03:59 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
2021-03-21 16:52:17 +01:00
}
void ffStrbufTrimRight ( FFstrbuf * strbuf , char c )
2021-03-27 18:14:19 +01:00
{
2022-09-24 19:22:33 +08:00
if ( strbuf -> length == 0 )
2022-09-06 13:24:57 +02:00
return ;
2022-01-01 17:28:41 +01:00
while ( ffStrbufEndsWithC ( strbuf , c ))
2021-03-21 16:52:17 +01:00
-- strbuf -> length ;
2022-09-06 13:24:57 +02:00
2021-03-21 16:52:17 +01:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
}
void ffStrbufTrim ( FFstrbuf * strbuf , char c )
{
ffStrbufTrimRight ( strbuf , c );
ffStrbufTrimLeft ( strbuf , c );
}
2022-01-12 01:02:14 +01:00
void ffStrbufRemoveSubstr ( FFstrbuf * strbuf , uint32_t startIndex , uint32_t endIndex )
2021-03-28 13:02:40 +02:00
{
2022-01-12 01:02:14 +01:00
if ( startIndex > strbuf -> length || startIndex >= endIndex )
return ;
2021-03-28 13:02:40 +02:00
2022-01-12 01:02:14 +01:00
if ( endIndex > strbuf -> length )
{
ffStrbufSubstrBefore ( strbuf , startIndex );
return ;
2021-03-28 13:02:40 +02:00
}
2022-01-12 01:02:14 +01:00
memmove ( strbuf -> chars + startIndex , strbuf -> chars + endIndex , strbuf -> length - endIndex );
strbuf -> length -= ( endIndex - startIndex );
2021-03-28 13:02:40 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
2022-01-12 01:02:14 +01:00
}
void ffStrbufRemoveS ( FFstrbuf * strbuf , const char * str )
{
uint32_t stringLength = ( uint32_t ) strlen ( str );
for ( uint32_t i = ffStrbufNextIndexS ( strbuf , 0 , str ); i < strbuf -> length ; i = ffStrbufNextIndexS ( strbuf , i , str ))
ffStrbufRemoveSubstr ( strbuf , i , i + stringLength );
2021-03-28 13:02:40 +02:00
}
2023-07-25 14:53:57 +08:00
void ffStrbufRemoveStrings ( FFstrbuf * strbuf , uint32_t numStrings , const char * strings [])
2021-03-28 13:02:40 +02:00
{
2022-01-12 01:02:14 +01:00
for ( uint32_t i = 0 ; i < numStrings ; i ++ )
ffStrbufRemoveS ( strbuf , strings [ i ]);
2021-03-28 13:02:40 +02:00
}
2021-06-26 15:34:01 +02:00
uint32_t ffStrbufNextIndexC ( const FFstrbuf * strbuf , uint32_t start , char c )
2021-03-28 15:38:52 +02:00
{
2022-09-24 19:22:33 +08:00
assert ( start <= strbuf -> length );
2021-03-28 15:38:52 +02:00
2022-09-24 19:22:33 +08:00
const char * ptr = ( const char * ) memchr ( strbuf -> chars + start , c , strbuf -> length - start );
return ptr ? ( uint32_t )( ptr - strbuf -> chars ) : strbuf -> length ;
2021-07-12 19:01:31 +02:00
}
2022-09-24 19:22:33 +08:00
uint32_t ffStrbufNextIndexS ( const FFstrbuf * strbuf , uint32_t start , const char * str )
2021-07-12 19:01:31 +02:00
{
2022-09-24 19:22:33 +08:00
assert ( start <= strbuf -> length );
2021-07-12 19:01:31 +02:00
2022-09-24 19:22:33 +08:00
const char * ptr = strstr ( strbuf -> chars + start , str );
return ptr ? ( uint32_t )( ptr - strbuf -> chars ) : strbuf -> length ;
2021-05-05 21:12:42 +02:00
}
2021-06-26 15:34:01 +02:00
uint32_t ffStrbufPreviousIndexC ( const FFstrbuf * strbuf , uint32_t start , char c )
2021-03-28 13:02:40 +02:00
{
2022-09-24 19:22:33 +08:00
assert ( start <= strbuf -> length );
2021-06-26 15:34:01 +02:00
2021-03-28 13:02:40 +02:00
//We need to loop one higher than the actual index, because uint32_t is guranteed to be >= 0, so this statement would always be true
2021-06-26 15:34:01 +02:00
for ( uint32_t i = start + 1 ; i > 0 ; i -- )
2021-03-28 13:02:40 +02:00
{
if ( strbuf -> chars [ i - 1 ] == c )
return i - 1 ;
}
return strbuf -> length ;
}
2023-01-02 11:49:41 +08:00
void ffStrbufReplaceAllC ( FFstrbuf * strbuf , char find , char replace )
{
for ( char * current_pos = strchr ( strbuf -> chars , find ); current_pos ; current_pos = strchr ( current_pos + 1 , find ))
* current_pos = replace ;
}
2021-04-02 16:21:52 +02:00
void ffStrbufSubstrBefore ( FFstrbuf * strbuf , uint32_t index )
2021-03-28 13:02:40 +02:00
{
2021-04-02 16:21:52 +02:00
if ( strbuf -> length <= index )
2021-03-28 13:02:40 +02:00
return ;
2021-04-02 16:21:52 +02:00
strbuf -> length = index ;
2021-03-28 13:02:40 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
}
2022-01-10 20:20:18 +01:00
void ffStrbufSubstrBeforeFirstC ( FFstrbuf * strbuf , char c )
2021-04-02 16:21:52 +02:00
{
ffStrbufSubstrBefore ( strbuf , ffStrbufFirstIndexC ( strbuf , c ));
}
2022-01-10 20:20:18 +01:00
void ffStrbufSubstrBeforeLastC ( FFstrbuf * strbuf , char c )
2021-05-07 17:10:22 +02:00
{
ffStrbufSubstrBefore ( strbuf , ffStrbufLastIndexC ( strbuf , c ));
}
2021-04-02 16:21:52 +02:00
void ffStrbufSubstrAfter ( FFstrbuf * strbuf , uint32_t index )
{
if ( index >= strbuf -> length )
{
ffStrbufClear ( strbuf );
return ;
}
memmove ( strbuf -> chars , strbuf -> chars + index + 1 , strbuf -> length - index - 1 );
strbuf -> length -= ( index + 1 );
2021-04-03 23:10:14 +02:00
strbuf -> chars [ strbuf -> length ] = '\0' ;
2021-04-02 16:21:52 +02:00
}
2022-01-10 20:20:18 +01:00
void ffStrbufSubstrAfterFirstC ( FFstrbuf * strbuf , char c )
2021-05-07 17:10:22 +02:00
{
uint32_t index = ffStrbufFirstIndexC ( strbuf , c );
if ( index < strbuf -> length )
ffStrbufSubstrAfter ( strbuf , index );
}
2022-01-10 20:20:18 +01:00
void ffStrbufSubstrAfterFirstS ( FFstrbuf * strbuf , const char * str )
{
2022-01-12 01:02:14 +01:00
if ( * str == '\0' )
return ;
uint32_t index = ffStrbufFirstIndexS ( strbuf , str ) + ( uint32_t ) strlen ( str ) - 1 ; // -1, because firstIndexS is already pointing to str[0], we want to add only the remaining length
2022-01-10 20:20:18 +01:00
if ( index < strbuf -> length )
ffStrbufSubstrAfter ( strbuf , index );
}
void ffStrbufSubstrAfterLastC ( FFstrbuf * strbuf , char c )
2021-04-02 16:21:52 +02:00
{
uint32_t index = ffStrbufLastIndexC ( strbuf , c );
if ( index < strbuf -> length )
ffStrbufSubstrAfter ( strbuf , index );
}
2022-04-21 17:59:26 +02:00
uint32_t ffStrbufCountC ( const FFstrbuf * strbuf , char c )
{
uint32_t result = 0 ;
for ( uint32_t i = 0 ; i < strbuf -> length ; i ++ )
{
if ( strbuf -> chars [ i ] == c )
result ++ ;
}
2022-09-24 19:22:33 +08:00
2022-04-21 17:59:26 +02:00
return result ;
}
2021-06-26 16:48:15 +02:00
bool ffStrbufRemoveIgnCaseEndS ( FFstrbuf * strbuf , const char * end )
{
2022-09-24 23:17:38 +08:00
uint32_t endLength = ( uint32_t ) strlen ( end );
if ( ffStrbufEndsWithIgnCaseNS ( strbuf , endLength , end ))
2021-06-26 16:48:15 +02:00
{
ffStrbufSubstrBefore ( strbuf , strbuf -> length - endLength );
return true ;
}
return false ;
}
2022-06-22 20:14:10 +02:00
void ffStrbufEnsureEndsWithC ( FFstrbuf * strbuf , char c )
{
if ( ! ffStrbufEndsWithC ( strbuf , c ))
ffStrbufAppendC ( strbuf , c );
}
2022-01-12 01:02:14 +01:00
void ffStrbufWriteTo ( const FFstrbuf * strbuf , FILE * file )
2021-04-05 19:25:34 +02:00
{
2022-01-12 01:02:14 +01:00
fwrite ( strbuf -> chars , sizeof ( * strbuf -> chars ), strbuf -> length , file );
}
void ffStrbufPutTo ( const FFstrbuf * strbuf , FILE * file )
{
ffStrbufWriteTo ( strbuf , file );
fputc ( '\n' , file );
2021-04-05 19:25:34 +02:00
}
2022-06-16 14:55:02 +02:00
double ffStrbufToDouble ( const FFstrbuf * strbuf )
{
2022-09-24 19:22:33 +08:00
char * str_end ;
double result = strtod ( strbuf -> chars , & str_end );
return str_end == strbuf -> chars ? 0.0 / 0.0 : result ;
2022-06-16 14:55:02 +02:00
}
2022-09-04 22:20:12 +02:00
uint16_t ffStrbufToUInt16 ( const FFstrbuf * strbuf , uint16_t defaultValue )
{
2022-09-24 19:22:33 +08:00
char * str_end ;
unsigned long result = strtoul ( strbuf -> chars , & str_end , 10 );
return str_end == strbuf -> chars || result > UINT16_MAX ? defaultValue : ( uint16_t ) result ;
2022-09-04 22:20:12 +02:00
}