1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 #ifndef WIN32	// Goober5000
11 
12 #include <string.h>
13 #include "globalincs/pstypes.h"
14 #include "osapi/osregistry.h"
15 #include "osapi/osapi.h"
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 
22 // ------------------------------------------------------------------------------------------------------------
23 // REGISTRY DEFINES/VARS
24 //
25 
26 const char *Osreg_company_name = "Volition";
27 const char *Osreg_class_name = "FreeSpace2Class";
28 
29 const char *Osreg_app_name = "FreeSpace2";
30 const char *Osreg_title = "FreeSpace 2";
31 #ifdef __APPLE__
32 	const char *Osreg_user_dir = "Library/FS2_Open";
33 #else
34 	const char *Osreg_user_dir = ".fs2_open";
35 #endif // __APPLE__
36 	#define PROFILE_NAME "fs2_open.ini"
37 
38 #define DEFAULT_SECTION "Default"
39 
40 typedef struct KeyValue
41 {
42 	char *key;
43 	char *value;
44 
45 	struct KeyValue *next;
46 } KeyValue;
47 
48 typedef struct Section
49 {
50 	char *name;
51 
52 	struct KeyValue *pairs;
53 	struct Section *next;
54 } Section;
55 
56 typedef struct Profile
57 {
58 	struct Section *sections;
59 } Profile;
60 
61 
62 // ------------------------------------------------------------------------------------------------------------
63 // REGISTRY FUNCTIONS
64 //
65 
read_line_from_file(FILE * fp)66 static char *read_line_from_file(FILE *fp)
67 {
68 	char *buf, *buf_start;
69 	int buflen, len, eol;
70 
71 	buflen = 80;
72 	buf = (char *)vm_malloc(buflen);
73 	buf_start = buf;
74 	eol = 0;
75 
76 	do {
77 		if (buf == NULL) {
78 			return NULL;
79 		}
80 
81 		if (fgets(buf_start, 80, fp) == NULL) {
82 			if (buf_start == buf) {
83 				vm_free(buf);
84 				return NULL;
85 			} else {
86 				*buf_start = 0;
87 				return buf;
88 			}
89 		}
90 
91 		len = strlen(buf_start);
92 
93 		if (buf_start[len-1] == '\n') {
94 			buf_start[len-1] = 0;
95 			eol = 1;
96 		} else {
97 			buflen += 80;
98 
99 			buf = (char *)vm_realloc(buf, buflen);
100 
101 			/* be sure to skip over the proper amount of nulls */
102 			buf_start = buf+(buflen-80)-(buflen/80)+1;
103 		}
104 	} while (!eol);
105 
106 	return buf;
107 }
108 
trim_string(char * str)109 static char *trim_string(char *str)
110 {
111 	char *ptr;
112 	int len;
113 
114 	if (str == NULL)
115 		return NULL;
116 
117 	/* kill any comment */
118 	ptr = strchr(str, ';');
119 	if (ptr)
120 		*ptr = 0;
121 	ptr = strchr(str, '#');
122 	if (ptr)
123 		*ptr = 0;
124 
125 	ptr = str;
126 	len = strlen(str);
127 	if (len > 0) {
128 		ptr += len-1;
129 	}
130 
131 	while ((ptr > str) && isspace(*ptr)) {
132 		ptr--;
133 	}
134 
135 	if (*ptr) {
136 		ptr++;
137 		*ptr = 0;
138 	}
139 
140 	ptr = str;
141 	while (*ptr && isspace(*ptr)) {
142 		ptr++;
143 	}
144 
145 	return ptr;
146 }
147 
profile_read(char * file)148 static Profile *profile_read(char *file)
149 {
150 	char fullname[MAX_PATH_LEN];
151 	FILE *fp = NULL;
152 	char *str;
153 
154 	snprintf(fullname, MAX_PATH_LEN, "%s%s%s%s%s", detect_home(), DIR_SEPARATOR_STR, Osreg_user_dir, DIR_SEPARATOR_STR, file);
155 
156 	fp = fopen(fullname, "rt");
157 
158 	if (fp == NULL)
159 		return NULL;
160 
161 	Profile *profile = (Profile *)vm_malloc(sizeof(Profile));
162 	profile->sections = NULL;
163 
164 	Section **sp_ptr = &(profile->sections);
165 	Section *sp = NULL;
166 
167 	KeyValue **kvp_ptr = NULL;
168 
169 	while ((str = read_line_from_file(fp)) != NULL) {
170 		char *ptr = trim_string(str);
171 
172 		if (*ptr == '[') {
173 			ptr++;
174 
175 			char *pend = strchr(ptr, ']');
176 			if (pend != NULL) {
177 				// if (pend[1]) { /* trailing garbage! */ }
178 
179 				*pend = 0;
180 
181 				if (*ptr) {
182 					sp = (Section *)vm_malloc(sizeof(Section));
183 					sp->next = NULL;
184 
185 					sp->name = vm_strdup(ptr);
186 					sp->pairs = NULL;
187 
188 					*sp_ptr = sp;
189 					sp_ptr = &(sp->next);
190 
191 					kvp_ptr = &(sp->pairs);
192 				} // else { /* null name! */ }
193 			} // else { /* incomplete section name! */ }
194 		} else {
195 			if (*ptr) {
196 				char *key = ptr;
197 				char *value = NULL;
198 
199 				ptr = strchr(ptr, '=');
200 				if (ptr != NULL) {
201 					*ptr = 0;
202 					ptr++;
203 
204 					value = ptr;
205 				} // else { /* random garbage! */ }
206 
207 				if (key && *key && value /* && *value */) {
208 					if (sp != NULL) {
209 						KeyValue *kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
210 
211 						kvp->key = vm_strdup(key);
212 						kvp->value = vm_strdup(value);
213 
214 						kvp->next = NULL;
215 
216 						*kvp_ptr = kvp;
217 						kvp_ptr = &(kvp->next);
218 					} // else { /* key/value with no section! */
219 				} // else { /* malformed key/value entry! */ }
220 			} // else it's just a comment or empty string
221 		}
222 
223 		vm_free(str);
224 	}
225 
226 	fclose(fp);
227 
228 	return profile;
229 }
230 
profile_free(Profile * profile)231 static void profile_free(Profile *profile)
232 {
233 	if (profile == NULL)
234 		return;
235 
236 	Section *sp = profile->sections;
237 	while (sp != NULL) {
238 		Section *st = sp;
239 		KeyValue *kvp = sp->pairs;
240 
241 		while (kvp != NULL) {
242 			KeyValue *kvt = kvp;
243 
244 			vm_free(kvp->key);
245 			vm_free(kvp->value);
246 
247 			kvp = kvp->next;
248 			vm_free(kvt);
249 		}
250 
251 		vm_free(sp->name);
252 
253 		sp = sp->next;
254 		vm_free(st);
255 	}
256 
257 	vm_free(profile);
258 }
259 
profile_update(Profile * profile,const char * section,const char * key,const char * value)260 static Profile *profile_update(Profile *profile, const char *section, const char *key, const char *value)
261 {
262 	if (profile == NULL) {
263 		profile = (Profile *)vm_malloc(sizeof(Profile));
264 
265 		profile->sections = NULL;
266 	}
267 
268 	KeyValue *kvp;
269 
270 	Section **sp_ptr = &(profile->sections);
271 	Section *sp = profile->sections;
272 
273 	while (sp != NULL) {
274 		if (strcmp(section, sp->name) == 0) {
275 			KeyValue **kvp_ptr = &(sp->pairs);
276 			kvp = sp->pairs;
277 
278 			while (kvp != NULL) {
279 				if (strcmp(key, kvp->key) == 0) {
280 					vm_free(kvp->value);
281 
282 					if (value == NULL) {
283 						*kvp_ptr = kvp->next;
284 
285 						vm_free(kvp->key);
286 						vm_free(kvp);
287 					} else {
288 						kvp->value = vm_strdup(value);
289 					}
290 
291 					/* all done */
292 					return profile;
293 				}
294 
295 				kvp_ptr = &(kvp->next);
296 				kvp = kvp->next;
297 			}
298 
299 			if (value != NULL) {
300 				/* key not found */
301 				kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
302 				kvp->next = NULL;
303 				kvp->key = vm_strdup(key);
304 				kvp->value = vm_strdup(value);
305 			}
306 
307 			*kvp_ptr = kvp;
308 
309 			/* all done */
310 			return profile;
311 		}
312 
313 		sp_ptr = &(sp->next);
314 		sp = sp->next;
315 	}
316 
317 	/* section not found */
318 	sp = (Section *)vm_malloc(sizeof(Section));
319 	sp->next = NULL;
320 	sp->name = vm_strdup(section);
321 
322 	kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
323 	kvp->next = NULL;
324 	kvp->key = vm_strdup(key);
325 	kvp->value = vm_strdup(value);
326 
327 	sp->pairs = kvp;
328 
329 	*sp_ptr = sp;
330 
331 	return profile;
332 }
333 
profile_get_value(Profile * profile,const char * section,const char * key)334 static char *profile_get_value(Profile *profile, const char *section, const char *key)
335 {
336 	if (profile == NULL)
337 		return NULL;
338 
339 	Section *sp = profile->sections;
340 
341 	while (sp != NULL) {
342 		if (strcmp(section, sp->name) == 0) {
343 			KeyValue *kvp = sp->pairs;
344 
345 			while (kvp != NULL) {
346 				if (strcmp(key, kvp->key) == 0) {
347 					return kvp->value;
348 				}
349 				kvp = kvp->next;
350 			}
351 		}
352 
353 		sp = sp->next;
354 	}
355 
356 	/* not found */
357 	return NULL;
358 }
359 
profile_save(Profile * profile,char * file)360 static void profile_save(Profile *profile, char *file)
361 {
362 	FILE *fp = NULL;
363 	char tmp[MAX_PATH] = "";
364 	char tmp2[MAX_PATH] = "";
365 	char fullname[MAX_PATH_LEN];
366 
367 	if (profile == NULL)
368 		return;
369 
370 	snprintf(fullname, MAX_PATH_LEN, "%s%s%s%s%s", detect_home(), DIR_SEPARATOR_STR, Osreg_user_dir, DIR_SEPARATOR_STR, file);
371 
372 	fp = fopen(fullname, "wt");
373 
374 	if (fp == NULL)
375 		return;
376 
377 	Section *sp = profile->sections;
378 
379 	while (sp != NULL) {
380 		sprintf(tmp, NOX("[%s]\n"), sp->name);
381 		fputs(tmp, fp);
382 
383 		KeyValue *kvp = sp->pairs;
384 		while (kvp != NULL) {
385 			sprintf(tmp2, NOX("%s=%s\n"), kvp->key, kvp->value);
386 			fputs(tmp2, fp);
387 			kvp = kvp->next;
388 		}
389 
390 		fprintf(fp, "\n");
391 
392 		sp = sp->next;
393 	}
394 
395 	fclose(fp);
396 }
397 
398 // os registry functions -------------------------------------------------------------
399 
400 static char			szCompanyName[128];
401 static char			szAppName[128];
402 static char			szAppVersion[128];
403 
404 int Os_reg_inited = 0;
405 
406 // initialize the registry. setup default keys to use
os_init_registry_stuff(const char * company,const char * app,const char * version)407 void os_init_registry_stuff(const char *company, const char *app, const char *version)
408 {
409 	if(company){
410 		strcpy_s( szCompanyName, company );
411 	} else {
412 		strcpy_s( szCompanyName, Osreg_company_name);
413 	}
414 
415 	if(app){
416 		strcpy_s( szAppName, app );
417 	} else {
418 		strcpy_s( szAppName, Osreg_app_name);
419 	}
420 
421 	if(version){
422 		strcpy_s( szAppVersion, version);
423 	} else {
424 		strcpy_s( szAppVersion, "1.0");
425 	}
426 
427 	Os_reg_inited = 1;
428 }
429 
430 static char tmp_string_data[1024];
431 
os_config_read_string(const char * section,const char * name,const char * default_value)432 const char *os_config_read_string(const char *section, const char *name, const char *default_value)
433 {
434 	nprintf(( "Registry", "os_config_read_string(): section = \"%s\", name = \"%s\", default value: \"%s\"\n",
435 			  (section) ? section : DEFAULT_SECTION, name, (default_value) ? default_value : NOX("NULL") ));
436 
437 	Profile *p = profile_read(PROFILE_NAME);
438 
439 	if (section == NULL)
440 		section = DEFAULT_SECTION;
441 
442 	char *ptr = profile_get_value(p, section, name);
443 
444 	if (ptr != NULL) {
445 		strncpy(tmp_string_data, ptr, 1023);
446 		default_value = tmp_string_data;
447 	}
448 
449 	profile_free(p);
450 
451 	return default_value;
452 }
453 
os_config_read_uint(const char * section,const char * name,unsigned int default_value)454 unsigned int os_config_read_uint(const char *section, const char *name, unsigned int default_value)
455 {
456 	Profile *p = profile_read(PROFILE_NAME);
457 
458 	if (section == NULL)
459 		section = DEFAULT_SECTION;
460 
461 	char *ptr = profile_get_value(p, section, name);
462 
463 	if (ptr != NULL) {
464 		default_value = atoi(ptr);
465 	}
466 
467 	profile_free(p);
468 
469 	return default_value;
470 }
471 
os_config_write_string(const char * section,const char * name,const char * value)472 void os_config_write_string(const char *section, const char *name, const char *value)
473 {
474 	Profile *p = profile_read(PROFILE_NAME);
475 
476 	if (section == NULL)
477 		section = DEFAULT_SECTION;
478 
479 	p = profile_update(p, section, name, value);
480 	profile_save(p, PROFILE_NAME);
481 	profile_free(p);
482 }
483 
os_config_write_uint(const char * section,const char * name,unsigned int value)484 void os_config_write_uint(const char *section, const char *name, unsigned int value)
485 {
486 	static char buf[21];
487 
488 	snprintf(buf, 20, "%u", value);
489 
490 	Profile *p = profile_read(PROFILE_NAME);
491 
492 	if (section == NULL)
493 		section = DEFAULT_SECTION;
494 
495 	p = profile_update(p, section, name, buf);
496 	profile_save(p, PROFILE_NAME);
497 	profile_free(p);
498 }
499 
500 #endif		// Goober5000 - #ifndef WIN32
501