1 #include "cfg.h" |
1 #include "cfg.h" |
2 |
2 |
3 #include "../util/inihelper.h" |
3 #include "../util/inihelper.h" |
4 #include "../util/logging.h" |
4 #include "../util/logging.h" |
5 #include "../util/util.h" |
5 #include "../util/util.h" |
|
6 #include "../util/refcounter.h" |
6 |
7 |
7 #include <stdio.h> |
8 #include <stdio.h> |
8 #include <stdlib.h> |
9 #include <stdlib.h> |
|
10 #include <limits.h> |
|
11 #include <string.h> |
9 |
12 |
10 static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *settingfile, flib_ini *modfile) { |
13 static void flib_cfg_meta_destroy(flib_cfg_meta *cfg) { |
11 flib_cfg_meta_destroy(result); |
|
12 flib_ini_destroy(settingfile); |
|
13 flib_ini_destroy(modfile); |
|
14 return NULL; |
|
15 } |
|
16 |
|
17 flib_cfg_meta *flib_cfg_meta_from_ini(const char *settingpath, const char *modpath) { |
|
18 if(!settingpath || !modpath) { |
|
19 flib_log_e("null parameter in flib_cfg_meta_from_ini"); |
|
20 return NULL; |
|
21 } |
|
22 flib_cfg_meta *result = flib_calloc(1, sizeof(flib_cfg_meta)); |
|
23 flib_ini *settingfile = flib_ini_load(settingpath); |
|
24 flib_ini *modfile = flib_ini_load(modpath); |
|
25 |
|
26 if(!result || !settingfile || !modfile) { |
|
27 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
28 } |
|
29 |
|
30 result->settingCount = flib_ini_get_sectioncount(settingfile); |
|
31 result->modCount = flib_ini_get_sectioncount(modfile); |
|
32 result->settings = flib_calloc(result->settingCount, sizeof(flib_cfg_setting_meta)); |
|
33 result->mods = flib_calloc(result->modCount, sizeof(flib_cfg_mod_meta)); |
|
34 |
|
35 if(!result->settings || !result->mods) { |
|
36 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
37 } |
|
38 |
|
39 for(int i=0; i<result->settingCount; i++) { |
|
40 result->settings[i].iniName = flib_ini_get_sectionname(settingfile, i); |
|
41 if(!result->settings[i].iniName) { |
|
42 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
43 } |
|
44 |
|
45 bool error = false; |
|
46 error |= flib_ini_enter_section(settingfile, result->settings[i].iniName); |
|
47 error |= flib_ini_get_str(settingfile, &result->settings[i].title, "title"); |
|
48 error |= flib_ini_get_str(settingfile, &result->settings[i].engineCommand, "command"); |
|
49 error |= flib_ini_get_str(settingfile, &result->settings[i].image, "image"); |
|
50 error |= flib_ini_get_bool(settingfile, &result->settings[i].checkOverMax, "checkOverMax"); |
|
51 error |= flib_ini_get_bool(settingfile, &result->settings[i].times1000, "times1000"); |
|
52 error |= flib_ini_get_int(settingfile, &result->settings[i].min, "min"); |
|
53 error |= flib_ini_get_int(settingfile, &result->settings[i].max, "max"); |
|
54 error |= flib_ini_get_int(settingfile, &result->settings[i].def, "default"); |
|
55 |
|
56 if(error) { |
|
57 flib_log_e("Missing or malformed ini parameter in file %s, section %s", settingpath, result->settings[i].iniName); |
|
58 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
59 } |
|
60 } |
|
61 |
|
62 for(int i=0; i<result->modCount; i++) { |
|
63 result->mods[i].iniName = flib_ini_get_sectionname(modfile, i); |
|
64 if(!result->mods[i].iniName) { |
|
65 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
66 } |
|
67 |
|
68 bool error = false; |
|
69 error |= flib_ini_enter_section(modfile, result->mods[i].iniName); |
|
70 error |= flib_ini_get_int(modfile, &result->mods[i].bitmaskIndex, "bitmaskIndex"); |
|
71 if(error) { |
|
72 flib_log_e("Missing or malformed ini parameter in file %s, section %s", modpath, result->mods[i].iniName); |
|
73 return flib_cfg_meta_from_ini_handleError(result, settingfile, modfile); |
|
74 } |
|
75 } |
|
76 |
|
77 flib_ini_destroy(settingfile); |
|
78 flib_ini_destroy(modfile); |
|
79 return result; |
|
80 } |
|
81 |
|
82 void flib_cfg_meta_destroy(flib_cfg_meta *cfg) { |
|
83 if(cfg) { |
14 if(cfg) { |
84 if(cfg->settings) { |
15 if(cfg->settings) { |
85 for(int i=0; i<cfg->settingCount; i++) { |
16 for(int i=0; i<cfg->settingCount; i++) { |
86 free(cfg->settings[i].iniName); |
17 free(cfg->settings[i].name); |
87 free(cfg->settings[i].title); |
|
88 free(cfg->settings[i].engineCommand); |
18 free(cfg->settings[i].engineCommand); |
89 free(cfg->settings[i].image); |
|
90 } |
19 } |
91 free(cfg->settings); |
20 free(cfg->settings); |
92 } |
21 } |
93 if(cfg->mods) { |
22 if(cfg->mods) { |
94 for(int i=0; i<cfg->modCount; i++) { |
23 for(int i=0; i<cfg->modCount; i++) { |
95 free(cfg->mods[i].iniName); |
24 free(cfg->mods[i].name); |
96 } |
25 } |
97 free(cfg->mods); |
26 free(cfg->mods); |
98 } |
27 } |
99 free(cfg); |
28 free(cfg); |
100 } |
29 } |
101 } |
30 } |
102 |
31 |
103 flib_cfg *flib_cfg_create(const flib_cfg_meta *meta, const char *schemeName) { |
32 static void flib_cfg_destroy(flib_cfg* cfg) { |
104 flib_cfg *result = flib_calloc(1, sizeof(flib_cfg)); |
33 if(cfg) { |
|
34 flib_cfg_meta_release(cfg->meta); |
|
35 free(cfg->mods); |
|
36 free(cfg->settings); |
|
37 free(cfg->schemeName); |
|
38 free(cfg); |
|
39 } |
|
40 } |
|
41 |
|
42 static flib_cfg_meta *flib_cfg_meta_from_ini_handleError(flib_cfg_meta *result, flib_ini *ini) { |
|
43 flib_cfg_meta_destroy(result); |
|
44 flib_ini_destroy(ini); |
|
45 return NULL; |
|
46 } |
|
47 |
|
48 static int readMetaSettingSections(flib_ini *ini, flib_cfg_meta *result, int limit) { |
|
49 while(result->settingCount<limit) { |
|
50 char sectionName[32]; |
|
51 if(snprintf(sectionName, sizeof(sectionName), "setting%i", result->settingCount) <= 0) { |
|
52 return -1; |
|
53 } |
|
54 if(!flib_ini_enter_section(ini, sectionName)) { |
|
55 flib_cfg_setting_meta *metasetting = &result->settings[result->settingCount]; |
|
56 result->settingCount++; |
|
57 |
|
58 bool error = false; |
|
59 error |= flib_ini_get_str(ini, &metasetting->name, "name"); |
|
60 error |= flib_ini_get_str_opt(ini, &metasetting->engineCommand, "command", NULL); |
|
61 error |= flib_ini_get_bool(ini, &metasetting->times1000, "times1000"); |
|
62 error |= flib_ini_get_bool(ini, &metasetting->maxMeansInfinity, "maxmeansinfinity"); |
|
63 error |= flib_ini_get_int(ini, &metasetting->min, "min"); |
|
64 error |= flib_ini_get_int(ini, &metasetting->max, "max"); |
|
65 error |= flib_ini_get_int(ini, &metasetting->def, "default"); |
|
66 if(error) { |
|
67 flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName); |
|
68 return -1; |
|
69 } |
|
70 } else { |
|
71 return 0; |
|
72 } |
|
73 } |
|
74 return 0; |
|
75 } |
|
76 |
|
77 static int readMetaModSections(flib_ini *ini, flib_cfg_meta *result, int limit) { |
|
78 while(result->modCount<limit) { |
|
79 char sectionName[32]; |
|
80 if(snprintf(sectionName, sizeof(sectionName), "mod%i", result->modCount) <= 0) { |
|
81 return -1; |
|
82 } |
|
83 if(!flib_ini_enter_section(ini, sectionName)) { |
|
84 flib_cfg_mod_meta *metamod = &result->mods[result->modCount]; |
|
85 result->modCount++; |
|
86 |
|
87 bool error = false; |
|
88 error |= flib_ini_get_str(ini, &metamod->name, "name"); |
|
89 error |= flib_ini_get_int(ini, &metamod->bitmaskIndex, "bitmaskIndex"); |
|
90 if(error) { |
|
91 flib_log_e("Missing or malformed ini parameter in metaconfig, section %s", sectionName); |
|
92 return -1; |
|
93 } |
|
94 } else { |
|
95 return 0; |
|
96 } |
|
97 } |
|
98 return 0; |
|
99 } |
|
100 |
|
101 flib_cfg_meta *flib_cfg_meta_from_ini(const char *filename) { |
|
102 if(!filename) { |
|
103 flib_log_e("null parameter in flib_cfg_meta_from_ini"); |
|
104 return NULL; |
|
105 } |
|
106 flib_cfg_meta *result = flib_cfg_meta_retain(flib_calloc(1, sizeof(flib_cfg_meta))); |
|
107 flib_ini *ini = flib_ini_load(filename); |
|
108 |
|
109 if(!result || !ini) { |
|
110 return flib_cfg_meta_from_ini_handleError(result, ini); |
|
111 } |
|
112 |
|
113 // We're overallocating here for simplicity |
|
114 int sectionCount = flib_ini_get_sectioncount(ini); |
|
115 result->settingCount = 0; |
|
116 result->modCount = 0; |
|
117 result->settings = flib_calloc(sectionCount, sizeof(flib_cfg_setting_meta)); |
|
118 result->mods = flib_calloc(sectionCount, sizeof(flib_cfg_mod_meta)); |
|
119 |
|
120 if(!result->settings || !result->mods) { |
|
121 return flib_cfg_meta_from_ini_handleError(result, ini); |
|
122 } |
|
123 |
|
124 if(readMetaSettingSections(ini, result, sectionCount) || readMetaModSections(ini, result, sectionCount)) { |
|
125 return flib_cfg_meta_from_ini_handleError(result, ini); |
|
126 } |
|
127 |
|
128 if(result->settingCount+result->modCount != sectionCount) { |
|
129 flib_log_e("Unknown or non-contiguous sections headers in metaconfig."); |
|
130 return flib_cfg_meta_from_ini_handleError(result, ini); |
|
131 } |
|
132 |
|
133 flib_ini_destroy(ini); |
|
134 return result; |
|
135 } |
|
136 |
|
137 flib_cfg_meta *flib_cfg_meta_retain(flib_cfg_meta *metainfo) { |
|
138 if(metainfo) { |
|
139 flib_retain(&metainfo->_referenceCount, "flib_cfg_meta"); |
|
140 } |
|
141 return metainfo; |
|
142 } |
|
143 |
|
144 void flib_cfg_meta_release(flib_cfg_meta *cfg) { |
|
145 if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg_meta")) { |
|
146 flib_cfg_meta_destroy(cfg); |
|
147 } |
|
148 } |
|
149 |
|
150 flib_cfg *flib_cfg_create(flib_cfg_meta *meta, const char *schemeName) { |
|
151 flib_cfg *result = flib_cfg_retain(flib_calloc(1, sizeof(flib_cfg))); |
105 if(!meta || !result || !schemeName) { |
152 if(!meta || !result || !schemeName) { |
106 flib_log_e("null parameter in flib_cfg_create"); |
153 flib_log_e("null parameter in flib_cfg_create"); |
107 return NULL; |
154 return NULL; |
108 } |
155 } |
109 |
156 |
110 result->modCount = meta->modCount; |
157 result->meta = flib_cfg_meta_retain(meta); |
111 result->settingCount = meta->settingCount; |
|
112 result->schemeName = flib_strdupnull(schemeName); |
158 result->schemeName = flib_strdupnull(schemeName); |
113 result->mods = flib_calloc(meta->modCount, sizeof(*result->mods)); |
159 result->mods = flib_calloc(meta->modCount, sizeof(*result->mods)); |
114 result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings)); |
160 result->settings = flib_calloc(meta->settingCount, sizeof(*result->settings)); |
115 |
161 |
116 if(!result->mods || !result->settings || !result->schemeName) { |
162 if(!result->mods || !result->settings || !result->schemeName) { |
122 result->settings[i] = meta->settings[i].def; |
168 result->settings[i] = meta->settings[i].def; |
123 } |
169 } |
124 return result; |
170 return result; |
125 } |
171 } |
126 |
172 |
127 flib_cfg *flib_cfg_from_ini_handleError(flib_cfg *result, flib_ini *settingfile) { |
173 flib_cfg *flib_cfg_copy(flib_cfg *cfg) { |
128 flib_ini_destroy(settingfile); |
174 flib_cfg *result = NULL; |
129 flib_cfg_destroy(result); |
175 if(cfg) { |
130 return NULL; |
176 result = flib_cfg_create(cfg->meta, cfg->schemeName); |
131 } |
177 if(result) { |
132 |
178 memcpy(result->mods, cfg->mods, cfg->meta->modCount * sizeof(*cfg->mods)); |
133 flib_cfg *flib_cfg_from_ini(const flib_cfg_meta *meta, const char *filename) { |
179 memcpy(result->settings, cfg->settings, cfg->meta->settingCount * sizeof(*cfg->settings)); |
134 if(!meta || !filename) { |
|
135 flib_log_e("null parameter in flib_cfg_from_ini"); |
|
136 return NULL; |
|
137 } |
|
138 flib_ini *settingfile = flib_ini_load(filename); |
|
139 if(!settingfile) { |
|
140 return NULL; |
|
141 } |
|
142 |
|
143 char *schemename = NULL; |
|
144 if(flib_ini_enter_section(settingfile, "Scheme")) { |
|
145 flib_log_e("Missing section \"Scheme\" in config file %s.", filename); |
|
146 return flib_cfg_from_ini_handleError(NULL, settingfile); |
|
147 } |
|
148 if(flib_ini_get_str(settingfile, &schemename, "name")) { |
|
149 flib_log_e("Missing scheme name in config file %s.", filename); |
|
150 return flib_cfg_from_ini_handleError(NULL, settingfile); |
|
151 } |
|
152 |
|
153 flib_cfg *result = flib_cfg_create(meta, schemename); |
|
154 |
|
155 if(flib_ini_enter_section(settingfile, "BasicSettings")) { |
|
156 flib_log_w("Missing section \"BasicSettings\" in config file %s, using defaults.", filename); |
|
157 } else { |
|
158 for(int i=0; i<meta->settingCount; i++) { |
|
159 if(flib_ini_get_int_opt(settingfile, &result->settings[i], meta->settings[i].iniName, meta->settings[i].def)) { |
|
160 flib_log_e("Error reading BasicSetting %s in config file %s.", meta->settings[i].iniName, filename); |
|
161 return flib_cfg_from_ini_handleError(result, settingfile); |
|
162 } |
|
163 } |
180 } |
164 } |
|
165 |
|
166 if(flib_ini_enter_section(settingfile, "GameMods")) { |
|
167 flib_log_w("Missing section \"GameMods\" in config file %s, using defaults.", filename); |
|
168 } else { |
|
169 for(int i=0; i<meta->modCount; i++) { |
|
170 if(flib_ini_get_bool_opt(settingfile, &result->mods[i], meta->mods[i].iniName, false)) { |
|
171 flib_log_e("Error reading GameMod %s in config file %s.", meta->mods[i].iniName, filename); |
|
172 return flib_cfg_from_ini_handleError(result, settingfile); |
|
173 } |
|
174 } |
|
175 } |
|
176 flib_ini_destroy(settingfile); |
|
177 return result; |
|
178 } |
|
179 |
|
180 int flib_cfg_to_ini(const flib_cfg_meta *meta, const char *filename, const flib_cfg *config) { |
|
181 int result = -1; |
|
182 if(!meta || !filename || !config || config->modCount!=meta->modCount || config->settingCount!=meta->settingCount) { |
|
183 flib_log_e("Invalid parameter in flib_cfg_to_ini"); |
|
184 } else { |
|
185 flib_ini *ini = flib_ini_create(filename); |
|
186 if(ini) { |
|
187 bool error = false; |
|
188 |
|
189 // Add the values |
|
190 error |= flib_ini_create_section(ini, "Scheme"); |
|
191 if(!error) { |
|
192 error |= flib_ini_set_str(ini, "name", config->schemeName); |
|
193 } |
|
194 |
|
195 |
|
196 error |= flib_ini_create_section(ini, "BasicSettings"); |
|
197 if(!error) { |
|
198 for(int i=0; i<config->settingCount; i++) { |
|
199 error |= flib_ini_set_int(ini, meta->settings[i].iniName, config->settings[i]); |
|
200 } |
|
201 } |
|
202 |
|
203 error |= flib_ini_create_section(ini, "GameMods"); |
|
204 if(!error) { |
|
205 for(int i=0; i<config->modCount; i++) { |
|
206 error |= flib_ini_set_bool(ini, meta->mods[i].iniName, config->mods[i]); |
|
207 } |
|
208 } |
|
209 |
|
210 if(!error) { |
|
211 result = flib_ini_save(ini, filename); |
|
212 } |
|
213 } |
|
214 flib_ini_destroy(ini); |
|
215 } |
181 } |
216 return result; |
182 return result; |
217 } |
183 } |
218 |
184 |
219 void flib_cfg_destroy(flib_cfg* cfg) { |
185 flib_cfg *flib_cfg_retain(flib_cfg *cfg) { |
220 if(cfg) { |
186 if(cfg) { |
221 free(cfg->mods); |
187 flib_retain(&cfg->_referenceCount, "flib_cfg"); |
222 free(cfg->settings); |
188 } |
223 free(cfg->schemeName); |
189 return cfg; |
224 free(cfg); |
190 } |
|
191 |
|
192 void flib_cfg_release(flib_cfg *cfg) { |
|
193 if(cfg && flib_release(&cfg->_referenceCount, "flib_cfg")) { |
|
194 flib_cfg_destroy(cfg); |
225 } |
195 } |
226 } |
196 } |