public: add new features to ParseFileSafe, such as disabling interpreting certain characters as separate tokens, or instead forcing them to be separate tokens

This commit is contained in:
Alibek Omarov
2026-02-28 02:49:37 +05:00
parent 56255f6de0
commit 192ed942c4
5 changed files with 92 additions and 21 deletions

View File

@@ -3218,7 +3218,8 @@ handle colon separately
*/
static char *pfnParseFile( char *data, char *token )
{
return COM_ParseFileSafe( data, token, PFILE_TOKEN_MAX_LENGTH, PFILE_HANDLECOLON, NULL, NULL );
// GoldSrc uses 1024 byte tokens
return COM_ParseFileSafe( data, token, 1024, PFILE_HANDLECOLON, NULL, NULL );
}
/*

View File

@@ -412,7 +412,8 @@ public:
qboolean qquoted;
char *p;
p = COM_ParseFileSafe( buf, token, PFILE_FS_TOKEN_MAX_LENGTH, 0, nullptr, &qquoted );
// filesystem_stdio expects 512 byte buffers
p = COM_ParseFileSafe( buf, token, 512, 0, nullptr, &qquoted );
if( quoted )
*quoted = qquoted;

View File

@@ -666,14 +666,23 @@ interpert this character as single
*/
static int COM_IsSingleChar( unsigned int flags, char c )
{
if( c == '{' || c == '}' || c == '\'' || c == ',' )
return true;
if( !FBitSet( flags, PFILE_IGNOREBRACKET ) && ( c == ')' || c == '(' ))
return true;
if( FBitSet( flags, PFILE_HANDLECOLON ) && c == ':' )
switch( c )
{
case '}':
case '{':
return true;
case ',':
return !FBitSet( flags, PFILE_NO_COMMA_AS_TOKEN );
case '\'':
return !FBitSet( flags, PFILE_NO_SINGLE_QUOTE_AS_TOKEN );
case '(':
case ')':
return !FBitSet( flags, PFILE_NO_BRACKETS_AS_TOKEN );
case ':':
return FBitSet( flags, PFILE_COLON_AS_TOKEN );
case '\n':
return FBitSet( flags, PFILE_NEWLINE_AS_TOKEN );
}
return false;
}
@@ -707,6 +716,9 @@ char *COM_ParseFileSafe( char *data, char *token, const int size, unsigned int f
skipwhite:
while(( c = ((byte)*data)) <= ' ' )
{
if( FBitSet( flags, PFILE_NEWLINE_AS_TOKEN ) && c == '\n' )
break;
if( c == 0 )
{
if( plen ) *plen = overflow ? -1 : len;
@@ -716,7 +728,7 @@ skipwhite:
}
// skip // or #, if requested, comments
if(( c == '/' && data[1] == '/' ) || ( c == '#' && FBitSet( flags, PFILE_IGNOREHASHCMT )))
if(( c == '/' && data[1] == '/' ) || ( c == '#' && FBitSet( flags, PFILE_HASH_AS_COMMENT )))
{
while( *data && *data != '\n' )
data++;
@@ -724,7 +736,7 @@ skipwhite:
}
// handle quoted strings specially
if( c == '\"' )
if( c == '\"' && !FBitSet( flags, PFILE_NO_QUOTED_TOKENS ))
{
if( quoted )
*quoted = true;

View File

@@ -41,12 +41,29 @@ enum
// a1ba: not using BIT macro, so flags can be copypasted into
// exported APIs headers and will not get warning in case of changing values
#define PFILE_IGNOREBRACKET (1<<0)
#define PFILE_HANDLECOLON (1<<1)
#define PFILE_IGNOREHASHCMT (1<<2)
#define PFILE_TOKEN_MAX_LENGTH 1024
#define PFILE_FS_TOKEN_MAX_LENGTH 512
// do NOT interpret brackets as separate token
// e.g. (a b) will be parsed as "(a", "b)"
#define PFILE_NO_BRACKETS_AS_TOKEN ( 1U << 0 )
// interpret ':' as separate token
// e.g. a:b will be parsed as "a", ":", "b"
#define PFILE_COLON_AS_TOKEN ( 1U << 1 )
// ignore the whole line starting with '#' interpreting it as comment
#define PFILE_HASH_AS_COMMENT ( 1U << 2 )
// when encountering double quotes, do not interpret what's inside as single token
#define PFILE_NO_QUOTED_TOKENS ( 1U << 3 )
// do NOT interpret ''' as separate token
#define PFILE_NO_SINGLE_QUOTE_AS_TOKEN ( 1U << 4 )
// do NOT interpret comma as token
#define PFILE_NO_COMMA_AS_TOKEN ( 1U << 5 )
// interpret '\n' as separate token
#define PFILE_NEWLINE_AS_TOKEN ( 1U << 6 )
#ifdef __cplusplus
#define restrict

View File

@@ -1,3 +1,4 @@
#include <stdio.h>
#include "crtlib.h"
static const char *test_file =
@@ -7,7 +8,15 @@ static const char *test_file =
"bashlikecomment #notignored test\n"
"#ignore comment\n"
"thisshall #be ignored\n"
"test_sentinel\n";
"test_sentinel\n"
"ignore:colon\n"
"notignore:colon\n"
"(a b)\n"
"\"test1\"\n"
"// comment\n"
"'a 'b\n"
",a ,b\n"
;
int main( void )
{
@@ -29,9 +38,25 @@ int main( void )
{ 5, "bark", 4 },
{ 32, "bashlikecomment", 15 },
{ 32, "#notignored", 11 },
{ 32, "test", 4, PFILE_IGNOREHASHCMT },
{ 32, "thisshall", 9, PFILE_IGNOREHASHCMT },
{ 32, "test_sentinel", 13, PFILE_IGNOREHASHCMT },
{ 32, "test", 4, PFILE_HASH_AS_COMMENT },
{ 32, "thisshall", 9, PFILE_HASH_AS_COMMENT },
{ 32, "test_sentinel", 13, PFILE_HASH_AS_COMMENT },
{ 32, "ignore:colon", 12, },
{ 32, "notignore", 9, PFILE_COLON_AS_TOKEN },
{ 32, ":", 1, PFILE_COLON_AS_TOKEN },
{ 32, "colon", 5, PFILE_COLON_AS_TOKEN },
{ 32, "(a", 2, PFILE_NO_BRACKETS_AS_TOKEN },
{ 32, "b", 1, },
{ 32, ")", 1, },
{ 32, "\"test1\"", 7, PFILE_NO_QUOTED_TOKENS },
{ 32, "\n", 1, PFILE_NEWLINE_AS_TOKEN },
{ 32, "'a", 2, PFILE_NO_SINGLE_QUOTE_AS_TOKEN },
{ 32, "'", 1, },
{ 32, "b", 1, },
{ 32, ",a", 2, PFILE_NO_COMMA_AS_TOKEN },
{ 32, ",", 1, },
{ 32, "b", 1, },
{ 32, NULL }, // EOF
};
for( i = 0; i < sizeof( testdata ) / sizeof( testdata[0] ); i++ )
@@ -41,12 +66,27 @@ int main( void )
file = COM_ParseFileSafe( file, buf, testdata[i].bufsize, testdata[i].flags, &len, NULL );
if( file == NULL )
if( testdata[i].expected == NULL && file != NULL )
{
printf( "expected NULL, but got no NULL\n" );
return i;
}
if( testdata[i].expected != NULL && file == NULL )
{
printf( "expected no NULL, but got NULL\n" );
return i;
}
if( testdata[i].expected == NULL && file == NULL )
continue;
if( !( !Q_strcmp( buf, testdata[i].expected ) && len == testdata[i].expected_len ))
{
printf( "expected '%s' with length %d, got '%s' with length %d\n", testdata[i].expected, testdata[i].expected_len, buf, len );
return i;
}
}
return 0;
}