DEADSOFTWARE

portability: avoid errors on some compilers
[flatwaifu.git] / src / config.c
1 /* Copyright (C) 2020 SovietPony
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 */
16 #include "glob.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <assert.h>
21 #include <ctype.h>
22 #include "system.h"
23 #include "files.h"
24 #include "input.h"
26 #include "common/cp866.h"
28 static FILE *f;
29 static int ch;
31 const cfg_t *CFG_find_entry (const char *key, const cfg_t *cfg) {
32 assert(key != NULL);
33 if (cfg != NULL) {
34 int i = 0;
35 while (cfg[i].cfg && cp866_strcasecmp(cfg[i].cfg, key) != 0) {
36 i++;
37 }
38 return cfg[i].cfg ? &cfg[i] : NULL;
39 } else {
40 return NULL;
41 }
42 }
44 int CFG_update_key (const char *key, const char *value, const cfg_t *cfg) {
45 const cfg_t *entry;
46 assert(key != NULL);
47 assert(value != NULL);
48 entry = CFG_find_entry(key, cfg);
49 if (entry != NULL) {
50 void *p = entry->p;
51 switch (entry->t) {
52 case Y_BYTE: *(byte*)p = atoi(value); break;
53 case Y_WORD: *(word*)p = atoi(value); break;
54 case Y_DWORD: *(dword*)p = atoi(value); break;
55 case Y_STRING: strcpy(p, value); break; // TODO fix this security problem
56 case Y_SW_ON: *(byte*)p = cp866_strcasecmp(value, "on") == 0 ? 1 : 0; break;
57 case Y_SW_OFF: *(byte*)p = cp866_strcasecmp(value, "off") == 0 ? 1 : 0; break;
58 case Y_FILES: F_addwad(value); break;
59 case Y_KEY: *(int*)p = I_string_to_key(value); break;
60 default: assert(0); // unknown type -> something broken
61 }
62 //logo("CFG_update_key: [%s] = [%s]\n", key, value);
63 return 1;
64 } else {
65 return 0;
66 }
67 }
69 /* --- parser --- */
71 int CFG_open_iterator (const char *name) {
72 assert(f == NULL);
73 f = fopen(name, "rb");
74 if (f != NULL) {
75 ch = fgetc(f);
76 }
77 return f != NULL;
78 }
80 static void CFG_skip_space (void) {
81 while (feof(f) == 0 && isspace(ch)) {
82 ch = fgetc(f);
83 }
84 }
86 static void CFG_skip_line (void) {
87 while (feof(f) == 0 && ch != '\n' && ch != '\r') {
88 ch = fgetc(f);
89 }
90 while (feof(f) == 0 && ch == '\n' && ch == '\r') {
91 ch = fgetc(f);
92 }
93 }
95 int CFG_scan_iterator (char *key, int keylen, char *value, int valuelen) {
96 int i;
97 int found = 0;
98 assert(key != NULL);
99 assert(keylen > 0);
100 assert(value != NULL);
101 assert(valuelen > 0);
102 while (feof(f) == 0 && found == 0) {
103 CFG_skip_space();
104 if (ch == ';') {
105 CFG_skip_line();
106 } else if (feof(f) == 0) {
107 found = 1;
108 i = 0;
109 while (feof(f) == 0 && isspace(ch) == 0 && ch != '=') {
110 if (i < keylen - 1) {
111 key[i] = ch;
112 i += 1;
114 ch = fgetc(f);
116 key[i] = 0;
117 CFG_skip_space();
118 if (feof(f) == 0 && ch == '=') {
119 ch = fgetc(f);
120 CFG_skip_space();
122 i = 0;
123 while (feof(f) == 0 && ch != '\n' && ch != '\r') {
124 if (i < valuelen - 1) {
125 value[i] = ch;
126 i += 1;
128 ch = fgetc(f);
130 value[i] = 0;
131 CFG_skip_line();
134 return found;
137 void CFG_close_iterator (void) {
138 assert(f != NULL);
139 fclose(f);
140 f = NULL;
143 /* --- reader --- */
145 int CFG_read_config (const char *name, int n, const cfg_t **cfg) {
146 int i;
147 char key[64];
148 char value[64];
149 assert(name != NULL);
150 assert(n >= 0);
151 assert(cfg != NULL);
152 assert(name != NULL);
153 if (CFG_open_iterator(name)) {
154 while (CFG_scan_iterator(key, 64, value, 64)) {
155 i = 0;
156 while (i < n && CFG_update_key(key, value, cfg[i]) == 0) {
157 i++;
160 CFG_close_iterator();
161 return 1;
162 } else {
163 return 0;
169 /* --- writer --- */
171 static void CFG_write_key_value (FILE *f, const char *key, const char *value) {
172 assert(f != NULL);
173 assert(key != NULL);
174 assert(value != NULL);
175 fwrite(key, strlen(key), 1, f);
176 fwrite("=", 1, 1, f);
177 fwrite(value, strlen(value), 1, f);
178 fwrite("\n", 1, 1, f);
181 static int CFG_write_entry (FILE *f, const cfg_t *entry) {
182 char buf[16];
183 const char *str;
184 const char *key;
185 assert(f != NULL);
186 assert(entry != NULL);
187 key = entry->cfg;
188 if (key != NULL) {
189 switch (entry->t) {
190 case Y_BYTE:
191 snprintf(buf, 16, "%i", *(byte*)entry->p);
192 CFG_write_key_value(f, key, buf);
193 break;
194 case Y_WORD:
195 snprintf(buf, 16, "%i", *(word*)entry->p);
196 CFG_write_key_value(f, key, buf);
197 break;
198 case Y_DWORD:
199 snprintf(buf, 16, "%i", *(dword*)entry->p);
200 CFG_write_key_value(f, key, buf);
201 break;
202 case Y_STRING:
203 CFG_write_key_value(f, key, entry->p);
204 break;
205 case Y_SW_ON:
206 case Y_SW_OFF:
207 str = *(byte*)entry->p ? "on" : "off";
208 CFG_write_key_value(f, key, str);
209 break;
210 case Y_KEY:
211 str = I_key_to_string(*(int*)entry->p);
212 CFG_write_key_value(f, key, str);
213 break;
214 case Y_FILES: return 1; // ignore
215 case 0: return 0; // end
216 default: assert(0); // unknown type -> something broken
219 return entry->t == 0 ? 0 : 1;
222 int CFG_update_config (const char *old, const char *new, int n, const cfg_t **cfg, const char *msg) {
223 int i, j;
224 char key[64];
225 char value[64];
226 FILE *nf;
227 assert(old != NULL);
228 assert(new != NULL);
229 assert(n >= 0);
230 assert(cfg != NULL);
231 nf = fopen(new, "wb");
232 if (nf != NULL) {
233 if (msg != NULL) {
234 fwrite("; ", 2, 1, nf);
235 fwrite(msg, strlen(msg), 1, nf);
236 fwrite("\n", 1, 1, nf);
238 if (CFG_open_iterator(old)) {
239 while (CFG_scan_iterator(key, 64, value, 64)) {
240 i = 0;
241 while (i < n && CFG_find_entry(key, cfg[i]) == NULL) {
242 i++;
244 if (i >= n) {
245 CFG_write_key_value(nf, key, value);
248 CFG_close_iterator();
250 for (j = 0; j < n; j++) {
251 if (cfg[j] != NULL) {
252 i = 0;
253 while (CFG_write_entry(nf, &cfg[j][i])) {
254 i++;
258 fclose(nf);
260 return nf != NULL;