]> icculus.org git repositories - taylor/freespace2.git/blob - src/osapi/osregistry.cpp
make sure unset cfg options don't return a value
[taylor/freespace2.git] / src / osapi / osregistry.cpp
1 #include "pstypes.h"
2 #include "osregistry.h"
3 #include "cfile.h"
4 #undef malloc
5 #undef free
6 #undef strdup
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12
13 const char *Osreg_company_name = "Volition";
14 #if defined(MAKE_FS1)
15 const char *Osreg_class_name = "FreeSpaceClass";
16 #else
17 const char *Osreg_class_name = "Freespace2Class";
18 #endif
19 #if defined(FS1_DEMO)
20 const char *Osreg_app_name = "FreeSpaceDemo";
21 const char *Osreg_title = "FreeSpace Demo";
22 #define PROFILE_NAME "FreeSpaceDemo.ini"
23 #elif defined(FS2_DEMO)
24 const char *Osreg_app_name = "FreeSpace2Demo";
25 const char *Osreg_title = "Freespace 2 Demo";
26 #define PROFILE_NAME "Freespace2Demo.ini"
27 #elif defined(OEM_BUILD)
28 const char *Osreg_app_name = "FreeSpace2OEM";
29 const char *Osreg_title = "Freespace 2 OEM";
30 #define PROFILE_NAME "Freespace2OEM.ini"
31 #elif defined(MAKE_FS1)
32 const char *Osreg_app_name = "FreeSpace";
33 const char *Osreg_title = "FreeSpace";
34 #define PROFILE_NAME "FreeSpace.ini"
35 #else
36 const char *Osreg_app_name = "FreeSpace2";
37 const char *Osreg_title = "Freespace 2";
38 #define PROFILE_NAME "Freespace2.ini"
39 #endif
40
41 #define DEFAULT_SECTION "Default"
42
43
44 typedef struct KeyValue
45 {
46         char *key;
47         char *value;
48         
49         struct KeyValue *next;
50 } KeyValue;
51
52 typedef struct Section
53 {
54         char *name;
55         
56         struct KeyValue *pairs;
57         struct Section *next;
58 } Section;
59         
60 typedef struct Profile
61 {
62         struct Section *sections;
63 } Profile;
64
65 static char *read_line_from_file(CFILE *fp)
66 {
67         char *buf, *buf_start;
68         int buflen, len, eol;
69         
70         buflen = 80;
71         buf = (char *)malloc(buflen);
72         buf_start = buf;
73         eol = 0;
74         
75         do {
76                 if (buf == NULL) {
77                         return NULL;
78                 }
79                 
80                 if (cfgets(buf_start, 80, fp) == NULL) {
81                         if (buf_start == buf) {
82                                 free(buf);
83                                 return NULL;
84                         } else {
85                                 *buf_start = 0;
86                                 return buf;
87                         }
88                 }
89                 
90                 len = strlen(buf_start);
91                 
92                 if (buf_start[len-1] == '\n') {
93                         buf_start[len-1] = 0;
94                         eol = 1;
95                 } else {
96                         buflen += 80;
97                         
98                         buf = (char *)realloc(buf, buflen);
99                         
100                         /* be sure to skip over the proper amount of nulls */
101                         buf_start = buf+(buflen-80)-(buflen/80)+1;
102                 }
103         } while (!eol);
104         
105         return buf;
106 }
107
108 static char *trim_string(char *str)
109 {
110         char *ptr;
111         int len;
112         
113         if (str == NULL)
114                 return NULL;
115         
116         /* kill any comment */
117         ptr = SDL_strchr(str, ';');
118         if (ptr)
119                 *ptr = 0;
120         ptr = SDL_strchr(str, '#');
121         if (ptr)
122                 *ptr = 0;
123         
124         ptr = str;
125         len = strlen(str);
126         if (len > 0) {
127                 ptr += len-1;
128         }
129         
130         while ((ptr > str) && isspace(*ptr)) {
131                 ptr--;
132         }
133         
134         if (*ptr) {
135                 ptr++;
136                 *ptr = 0;
137         }
138         
139         ptr = str;
140         while (*ptr && isspace(*ptr)) {
141                 ptr++;
142         }
143         
144         return ptr;
145 }
146
147 static Profile *profile_read(const char *file)
148 {
149         CFILE *fp = cfopen(file, "rt", CFILE_NORMAL, CF_TYPE_ROOT);
150         if (fp == NULL)
151                 return NULL;
152         
153         Profile *profile = (Profile *)malloc(sizeof(Profile));
154         profile->sections = NULL;
155         
156         Section **sp_ptr = &(profile->sections);
157         Section *sp = NULL;
158
159         KeyValue **kvp_ptr = NULL;
160                 
161         char *str;
162         while ((str = read_line_from_file(fp)) != NULL) {
163                 char *ptr = trim_string(str);
164                 
165                 if (*ptr == '[') {
166                         ptr++;
167                         
168                         char *pend = SDL_strchr(ptr, ']');
169                         if (pend != NULL) {
170                                 // if (pend[1]) { /* trailing garbage! */ }
171                                 
172                                 *pend = 0;                              
173                                 
174                                 if (*ptr) {
175                                         sp = (Section *)malloc(sizeof(Section));
176                                         sp->next = NULL;
177                                 
178                                         sp->name = strdup(ptr);
179                                         sp->pairs = NULL;
180                                         
181                                         *sp_ptr = sp;
182                                         sp_ptr = &(sp->next);
183                                         
184                                         kvp_ptr = &(sp->pairs);
185                                 } // else { /* null name! */ }
186                         } // else { /* incomplete section name! */ }
187                 } else {
188                         if (*ptr) {
189                                 char *key = ptr;
190                                 char *value = NULL;
191                                 
192                                 ptr = SDL_strchr(ptr, '=');
193                                 if (ptr != NULL) {
194                                         *ptr = 0;
195                                         ptr++;
196                                         
197                                         value = ptr;
198                                 } // else { /* random garbage! */ }
199                                 
200                                 if (key && *key && value /* && *value */) {
201                                         if (sp != NULL) {
202                                                 KeyValue *kvp = (KeyValue *)malloc(sizeof(KeyValue));
203                                                 
204                                                 kvp->key = strdup(key);
205                                                 kvp->value = strdup(value);
206                                                 
207                                                 kvp->next = NULL;
208                                                 
209                                                 *kvp_ptr = kvp;
210                                                 kvp_ptr = &(kvp->next);
211                                         } // else { /* key/value with no section! */
212                                 } // else { /* malformed key/value entry! */ }
213                         } // else it's just a comment or empty string
214                 }
215                                 
216                 free(str);
217         }
218         
219         cfclose(fp);
220
221         return profile;
222 }
223
224 static void profile_free(Profile *profile)
225 {
226         if (profile == NULL)
227                 return;
228                 
229         Section *sp = profile->sections;
230         while (sp != NULL) {
231                 Section *st = sp;
232                 KeyValue *kvp = sp->pairs;
233                 
234                 while (kvp != NULL) {
235                         KeyValue *kvt = kvp;
236                         
237                         free(kvp->key);
238                         free(kvp->value);
239                         
240                         kvp = kvp->next;
241                         free(kvt);
242                 }
243                 
244                 free(sp->name);
245                 
246                 sp = sp->next;
247                 free(st);
248         }
249         
250         free(profile);
251 }
252
253 static Profile *profile_update(Profile *profile, const char *section, const char *key, const char *value)
254 {
255         if (profile == NULL) {
256                 profile = (Profile *)malloc(sizeof(Profile));
257                 
258                 profile->sections = NULL;
259         }
260         
261         KeyValue *kvp;
262         
263         Section **sp_ptr = &(profile->sections);
264         Section *sp = profile->sections;
265         while (sp != NULL) {
266                 if (strcmp(section, sp->name) == 0) {
267                         KeyValue **kvp_ptr = &(sp->pairs);
268                         kvp = sp->pairs;
269                         
270                         while (kvp != NULL) {
271                                 if (strcmp(key, kvp->key) == 0) {
272                                         free(kvp->value);
273                                         
274                                         if (value == NULL) {
275                                                 *kvp_ptr = kvp->next;
276                                                 
277                                                 free(kvp->key);
278                                                 free(kvp);
279                                         } else {
280                                                 kvp->value = strdup(value);
281                                         }
282                                         
283                                         /* all done */
284                                         return profile;
285                                 }
286                                 
287                                 kvp_ptr = &(kvp->next);
288                                 kvp = kvp->next;
289                         }
290                         
291                         if (value != NULL) {
292                                 /* key not found */
293                                 kvp = (KeyValue *)malloc(sizeof(KeyValue));
294                                 kvp->next = NULL;
295                                 kvp->key = strdup(key);
296                                 kvp->value = strdup(value);
297                         }
298                                         
299                         *kvp_ptr = kvp;
300                         
301                         /* all done */
302                         return profile;
303                 }
304                 
305                 sp_ptr = &(sp->next);
306                 sp = sp->next;
307         }
308         
309         /* section not found */
310         sp = (Section *)malloc(sizeof(Section));
311         sp->next = NULL;
312         sp->name = strdup(section);
313         
314         kvp = (KeyValue *)malloc(sizeof(KeyValue));
315         kvp->next = NULL;
316         kvp->key = strdup(key);
317         kvp->value = strdup(value);
318         
319         sp->pairs = kvp;
320         
321         *sp_ptr = sp;
322         
323         return profile;
324 }
325
326 static const char *profile_get_value(Profile *profile, const char *section, const char *key)
327 {
328         if (profile == NULL)
329                 return NULL;
330         
331         Section *sp = profile->sections;
332         while (sp != NULL) {
333                 if (strcmp(section, sp->name) == 0) {
334                         KeyValue *kvp = sp->pairs;
335                 
336                         while (kvp != NULL) {
337                                 if (strcmp(key, kvp->key) == 0) {
338                                         return kvp->value;
339                                 }
340                                 kvp = kvp->next;
341                         }
342                 }
343                 
344                 sp = sp->next;
345         }
346         
347         /* not found */
348         return NULL;
349 }
350
351 static char tmp_string_data[1024];
352
353 static void profile_save(Profile *profile, const char *file)
354 {
355         CFILE *fp;
356
357         if (profile == NULL)
358                 return;
359                 
360         fp = cfopen(file, "wt", CFILE_NORMAL, CF_TYPE_ROOT);
361         if (fp == NULL)
362                 return;
363         
364         Section *sp = profile->sections;
365         while (sp != NULL) {
366                 SDL_snprintf(tmp_string_data, sizeof(tmp_string_data), NOX("[%s]\n"), sp->name);
367                 cfputs(tmp_string_data, fp);
368                 
369                 KeyValue *kvp = sp->pairs;
370                 while (kvp != NULL) {
371                         SDL_snprintf(tmp_string_data, sizeof(tmp_string_data), NOX("%s=%s\n"), kvp->key, kvp->value);
372                         cfputs(tmp_string_data, fp);
373                         kvp = kvp->next;
374                 }
375                 
376                 cfwrite_char('\n', fp);
377                 
378                 sp = sp->next;
379         }
380         
381         cfclose(fp);
382 }
383
384 const char *os_config_read_string(const char *section, const char *name, const char *default_value)
385 {
386         Profile *p = profile_read(PROFILE_NAME);
387
388         if (section == NULL)
389                 section = DEFAULT_SECTION;
390                 
391         const char *ptr = profile_get_value(p, section, name);
392         if ( (ptr != NULL) && SDL_strlen(ptr) ) {
393                 SDL_strlcpy(tmp_string_data, ptr, sizeof(tmp_string_data));
394                 default_value = tmp_string_data;
395         }
396         
397         profile_free(p);
398         
399         return default_value;
400 }
401
402 unsigned int os_config_read_uint(const char *section, const char *name, unsigned int default_value)
403 {
404         Profile *p = profile_read(PROFILE_NAME);
405         
406         if (section == NULL)
407                 section = DEFAULT_SECTION;
408                 
409         const char *ptr = profile_get_value(p, section, name);
410         if ( (ptr != NULL) && SDL_strlen(ptr) ) {
411                 default_value = atoi(ptr);
412         }
413         
414         profile_free(p);
415         
416         return default_value;
417 }
418
419 void os_config_write_string(const char *section, const char *name, const char *value)
420 {
421         Profile *p = profile_read(PROFILE_NAME);
422         
423         if (section == NULL)
424                 section = DEFAULT_SECTION;
425                 
426         p = profile_update(p, section, name, value);
427         profile_save(p, PROFILE_NAME);
428         profile_free(p);        
429 }
430
431 void os_config_write_uint(const char *section, const char *name, unsigned int value)
432 {
433         static char buf[21];
434         
435         SDL_snprintf(buf, 20, "%u", value);
436         
437         Profile *p = profile_read(PROFILE_NAME);
438
439         if (section == NULL)
440                 section = DEFAULT_SECTION;
441         
442         p = profile_update(p, section, name, buf);
443         profile_save(p, PROFILE_NAME);
444         profile_free(p);
445 }
446
447 // set default config options
448 // NOTE: this will * RESET CURRENT OPTIONS TO THEIR DEFAULTS *
449 void os_init_registry_stuff()
450 {
451         // 'Default' section
452         os_config_write_string(NULL, "Language", "English" /* DEFAULT_LANGUAGE */);
453         os_config_write_string(NULL, "LastPlayer", "");
454         os_config_write_uint(NULL, "ComputerSpeed", 2);
455         os_config_write_string(NULL, "ExtrasPath", "");
456         os_config_write_uint(NULL, "LowMem", 0);
457
458         // 'Video' section
459         os_config_write_string("Video", "Renderer", "OpenGL");
460         os_config_write_uint("Video", "AntiAlias", 0);
461         os_config_write_uint("Video", "Fullscreen", 1);
462         os_config_write_string("Video", "Gamma", "1.8");
463         os_config_write_uint("Video", "ShowFPS", 0);
464         os_config_write_uint("Video", "LowRes", 0);
465         os_config_write_uint("Video", "PreloadTextures", 1);
466         os_config_write_uint("Video", "ScaleMovies", 1);
467
468         // 'Audio' section
469         os_config_write_string("Audio", "CaptureDevice", "");
470         os_config_write_string("Audio", "PlaybackDevice", "");
471         os_config_write_uint("Audio", "EFX", 0);
472
473         // 'Controls' section
474         os_config_write_string("Controls", "CurrentJoystick", "");
475         os_config_write_uint("Controls", "EnableJoystickFF", 1);
476         os_config_write_uint("Controls", "EnableHitEffect", 1);
477
478         // 'Network' section
479         os_config_write_string("Network", "NetworkConnection", "LAN");
480         os_config_write_string("Network", "ConnectionSpeed", "Fast");
481         os_config_write_uint("Network", "ForcePort", 0);
482         os_config_write_uint("Network", "SkipVerify", 0);
483
484         // 'PXO' section
485         os_config_write_string("PXO", "Login", "");
486         os_config_write_string("PXO", "Password", "");
487         os_config_write_string("PXO", "SquadName", "");
488 }