summaryrefslogtreecommitdiff
path: root/src/util/config/config.cpp
diff options
context:
space:
mode:
authornavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
committernavewindre <boneyaard@gmail.com>2025-09-03 20:10:09 +0200
commitf8b92ce3aa08b1445c9f956d8166830946562d12 (patch)
tree94e63a5aec9f8f52b577f56799e0c9201fd976a5 /src/util/config/config.cpp
a
Diffstat (limited to 'src/util/config/config.cpp')
-rw-r--r--src/util/config/config.cpp263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/util/config/config.cpp b/src/util/config/config.cpp
new file mode 100644
index 0000000..1601afe
--- /dev/null
+++ b/src/util/config/config.cpp
@@ -0,0 +1,263 @@
+#include <cstdarg>
+#include <cstdio>
+
+#include "../config.h"
+
+void cfg_seterr( CFG_PARSER* p, const char* fmt, ... ) {
+ va_list args;
+ va_start( args, fmt );
+ vsnprintf( p->err, sizeof(p->err), fmt, args );
+ p->iserr = 1;
+ va_end( args );
+}
+
+inline U8 is_whitespace( char c ) {
+ return c == ' ' || c == '\t' || c == '\n';
+}
+
+inline void trim_whitespace( char* buf ) {
+ U32 i;
+ for( i = 0; !!buf[i]; ++i )
+ if( !is_whitespace( buf[i] ) ) break;
+ for( U32 i2 = i; !!buf[i2]; ++i2 ) {
+ if( is_whitespace( buf[i2] ) ) {
+ buf[i2 - i] = 0;
+ return;
+ }
+ buf[i2 - i] = buf[i2];
+ }
+}
+
+inline void init_cfg_node( CFG_NODE* node, const char* name, CFG_NODE* parent, U8 type ) {
+ memset( node->name, 0, sizeof(node->name) );
+ strcpy( node->name, name );
+ node->name[sizeof(node->name) - 1] = '\0';
+ node->parent = parent;
+ if( parent )
+ ( (CFG_SECTION*)parent )->children.push( node );
+ node->type = type;
+}
+
+CFG_SECTION* cfg_section_new( const char* name, CFG_NODE* parent ) {
+ CFG_SECTION* section = new CFG_SECTION;
+ init_cfg_node( (CFG_NODE*)section, name, parent, CFGT_SECTION );
+ return section;
+}
+
+CFG_BYTES* cfg_bytes( const char* name, CFG_NODE* parent, U8* bytes, U32 size ) {
+ CFG_BYTES* cfg_bytes = new CFG_BYTES;
+ init_cfg_node( (CFG_NODE*)cfg_bytes, name, parent, CFGT_BYTES );
+ cfg_bytes->bytes = bytes;
+ cfg_bytes->size = size;
+ return cfg_bytes;
+}
+
+CFG_STR* cfg_str( const char* name, CFG_NODE* parent, const char* str, U32 len ) {
+ CFG_STR* cfg_str = new CFG_STR;
+ init_cfg_node( (CFG_NODE*)cfg_str, name, parent, CFGT_STR );
+ cfg_str->str = (char*)malloc( len + 1 );
+ strcpy( cfg_str->str, str );
+ cfg_str->str[len] = '\0';
+ cfg_str->len = len;
+ return cfg_str;
+}
+
+CFG_INT* cfg_int( const char* name, CFG_NODE* parent, I32 value ) {
+ CFG_INT* cfg_int = new CFG_INT;
+ init_cfg_node( (CFG_NODE*)cfg_int, name, parent, CFGT_INT );
+ cfg_int->value = value;
+ return cfg_int;
+}
+
+CFG_FLOAT* cfg_float( const char* name, CFG_NODE* parent, F32 value) {
+ CFG_FLOAT* cfg_float = new CFG_FLOAT;
+ init_cfg_node( (CFG_NODE*)cfg_float, name, parent, CFGT_FLOAT );
+ cfg_float->value = value;
+ return cfg_float;
+}
+
+CFG_VEC2* cfg_vec2( const char* name, CFG_NODE* parent, VEC2 value ) {
+ CFG_VEC2* cfg_vec2 = new CFG_VEC2;
+ init_cfg_node( (CFG_NODE*)cfg_vec2, name, parent, CFGT_VEC2 );
+ cfg_vec2->value = value;
+ return cfg_vec2;
+}
+
+CFG_VEC3* cfg_vec3( const char* name, CFG_NODE* parent, VEC3 value ) {
+ CFG_VEC3* cfg_vec3 = new CFG_VEC3;
+ init_cfg_node( (CFG_NODE*)cfg_vec3, name, parent, CFGT_VEC3 );
+ cfg_vec3->value = value;
+ return cfg_vec3;
+}
+
+CFG_CLR* cfg_clr( const char* name, CFG_NODE* parent, CLR value ) {
+ CFG_CLR* cfg_clr = new CFG_CLR;
+ init_cfg_node( (CFG_NODE*)cfg_clr, name, parent, CFGT_CLR );
+ cfg_clr->value = value;
+ return cfg_clr;
+}
+
+CFG_SECTION* cfg_section( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_SECTION && strcmp( n->name, name ) == 0 )
+ return (CFG_SECTION*)n;
+ }
+
+ return 0;
+}
+
+CFG_BYTES* cfg_bytes( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_BYTES && strcmp( n->name, name ) == 0 )
+ return (CFG_BYTES*)n;
+ }
+
+ return 0;
+}
+
+CFG_STR* cfg_str( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_STR && strcmp( n->name, name ) == 0 )
+ return (CFG_STR*)n;
+ }
+
+ return 0;
+}
+
+CFG_INT* cfg_int( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_INT && strcmp( n->name, name ) == 0 )
+ return (CFG_INT*)n;
+ }
+
+ return 0;
+}
+
+CFG_FLOAT* cfg_float( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_FLOAT && strcmp( n->name, name ) == 0 )
+ return (CFG_FLOAT*)n;
+ }
+ return 0;
+}
+
+CFG_VEC2* cfg_vec2( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_VEC2 && strcmp( n->name, name ) == 0 )
+ return (CFG_VEC2*)n;
+ }
+ return 0;
+}
+
+CFG_VEC3* cfg_vec3( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_VEC3 && strcmp( n->name, name ) == 0 )
+ return (CFG_VEC3*)n;
+ }
+ return 0;
+}
+
+CFG_CLR* cfg_clr( CFG_SECTION* parent, const char* name ) {
+ for( I32 i = 0; i < parent->children.size; ++i ) {
+ CFG_NODE* n = parent->children[i];
+ if( n->type == CFGT_CLR && strcmp( n->name, name ) == 0 )
+ return (CFG_CLR*)n;
+ }
+ return 0;
+}
+
+void parse_section( CFG_PARSER* parser, CFG_SECTION* current_section ) {
+ char line[8192];
+ char* token;
+ char* next_token;
+
+ while( fgets( line, sizeof(line), parser->file ) ) {
+ token = strtok( line, " \t\n" );
+ if( !token ) continue;
+ if( strcmp( token, "{" ) == 0 )
+ continue;
+ else if( strcmp( token, "}" ) == 0 ) {
+ return;
+ } else if( strcmp( token, cfg_types[CFGT_SECTION].def ) == 0 ) {
+ next_token = strtok( NULL, " \t\n" );
+ char sectname[64];
+ strcpy( sectname, next_token );
+ trim_whitespace( sectname );
+
+ CFG_SECTION* new_section = cfg_section_new( sectname, (CFG_NODE*)current_section );
+ strtok( NULL, " \t\n" );
+ parse_section( parser, new_section );
+ } else {
+ char name[64];
+ strcpy( name, token );
+ trim_whitespace( name );
+
+ token = strtok( NULL, "=[" );
+ if( !token )
+ continue;
+
+ char varname[64];
+ strcpy( varname, token );
+ trim_whitespace( varname );
+
+ for( I32 i = 0; i < sizeof(cfg_types) / sizeof(CFG_TYPE); ++i ) {
+ const CFG_TYPE* fn = &cfg_types[i];
+ if( strncmp( name, fn->def, strlen( fn->def ) ) == 0 ) {
+ fn->parser( parser, current_section, varname );
+ break;
+ }
+ }
+
+ if( parser->iserr ) {
+ dlog( "parse_section() : %s parse error:\n - %s\n", name, parser->err );
+ return;
+ }
+ }
+
+ parser->linen++;
+ }
+}
+
+CFG_SECTION* cfg_load( const char* path ) {
+ FILE* f = fopen( path, "rb" );
+ if( !f )
+ return 0;
+
+ CFG_PARSER p;
+ p.iserr = 0;
+ p.file = f;
+ p.linen = 0;
+ p.root = cfg_section_new( "root", 0 );
+ parse_section( &p, p.root );
+
+ fclose( f );
+ return p.root;
+}
+
+STAT cfg_save( CFG_SECTION* root, const char* path ) {
+ FILE* f = fopen( path, "w" );
+ if( !f )
+ return STAT_ERR;
+
+ char* buf = (char*)malloc( 999999 );
+ buf[0] = 0;
+ CFG_SERIALIZER s;
+ s.tabc = 0;
+ s.f = f;
+
+ cfg_serialize_section( &s, (CFG_NODE*)root, buf );
+ U32 len = strlen( buf );
+
+ fwrite( buf, 1, len, f );
+ free( buf );
+
+ fclose( f );
+ return STAT_OK;
+}