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 #include "globalincs/pstypes.h"
11 #include "osapi/osregistry.h"
12 #include "osapi/osapi.h"
13 #include "cmdline/cmdline.h"
14 #include "osregistry.h"
15
16
17 #ifdef WIN32
18 #include <windows.h>
19 // Stupid Microsoft is not able to fix a simple compile warning: https://connect.microsoft.com/VisualStudio/feedback/details/1342304/level-1-compiler-warnings-in-windows-sdk-shipped-with-visual-studio
20 #pragma warning(push)
21 #pragma warning(disable: 4091) // ignored on left of '' when no variable is declared
22 #pragma warning(pop)
23 #include <sddl.h>
24 #endif
25
26 namespace
27 {
28 // ------------------------------------------------------------------------------------------------------------
29 // REGISTRY FUNCTIONS
30 //
31
32 char szCompanyName[128] = "Volition";
33 char szAppName[128] = "FreeSpace2";
34
35 int Os_reg_inited = 0;
36
37 #ifdef WIN32
38 // os registry functions -------------------------------------------------------------
39
40 // This code is needed for compatibility with the old windows registry
41 bool userSIDInitialized = false;
42 bool userSIDValid = false;
43 SCP_string userSID;
44
get_user_sid(SCP_string & outStr)45 bool get_user_sid(SCP_string& outStr)
46 {
47 HANDLE hToken = NULL;
48 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) == FALSE)
49 {
50 mprintf(("Failed to get process token! Error Code: %d\n", (int)GetLastError()));
51
52 return false;
53 }
54
55 DWORD dwBufferSize;
56 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize);
57
58 PTOKEN_USER ptkUser = (PTOKEN_USER) new byte[dwBufferSize];
59
60 if (GetTokenInformation(hToken, TokenUser, ptkUser, dwBufferSize, &dwBufferSize))
61 {
62 CloseHandle(hToken);
63 }
64
65 if (IsValidSid(ptkUser->User.Sid) == FALSE)
66 {
67 mprintf(("Invalid SID structure detected!\n"));
68
69 delete[] ptkUser;
70 return false;
71 }
72
73 LPTSTR sidName = NULL;
74 if (ConvertSidToStringSid(ptkUser->User.Sid, &sidName) == 0)
75 {
76 mprintf(("Failed to convert SID structure to string! Error Code: %d\n", (int)GetLastError()));
77
78 delete[] ptkUser;
79 return false;
80 }
81
82 outStr.assign(sidName);
83
84 LocalFree(sidName);
85 delete[](byte*) ptkUser;
86
87 return true;
88 }
89
needsWOW64()90 bool needsWOW64()
91 {
92 #if IS_64BIT
93 // 64-bit application always use the Wow6432Node
94 return true;
95 #else
96 BOOL bIsWow64 = FALSE;
97 if (!IsWow64Process(GetCurrentProcess(), &bIsWow64))
98 {
99 mprintf(("Failed to determine if we run under Wow64, registry configuration may fail!\n"));
100 return false;
101 }
102
103 return bIsWow64 == TRUE;
104 #endif
105 }
106
get_registry_keyname(char * out_keyname,const char * section,bool alternate_path)107 HKEY get_registry_keyname(char* out_keyname, const char* section, bool alternate_path) {
108 if (!alternate_path) {
109 // Use the original registry path, sometimes breaks for no reason which can be fixed by the code below
110 if (section) {
111 sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
112 }
113 else {
114 sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
115 }
116 return HKEY_LOCAL_MACHINE;
117 }
118
119 // Every compiler from Visual Studio 2008 onward should have support for UAC
120 if (!userSIDInitialized)
121 {
122 OSVERSIONINFO versionInfo;
123 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
124 GetVersionEx(&versionInfo);
125
126 // Windows Vista is 6.0 which is the first version requiring this
127 if (versionInfo.dwMajorVersion >= 6)
128 {
129 userSIDValid = get_user_sid(userSID);
130 }
131 userSIDInitialized = true;
132 }
133 #if !defined(_MSC_VER) || _MSC_VER >= 1400
134 if (userSIDValid)
135 {
136 if (needsWOW64())
137 {
138 if (section) {
139 sprintf(out_keyname, "%s_Classes\\VirtualStore\\MACHINE\\SOFTWARE\\WOW6432Node\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
140 }
141 else {
142 sprintf(out_keyname, "%s_Classes\\VirtualStore\\MACHINE\\SOFTWARE\\WOW6432Node\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
143 }
144 }
145 else
146 {
147 if (section) {
148 sprintf(out_keyname, "%s_Classes\\VirtualStore\\MACHINE\\SOFTWARE\\%s\\%s\\%s", userSID.c_str(), szCompanyName, szAppName, section);
149 }
150 else {
151 sprintf(out_keyname, "%s_Classes\\VirtualStore\\MACHINE\\SOFTWARE\\%s\\%s", userSID.c_str(), szCompanyName, szAppName);
152 }
153 }
154
155 return HKEY_USERS;
156 }
157 else
158 {
159 // This will probably fail
160 if (section) {
161 sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
162 }
163 else {
164 sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
165 }
166
167 return HKEY_LOCAL_MACHINE;
168 }
169 #else
170 if (section) {
171 sprintf(out_keyname, "Software\\%s\\%s\\%s", szCompanyName, szAppName, section);
172 }
173 else {
174 sprintf(out_keyname, "Software\\%s\\%s", szCompanyName, szAppName);
175 }
176
177 return HKEY_LOCAL_MACHINE;
178 #endif
179 }
180
registry_write_string(const char * section,const char * name,const char * value)181 void registry_write_string(const char *section, const char *name, const char *value)
182 {
183 HKEY hKey = NULL;
184 DWORD dwDisposition;
185 char keyname[1024];
186 LONG lResult;
187
188 if (!Os_reg_inited) {
189 return;
190 }
191
192 HKEY useHKey = get_registry_keyname(keyname, section, Cmdline_alternate_registry_path);
193
194 lResult = RegCreateKeyEx(useHKey, // Where to add it
195 keyname, // name of key
196 0, // DWORD reserved
197 NULL, // Object class
198 REG_OPTION_NON_VOLATILE, // Save to disk
199 KEY_ALL_ACCESS, // Allows all changes
200 NULL, // Default security attributes
201 &hKey, // Location to store key
202 &dwDisposition); // Location to store status of key
203
204 if (lResult != ERROR_SUCCESS) {
205 goto Cleanup;
206 }
207
208 if (!name) {
209 goto Cleanup;
210 }
211
212 lResult = RegSetValueEx(hKey, // Handle to key
213 name, // The values name
214 0, // DWORD reserved
215 REG_SZ, // null terminated string
216 (CONST BYTE *)value, // value to set
217 (DWORD)(strlen(value) + 1)); // How many bytes to set
218
219 if (lResult != ERROR_SUCCESS) {
220 goto Cleanup;
221 }
222
223
224 Cleanup:
225 if (hKey)
226 RegCloseKey(hKey);
227 }
228
registry_write_uint(const char * section,const char * name,uint value)229 void registry_write_uint(const char *section, const char *name, uint value)
230 {
231 HKEY hKey = NULL;
232 DWORD dwDisposition;
233 char keyname[1024];
234 LONG lResult;
235
236 if (!Os_reg_inited) {
237 return;
238 }
239
240 HKEY useHKey = get_registry_keyname(keyname, section, Cmdline_alternate_registry_path);
241
242 lResult = RegCreateKeyEx(useHKey, // Where to add it
243 keyname, // name of key
244 0, // DWORD reserved
245 NULL, // Object class
246 REG_OPTION_NON_VOLATILE, // Save to disk
247 KEY_ALL_ACCESS, // Allows all changes
248 NULL, // Default security attributes
249 &hKey, // Location to store key
250 &dwDisposition); // Location to store status of key
251
252 if (lResult != ERROR_SUCCESS) {
253 goto Cleanup;
254 }
255
256 if (!name) {
257 goto Cleanup;
258 }
259
260 lResult = RegSetValueEx(hKey, // Handle to key
261 name, // The values name
262 0, // DWORD reserved
263 REG_DWORD, // null terminated string
264 (CONST BYTE *)&value, // value to set
265 4); // How many bytes to set
266
267 if (lResult != ERROR_SUCCESS) {
268 goto Cleanup;
269 }
270
271 Cleanup:
272 if (hKey)
273 RegCloseKey(hKey);
274
275 }
276
277 // Reads a string from the INI file. If default is passed,
278 // and the string isn't found, returns ptr to default otherwise
279 // returns NULL; Copy the return value somewhere before
280 // calling os_read_string again, because it might reuse the
281 // same buffer.
282 static char registry_tmp_string_data[1024];
registry_read_string(const char * section,const char * name,const char * default_value)283 const char * registry_read_string(const char *section, const char *name, const char *default_value)
284 {
285 HKEY hKey = NULL;
286 DWORD dwType, dwLen;
287 char keyname[1024];
288 LONG lResult;
289
290 if (!Os_reg_inited) {
291 return NULL;
292 }
293
294 HKEY useHKey = get_registry_keyname(keyname, section, Cmdline_alternate_registry_path);
295
296 lResult = RegOpenKeyEx(useHKey, // Where it is
297 keyname, // name of key
298 0, // DWORD reserved
299 KEY_QUERY_VALUE, // Allows all changes
300 &hKey); // Location to store key
301
302 if (lResult != ERROR_SUCCESS) {
303 goto Cleanup;
304 }
305
306 if (!name) {
307 goto Cleanup;
308 }
309
310 dwLen = 1024;
311 lResult = RegQueryValueEx(hKey, // Handle to key
312 name, // The values name
313 NULL, // DWORD reserved
314 &dwType, // What kind it is
315 (ubyte *)®istry_tmp_string_data, // value to set
316 &dwLen); // How many bytes to set
317
318 if (lResult != ERROR_SUCCESS) {
319 goto Cleanup;
320 }
321
322 default_value = registry_tmp_string_data;
323
324 Cleanup:
325 if (hKey)
326 RegCloseKey(hKey);
327
328 return default_value;
329 }
330
331 // Reads a string from the INI file. Default_value must
332 // be passed, and if 'name' isn't found, then returns default_value
registry_read_uint(const char * section,const char * name,uint default_value)333 uint registry_read_uint(const char *section, const char *name, uint default_value)
334 {
335 HKEY hKey = NULL;
336 DWORD dwType, dwLen;
337 char keyname[1024];
338 LONG lResult;
339 uint tmp_val;
340
341 if (!Os_reg_inited) {
342 return default_value;
343 }
344
345 HKEY useHKey = get_registry_keyname(keyname, section, Cmdline_alternate_registry_path);
346
347 lResult = RegOpenKeyEx(useHKey, // Where it is
348 keyname, // name of key
349 0, // DWORD reserved
350 KEY_QUERY_VALUE, // Allows all changes
351 &hKey); // Location to store key
352
353 if (lResult != ERROR_SUCCESS) {
354 goto Cleanup;
355 }
356
357 if (!name) {
358 goto Cleanup;
359 }
360
361 dwLen = 4;
362 lResult = RegQueryValueEx(hKey, // Handle to key
363 name, // The values name
364 NULL, // DWORD reserved
365 &dwType, // What kind it is
366 (ubyte *)&tmp_val, // value to set
367 &dwLen); // How many bytes to set
368
369 if (lResult != ERROR_SUCCESS) {
370 goto Cleanup;
371 }
372
373 default_value = tmp_val;
374
375 Cleanup:
376 if (hKey)
377 RegCloseKey(hKey);
378
379 return default_value;
380 }
381 #endif
382 }
383
384 #ifdef WIN32
385
filetime_to_timet(const FILETIME & ft)386 static time_t filetime_to_timet(const FILETIME& ft)
387 {
388 ULARGE_INTEGER ull;
389 ull.LowPart = ft.dwLowDateTime;
390 ull.HighPart = ft.dwHighDateTime;
391 return ull.QuadPart / 10000000ULL - 11644473600ULL;
392 }
393
key_mod_time(bool alternate_path)394 static time_t key_mod_time(bool alternate_path) {
395 char keyname[1024];
396
397 HKEY useHKey = get_registry_keyname(keyname, nullptr, alternate_path);
398
399 HKEY hKey = nullptr;
400 auto lResult = RegOpenKeyEx(useHKey, // Where it is
401 keyname, // name of key
402 0, // DWORD reserved
403 KEY_QUERY_VALUE, // Allows all changes
404 &hKey); // Location to store key
405
406 if (lResult != ERROR_SUCCESS) {
407 ::RegCloseKey(hKey);
408 return 0;
409 }
410
411 FILETIME time;
412 lResult = RegQueryInfoKey(hKey,
413 nullptr,
414 nullptr,
415 nullptr,
416 nullptr,
417 nullptr,
418 nullptr,
419 nullptr,
420 nullptr,
421 nullptr,
422 nullptr,
423 &time);
424 ::RegCloseKey(hKey);
425
426 if (lResult != ERROR_SUCCESS) {
427 return 0;
428 }
429 return filetime_to_timet(time);
430 }
431
os_registry_get_last_modification_time()432 time_t os_registry_get_last_modification_time() {
433 auto standard_time = key_mod_time(false);
434 auto alternate_time = key_mod_time(true);
435
436 return std::max(standard_time, alternate_time);
437 }
438
439 #endif
440
441 // ------------------------------------------------------------------------------------------------------------
442 // REGISTRY DEFINES/VARS
443 //
444 #ifdef SCP_UNIX
445 // Initialize path of old pilot files
446 #ifdef __APPLE__
447 const char* Osreg_user_dir_legacy = "Library/FS2_Open";
448 #else
449 const char* Osreg_user_dir_legacy = ".fs2_open";
450 #endif // __APPLE__
451 #endif
452
453 const char *Osreg_company_name = "Volition";
454 const char *Osreg_class_name = "FreeSpace2Class";
455
456 const char *Osreg_app_name = "FreeSpace2";
457 const char *Osreg_title = "FreeSpace 2";
458
459 const char *Osreg_config_file_name = "fs2_open.ini";
460
461 #define DEFAULT_SECTION "Default"
462
463 typedef struct KeyValue
464 {
465 char *key;
466 char *value;
467
468 struct KeyValue *next;
469 } KeyValue;
470
471 typedef struct Section
472 {
473 char *name;
474
475 struct KeyValue *pairs;
476 struct Section *next;
477 } Section;
478
479 typedef struct Profile
480 {
481 struct Section *sections;
482 } Profile;
483
484 // For string config functions
485 static char tmp_string_data[1024];
486
487 // This code is needed for compatibility with the old windows registry
488
read_line_from_file(FILE * fp)489 static char *read_line_from_file(FILE *fp)
490 {
491 char *buf, *buf_start;
492 int buflen, eol;
493
494 buflen = 80;
495 buf = (char *)vm_malloc(buflen);
496 buf_start = buf;
497 eol = 0;
498
499 do {
500 if (buf == NULL) {
501 return NULL;
502 }
503
504 if (fgets(buf_start, 80, fp) == NULL) {
505 if (buf_start == buf) {
506 vm_free(buf);
507 return NULL;
508 }
509 else {
510 *buf_start = 0;
511 return buf;
512 }
513 }
514
515 auto len = strlen(buf_start);
516
517 if (buf_start[len - 1] == '\n') {
518 buf_start[len - 1] = 0;
519 eol = 1;
520 }
521 else {
522 buflen += 80;
523
524 buf = (char *)vm_realloc(buf, buflen);
525
526 /* be sure to skip over the proper amount of nulls */
527 buf_start = buf + (buflen - 80) - (buflen / 80) + 1;
528 }
529 } while (!eol);
530
531 return buf;
532 }
533
trim_string(char * str)534 static char *trim_string(char *str)
535 {
536 char *ptr;
537
538 if (str == NULL)
539 return NULL;
540
541 /* kill any comment */
542 ptr = strchr(str, ';');
543 if (ptr)
544 *ptr = 0;
545 ptr = strchr(str, '#');
546 if (ptr)
547 *ptr = 0;
548
549 ptr = str;
550 auto len = strlen(str);
551 if (len > 0) {
552 ptr += len - 1;
553 }
554
555 while ((ptr > str) && isspace(*ptr)) {
556 ptr--;
557 }
558
559 if (*ptr) {
560 ptr++;
561 *ptr = 0;
562 }
563
564 ptr = str;
565 while (*ptr && isspace(*ptr)) {
566 ptr++;
567 }
568
569 return ptr;
570 }
571
profile_read(const char * file)572 static Profile *profile_read(const char *file)
573 {
574 FILE *fp = NULL;
575 char *str;
576
577 if (os_is_legacy_mode()) {
578 #ifdef WIN32
579 return nullptr; // No config file in legacy mode
580 #else
581 // Try to use the config file at the old location
582 char legacy_path[MAX_PATH_LEN];
583 snprintf(legacy_path, MAX_PATH_LEN, "%s/%s/%s", getenv("HOME"), Osreg_user_dir_legacy, file);
584
585 fp = fopen(legacy_path, "rt");
586 #endif
587 }
588 else {
589 fp = fopen(os_get_config_path(file).c_str(), "rt");
590 }
591
592 if (fp == NULL)
593 return NULL;
594
595 Profile *profile = (Profile *)vm_malloc(sizeof(Profile));
596 profile->sections = NULL;
597
598 Section **sp_ptr = &(profile->sections);
599 Section *sp = NULL;
600
601 KeyValue **kvp_ptr = NULL;
602
603 while ((str = read_line_from_file(fp)) != NULL) {
604 char *ptr = trim_string(str);
605
606 if (*ptr == '[') {
607 ptr++;
608
609 char *pend = strchr(ptr, ']');
610 if (pend != NULL) {
611 // if (pend[1]) { /* trailing garbage! */ }
612
613 *pend = 0;
614
615 if (*ptr) {
616 sp = (Section *)vm_malloc(sizeof(Section));
617 sp->next = NULL;
618
619 sp->name = vm_strdup(ptr);
620 sp->pairs = NULL;
621
622 *sp_ptr = sp;
623 sp_ptr = &(sp->next);
624
625 kvp_ptr = &(sp->pairs);
626 } // else { /* null name! */ }
627 } // else { /* incomplete section name! */ }
628 }
629 else {
630 if (*ptr) {
631 char *key = ptr;
632 char *value = NULL;
633
634 ptr = strchr(ptr, '=');
635 if (ptr != NULL) {
636 *ptr = 0;
637 ptr++;
638
639 value = ptr;
640 } // else { /* random garbage! */ }
641
642 if (key && *key && value /* && *value */) {
643 if (sp != NULL) {
644 KeyValue *kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
645
646 kvp->key = vm_strdup(key);
647 kvp->value = vm_strdup(value);
648
649 kvp->next = NULL;
650
651 *kvp_ptr = kvp;
652 kvp_ptr = &(kvp->next);
653 } // else { /* key/value with no section! */
654 } // else { /* malformed key/value entry! */ }
655 } // else it's just a comment or empty string
656 }
657
658 vm_free(str);
659 }
660
661 fclose(fp);
662
663 return profile;
664 }
665
profile_free(Profile * profile)666 static void profile_free(Profile *profile)
667 {
668 if (profile == NULL)
669 return;
670
671 Section *sp = profile->sections;
672 while (sp != NULL) {
673 Section *st = sp;
674 KeyValue *kvp = sp->pairs;
675
676 while (kvp != NULL) {
677 KeyValue *kvt = kvp;
678
679 vm_free(kvp->key);
680 vm_free(kvp->value);
681
682 kvp = kvp->next;
683 vm_free(kvt);
684 }
685
686 vm_free(sp->name);
687
688 sp = sp->next;
689 vm_free(st);
690 }
691
692 vm_free(profile);
693 }
694
profile_update(Profile * profile,const char * section,const char * key,const char * value)695 static Profile *profile_update(Profile *profile, const char *section, const char *key, const char *value)
696 {
697 if (profile == NULL) {
698 profile = (Profile *)vm_malloc(sizeof(Profile));
699
700 profile->sections = NULL;
701 }
702
703 KeyValue *kvp;
704
705 Section **sp_ptr = &(profile->sections);
706 Section *sp = profile->sections;
707
708 while (sp != NULL) {
709 if (strcmp(section, sp->name) == 0) {
710 KeyValue **kvp_ptr = &(sp->pairs);
711 kvp = sp->pairs;
712
713 while (kvp != NULL) {
714 if (strcmp(key, kvp->key) == 0) {
715 vm_free(kvp->value);
716
717 if (value == NULL) {
718 *kvp_ptr = kvp->next;
719
720 vm_free(kvp->key);
721 vm_free(kvp);
722 }
723 else {
724 kvp->value = vm_strdup(value);
725 }
726
727 /* all done */
728 return profile;
729 }
730
731 kvp_ptr = &(kvp->next);
732 kvp = kvp->next;
733 }
734
735 if (value != NULL) {
736 /* key not found */
737 kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
738 kvp->next = NULL;
739 kvp->key = vm_strdup(key);
740 kvp->value = vm_strdup(value);
741 }
742
743 *kvp_ptr = kvp;
744
745 /* all done */
746 return profile;
747 }
748
749 sp_ptr = &(sp->next);
750 sp = sp->next;
751 }
752
753 /* section not found */
754 sp = (Section *)vm_malloc(sizeof(Section));
755 sp->next = NULL;
756 sp->name = vm_strdup(section);
757
758 kvp = (KeyValue *)vm_malloc(sizeof(KeyValue));
759 kvp->next = NULL;
760 kvp->key = vm_strdup(key);
761 kvp->value = vm_strdup(value);
762
763 sp->pairs = kvp;
764
765 *sp_ptr = sp;
766
767 return profile;
768 }
769
profile_get_value(Profile * profile,const char * section,const char * key)770 static char *profile_get_value(Profile *profile, const char *section, const char *key)
771 {
772 if (profile == NULL)
773 return NULL;
774
775 Section *sp = profile->sections;
776
777 while (sp != NULL) {
778 if (stricmp(section, sp->name) == 0) {
779 KeyValue *kvp = sp->pairs;
780
781 while (kvp != NULL) {
782 if (strcmp(key, kvp->key) == 0) {
783 return kvp->value;
784 }
785 kvp = kvp->next;
786 }
787 }
788
789 sp = sp->next;
790 }
791
792 /* not found */
793 return NULL;
794 }
795
profile_save(Profile * profile,const char * file)796 static void profile_save(Profile *profile, const char *file)
797 {
798 FILE *fp = NULL;
799 char tmp[MAX_PATH] = "";
800 char tmp2[MAX_PATH] = "";
801
802 if (profile == NULL)
803 return;
804
805 fp = fopen(os_get_config_path(file).c_str(), "wt");
806
807 if (fp == NULL)
808 return;
809
810 Section *sp = profile->sections;
811
812 while (sp != NULL) {
813 sprintf(tmp, NOX("[%s]\n"), sp->name);
814 fputs(tmp, fp);
815
816 KeyValue *kvp = sp->pairs;
817 while (kvp != NULL) {
818 sprintf(tmp2, NOX("%s=%s\n"), kvp->key, kvp->value);
819 fputs(tmp2, fp);
820 kvp = kvp->next;
821 }
822
823 fprintf(fp, "\n");
824
825 sp = sp->next;
826 }
827
828 fclose(fp);
829 }
830
831 // os registry functions -------------------------------------------------------------
832
833 static Profile* Osreg_profile = nullptr;
834
835 // initialize the registry. setup default keys to use
os_init_registry_stuff(const char * company,const char * app)836 void os_init_registry_stuff(const char *company, const char *app)
837 {
838 if (company) {
839 strcpy_s(szCompanyName, company);
840 }
841 else {
842 strcpy_s(szCompanyName, Osreg_company_name);
843 }
844
845 if (app) {
846 strcpy_s(szAppName, app);
847 }
848 else {
849 strcpy_s(szAppName, Osreg_app_name);
850 }
851
852 Osreg_profile = profile_read(Osreg_config_file_name);
853
854 Os_reg_inited = 1;
855 }
os_deinit_registry_stuff()856 void os_deinit_registry_stuff()
857 {
858 if (Osreg_profile != nullptr) {
859 profile_free(Osreg_profile);
860 Osreg_profile = nullptr;
861 }
862 }
os_config_has_value(const char * section,const char * name)863 bool os_config_has_value(const char* section, const char* name) {
864 #ifdef WIN32
865 if (Osreg_profile == nullptr) {
866 // No config file, fall back to registy
867 return registry_read_string(section, name, nullptr) != nullptr;
868 }
869 #endif
870 if (section == nullptr)
871 section = DEFAULT_SECTION;
872
873 char *ptr = profile_get_value(Osreg_profile, section, name);
874
875 return ptr != nullptr;
876 }
877
os_config_read_string(const char * section,const char * name,const char * default_value)878 const char *os_config_read_string(const char *section, const char *name, const char *default_value)
879 {
880 #ifdef WIN32
881 if (Osreg_profile == nullptr) {
882 // No config file, fall back to registy
883 return registry_read_string(section, name, default_value);
884 }
885 #endif
886 nprintf(("Registry", "os_config_read_string(): section = \"%s\", name = \"%s\", default value: \"%s\"\n",
887 (section) ? section : DEFAULT_SECTION, name, (default_value) ? default_value : NOX("NULL")));
888
889 if (section == NULL)
890 section = DEFAULT_SECTION;
891
892 char *ptr = profile_get_value(Osreg_profile, section, name);
893
894 if (ptr != NULL) {
895 strncpy(tmp_string_data, ptr, 1023);
896 default_value = tmp_string_data;
897 }
898
899 return default_value;
900 }
901
os_config_read_uint(const char * section,const char * name,unsigned int default_value)902 unsigned int os_config_read_uint(const char *section, const char *name, unsigned int default_value)
903 {
904 #ifdef WIN32
905 if (Osreg_profile == nullptr) {
906 // No config file, fall back to registy
907 return registry_read_uint(section, name, default_value);
908 }
909 #endif
910
911 if (section == NULL)
912 section = DEFAULT_SECTION;
913
914 char *ptr = profile_get_value(Osreg_profile, section, name);
915
916 if (ptr != NULL) {
917 default_value = atoi(ptr);
918 }
919
920 return default_value;
921 }
922
os_config_write_string(const char * section,const char * name,const char * value)923 void os_config_write_string(const char *section, const char *name, const char *value)
924 {
925 #ifdef WIN32
926 // When there is no config file then it shouldn't be created because that would "hide" all previous settings
927 // Instead fall back to writing the settings to the config file
928 if (Osreg_profile == nullptr) {
929 registry_write_string(section, name, value);
930 return;
931 }
932 #endif
933
934 if (section == NULL)
935 section = DEFAULT_SECTION;
936
937 Osreg_profile = profile_update(Osreg_profile, section, name, value);
938 profile_save(Osreg_profile, Osreg_config_file_name);
939 }
940
os_config_write_uint(const char * section,const char * name,unsigned int value)941 void os_config_write_uint(const char *section, const char *name, unsigned int value)
942 {
943 #ifdef WIN32
944 // When there is no config file then it shouldn't be created because that would "hide" all previous settings
945 // Instead fall back to writing the settings to the config file
946 if (Osreg_profile == nullptr) {
947 registry_write_uint(section, name, value);
948 return;
949 }
950 #endif
951
952 if (section == NULL)
953 section = DEFAULT_SECTION;
954
955 char buf[21];
956
957 snprintf(buf, 20, "%u", value);
958
959 Osreg_profile = profile_update(Osreg_profile, section, name, buf);
960 profile_save(Osreg_profile, Osreg_config_file_name);
961 }
962
963