summaryrefslogtreecommitdiff
path: root/src/util/config.h
blob: d8c1c2ec18ed8c9687f79695f4b31e1f3e00662a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#pragma once
#include <stdio.h>

#include "string.h"
#include "vector.h"
#include "color.h"

// config parsers and serializers go here

struct CFG_NODE;
struct CFG_SECTION;

struct CFG_PARSER;
struct CFG_SERIALIZER;

enum CfgNodeType_t {
  CFGT_SECTION,
  CFGT_BYTES,
  CFGT_STR,
  CFGT_FLOAT,
  CFGT_INT,
  CFGT_VEC2,
  CFGT_VEC3,
  CFGT_CLR
};

// ===================================== [ definitions ] ===========================================

using CFG_PARSEFN = FN<STAT( CFG_PARSER*, CFG_SECTION*, char* )>;
using CFG_SERIALIZEFN = FN<STR( CFG_SERIALIZER*, CFG_NODE*)>;

struct CFG_TYPE {
  U8 type;
  const char* def;
  CFG_PARSEFN parser;
  CFG_SERIALIZEFN serializer;
};

struct CFG_NODE {
  STR name;
  CFG_NODE* parent;
  U8 type;
};

struct CFG_SECTION : CFG_NODE {
  LIST<CFG_NODE*> children;
};

struct CFG_BYTES : CFG_NODE { U8* bytes; U32 size; };
struct CFG_STR   : CFG_NODE { char* str; U32 len; };
struct CFG_INT   : CFG_NODE { I32 value; };
struct CFG_FLOAT : CFG_NODE { F32 value; };
struct CFG_VEC2  : CFG_NODE { VEC2 value; };
struct CFG_VEC3  : CFG_NODE { VEC3 value; };
struct CFG_CLR   : CFG_NODE { CLR value; };

// ======================================= [ parsers ] =============================================

extern STAT cfg_parser_bytes( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_str( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_int( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_float( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_vec2( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_vec3( CFG_PARSER* parser, CFG_SECTION* section, char* name );
extern STAT cfg_parser_clr( CFG_PARSER* parser, CFG_SECTION* section, char* name );

// ====================================== [ serializers ] ==========================================

extern STR cfg_serialize_section( CFG_SERIALIZER* serializer, CFG_NODE* section );
extern STR cfg_serialize_bytes( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_str( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_float( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_int( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_vec2( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_vec3( CFG_SERIALIZER* serializer, CFG_NODE* node );
extern STR cfg_serialize_clr( CFG_SERIALIZER* serializer, CFG_NODE* node );

// ========================================= [ config ] ============================================

static const CFG_TYPE cfg_types[] = {
  { CFGT_SECTION, "DEF" ,                 0, &cfg_serialize_section }, // section
  { CFGT_BYTES  , "U8"  , &cfg_parser_bytes, &cfg_serialize_bytes   },
  { CFGT_STR    , "STR" , &cfg_parser_str  , &cfg_serialize_str     },
  { CFGT_FLOAT  , "F32" , &cfg_parser_float, &cfg_serialize_float   },
  { CFGT_INT    , "I32" , &cfg_parser_int  , &cfg_serialize_int     },
  { CFGT_VEC2   , "VEC2", &cfg_parser_vec2 , &cfg_serialize_vec2    },
  { CFGT_VEC3   , "VEC3", &cfg_parser_vec3 , &cfg_serialize_vec3    },
  { CFGT_CLR    , "CLR" , &cfg_parser_clr  , &cfg_serialize_clr     },
};
// ========================================= [ io ] ================================================

extern CFG_SECTION* cfg_load( const char* path );
extern STAT         cfg_save( CFG_SECTION* root, const char* path );
static void         cfg_free( CFG_NODE* n );

// =================================== [ getters/setters ] =========================================

// cfg_section_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_SECTION* cfg_section( CFG_SECTION* parent, const char* name );
// cfg_str_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_STR*     cfg_str( CFG_SECTION* section, const char* name );
// cfg_bytes_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_BYTES*   cfg_bytes( CFG_SECTION* section, const char* name );
// cfg_float_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_FLOAT*   cfg_float( CFG_SECTION* section, const char* name );
// cfg_int_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_INT*     cfg_int( CFG_SECTION* section, const char* name );
// cfg_vec2_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_VEC2*   cfg_vec2( CFG_SECTION* section, const char* name );
// cfg_vec3_get( CFG_SECTION*, const char* ) -- retrieve function
extern CFG_VEC3*   cfg_vec3( CFG_SECTION* section, const char* name );
// cfg_clr_get( CFG_SECTION*, const char* ) -- retrieve function for
extern CFG_CLR*     cfg_clr( CFG_SECTION* section, const char* name );

// cfg_section_new( const char*, CFG_NODE*, I32 ) -- create function
extern CFG_SECTION* cfg_section_new( const char* name, CFG_NODE* parent );
// cfg_str_new( const char*, CFG_NODE*, const char*, U32 ) -- create function
extern CFG_STR*     cfg_str( const char* name, CFG_NODE* section, const char* value, U32 len );
// cfg_bytes_new( const char*, CFG_NODE*, U8*, U32 ) -- create function
extern CFG_BYTES*   cfg_bytes( const char* name, CFG_NODE* section, U8* value, U32 size );
// cfg_float_new( const char*, CFG_NODE*, F32 ) -- create function
extern CFG_FLOAT*   cfg_float( const char* name, CFG_NODE* section, F32 value );
// cfg_int_new( const char*, CFG_NODE*, I32 ) -- create function
extern CFG_INT*     cfg_int( const char* name, CFG_NODE* section, I32 value );
// cfg_vec2_new( const char*, CFG_NODE*, VEC2 ) -- create function
extern CFG_VEC2*    cfg_vec2( const char* name, CFG_NODE* section, VEC2 value );
// cfg_vec3_new( const char*, CFG_NODE*, VEC3 ) -- create function
extern CFG_VEC3*    cfg_vec3( const char* name, CFG_NODE* section, VEC3 value );
// cfg_clr_new( const char*, CFG_NODE*, CLR ) -- create function
extern CFG_CLR*     cfg_clr( const char* name, CFG_NODE* section, CLR value );

// =================================================================================================

struct CFG_PARSER {
  FILE* file;
  CFG_SECTION* root;
  char err[256];
  U32 linen;
  U8 iserr;
};

struct CFG_SERIALIZER {
  FILE* f;
  U8 iserr;
  char err[256];
  U32 tabc;
};

static void cfg_free( CFG_NODE* n ) {
  if( n->type == CFGT_STR ) {
    CFG_STR* str = (CFG_STR*)n;
    free( str->str );
  }
  else if( n->type == CFGT_BYTES ) {
    CFG_BYTES* bytes = (CFG_BYTES*)n;
    free( bytes->bytes );
  }
  else if( n->type == CFGT_SECTION ) {
    CFG_SECTION* s = (CFG_SECTION*)n;
    s->children.each( fn( CFG_NODE** child ) { cfg_free( *child ); } );
    return delete s;
  }

  delete n;
}

extern void cfg_seterr( CFG_PARSER* p, const char* fmt, ... );