src/gba/supervisor/config.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "config.h"
7
8#include "util/formatting.h"
9#include "util/vfs.h"
10
11#include <sys/stat.h>
12
13#ifdef _WIN32
14#include <windows.h>
15#include <shlobj.h>
16#include <strsafe.h>
17#endif
18
19#define SECTION_NAME_MAX 128
20
21static const char* _lookupValue(const struct GBAConfig* config, const char* key) {
22 const char* value;
23 if (config->port) {
24 value = ConfigurationGetValue(&config->configTable, config->port, key);
25 if (value) {
26 return value;
27 }
28 }
29 value = ConfigurationGetValue(&config->configTable, 0, key);
30 if (value) {
31 return value;
32 }
33 if (config->port) {
34 value = ConfigurationGetValue(&config->defaultsTable, config->port, key);
35 if (value) {
36 return value;
37 }
38 }
39 return ConfigurationGetValue(&config->defaultsTable, 0, key);
40}
41
42static bool _lookupCharValue(const struct GBAConfig* config, const char* key, char** out) {
43 const char* value = _lookupValue(config, key);
44 if (!value) {
45 return false;
46 }
47 if (*out) {
48 free(*out);
49 }
50 *out = strdup(value);
51 return true;
52}
53
54static bool _lookupIntValue(const struct GBAConfig* config, const char* key, int* out) {
55 const char* charValue = _lookupValue(config, key);
56 if (!charValue) {
57 return false;
58 }
59 char* end;
60 long value = strtol(charValue, &end, 10);
61 if (*end) {
62 return false;
63 }
64 *out = value;
65 return true;
66}
67
68static bool _lookupUIntValue(const struct GBAConfig* config, const char* key, unsigned* out) {
69 const char* charValue = _lookupValue(config, key);
70 if (!charValue) {
71 return false;
72 }
73 char* end;
74 unsigned long value = strtoul(charValue, &end, 10);
75 if (*end) {
76 return false;
77 }
78 *out = value;
79 return true;
80}
81
82static bool _lookupFloatValue(const struct GBAConfig* config, const char* key, float* out) {
83 const char* charValue = _lookupValue(config, key);
84 if (!charValue) {
85 return false;
86 }
87 char* end;
88 float value = strtof_u(charValue, &end);
89 if (*end) {
90 return false;
91 }
92 *out = value;
93 return true;
94}
95
96void GBAConfigInit(struct GBAConfig* config, const char* port) {
97 ConfigurationInit(&config->configTable);
98 ConfigurationInit(&config->defaultsTable);
99 if (port) {
100 config->port = malloc(strlen("ports.") + strlen(port) + 1);
101 snprintf(config->port, strlen("ports.") + strlen(port) + 1, "ports.%s", port);
102 } else {
103 config->port = 0;
104 }
105}
106
107void GBAConfigDeinit(struct GBAConfig* config) {
108 ConfigurationDeinit(&config->configTable);
109 ConfigurationDeinit(&config->defaultsTable);
110 free(config->port);
111}
112
113bool GBAConfigLoad(struct GBAConfig* config) {
114 char path[PATH_MAX];
115 GBAConfigDirectory(path, PATH_MAX);
116 strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path));
117 return ConfigurationRead(&config->configTable, path);
118}
119
120bool GBAConfigSave(const struct GBAConfig* config) {
121 char path[PATH_MAX];
122 GBAConfigDirectory(path, PATH_MAX);
123 strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path));
124 return ConfigurationWrite(&config->configTable, path);
125}
126
127void GBAConfigDirectory(char* out, size_t outLength) {
128#ifndef _WIN32
129 char* home = getenv("HOME");
130 snprintf(out, outLength, "%s/.config", home);
131 mkdir(out, 0755);
132 snprintf(out, outLength, "%s/.config/%s", home, BINARY_NAME);
133 mkdir(out, 0755);
134#else
135 char home[MAX_PATH];
136 SHGetFolderPath(0, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, home);
137 snprintf(out, outLength, "%s\\%s", home, PROJECT_NAME);
138 CreateDirectoryA(out, NULL);
139#endif
140}
141
142const char* GBAConfigGetValue(const struct GBAConfig* config, const char* key) {
143 return _lookupValue(config, key);
144}
145
146void GBAConfigSetValue(struct GBAConfig* config, const char* key, const char* value) {
147 ConfigurationSetValue(&config->configTable, config->port, key, value);
148}
149
150void GBAConfigSetIntValue(struct GBAConfig* config, const char* key, int value) {
151 ConfigurationSetIntValue(&config->configTable, config->port, key, value);
152}
153
154void GBAConfigSetUIntValue(struct GBAConfig* config, const char* key, unsigned value) {
155 ConfigurationSetUIntValue(&config->configTable, config->port, key, value);
156}
157
158void GBAConfigSetFloatValue(struct GBAConfig* config, const char* key, float value) {
159 ConfigurationSetFloatValue(&config->configTable, config->port, key, value);
160}
161
162void GBAConfigSetDefaultValue(struct GBAConfig* config, const char* key, const char* value) {
163 ConfigurationSetValue(&config->defaultsTable, config->port, key, value);
164}
165
166void GBAConfigSetDefaultIntValue(struct GBAConfig* config, const char* key, int value) {
167 ConfigurationSetIntValue(&config->defaultsTable, config->port, key, value);
168}
169
170void GBAConfigSetDefaultUIntValue(struct GBAConfig* config, const char* key, unsigned value) {
171 ConfigurationSetUIntValue(&config->defaultsTable, config->port, key, value);
172}
173
174void GBAConfigSetDefaultFloatValue(struct GBAConfig* config, const char* key, float value) {
175 ConfigurationSetFloatValue(&config->defaultsTable, config->port, key, value);
176}
177
178void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) {
179 _lookupCharValue(config, "bios", &opts->bios);
180 _lookupIntValue(config, "logLevel", &opts->logLevel);
181 _lookupIntValue(config, "frameskip", &opts->frameskip);
182 _lookupIntValue(config, "volume", &opts->volume);
183 _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity);
184 _lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval);
185 _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget);
186 unsigned audioBuffers;
187 if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) {
188 opts->audioBuffers = audioBuffers;
189 }
190
191 int fakeBool;
192 if (_lookupIntValue(config, "useBios", &fakeBool)) {
193 opts->useBios = fakeBool;
194 }
195 if (_lookupIntValue(config, "audioSync", &fakeBool)) {
196 opts->audioSync = fakeBool;
197 }
198 if (_lookupIntValue(config, "videoSync", &fakeBool)) {
199 opts->videoSync = fakeBool;
200 }
201 if (_lookupIntValue(config, "lockAspectRatio", &fakeBool)) {
202 opts->lockAspectRatio = fakeBool;
203 }
204 if (_lookupIntValue(config, "resampleVideo", &fakeBool)) {
205 opts->resampleVideo = fakeBool;
206 }
207 if (_lookupIntValue(config, "suspendScreensaver", &fakeBool)) {
208 opts->suspendScreensaver = fakeBool;
209 }
210 if (_lookupIntValue(config, "mute", &fakeBool)) {
211 opts->mute = fakeBool;
212 }
213 if (_lookupIntValue(config, "skipBios", &fakeBool)) {
214 opts->skipBios = fakeBool;
215 }
216 if (_lookupIntValue(config, "rewindEnable", &fakeBool)) {
217 opts->rewindEnable = fakeBool;
218 }
219
220 _lookupIntValue(config, "fullscreen", &opts->fullscreen);
221 _lookupIntValue(config, "width", &opts->width);
222 _lookupIntValue(config, "height", &opts->height);
223
224 char* idleOptimization = 0;
225 if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) {
226 if (strcasecmp(idleOptimization, "ignore") == 0) {
227 opts->idleOptimization = IDLE_LOOP_IGNORE;
228 } else if (strcasecmp(idleOptimization, "remove") == 0) {
229 opts->idleOptimization = IDLE_LOOP_REMOVE;
230 } else if (strcasecmp(idleOptimization, "detect") == 0) {
231 opts->idleOptimization = IDLE_LOOP_DETECT;
232 }
233 free(idleOptimization);
234 }
235}
236
237void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* opts) {
238 ConfigurationSetValue(&config->defaultsTable, 0, "bios", opts->bios);
239 ConfigurationSetIntValue(&config->defaultsTable, 0, "skipBios", opts->skipBios);
240 ConfigurationSetIntValue(&config->defaultsTable, 0, "useBios", opts->useBios);
241 ConfigurationSetIntValue(&config->defaultsTable, 0, "logLevel", opts->logLevel);
242 ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip);
243 ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable);
244 ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity);
245 ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval);
246 ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget);
247 ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers);
248 ConfigurationSetIntValue(&config->defaultsTable, 0, "audioSync", opts->audioSync);
249 ConfigurationSetIntValue(&config->defaultsTable, 0, "videoSync", opts->videoSync);
250 ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen);
251 ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width);
252 ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height);
253 ConfigurationSetIntValue(&config->defaultsTable, 0, "volume", opts->volume);
254 ConfigurationSetIntValue(&config->defaultsTable, 0, "mute", opts->mute);
255 ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio);
256 ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo);
257 ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver);
258
259 switch (opts->idleOptimization) {
260 case IDLE_LOOP_IGNORE:
261 ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "ignore");
262 break;
263 case IDLE_LOOP_REMOVE:
264 ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "remove");
265 break;
266 case IDLE_LOOP_DETECT:
267 ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "detect");
268 break;
269 }
270}
271
272// These two are basically placeholders in case the internal layout changes, e.g. for loading separate files
273struct Configuration* GBAConfigGetInput(struct GBAConfig* config) {
274 return &config->configTable;
275}
276
277struct Configuration* GBAConfigGetOverrides(struct GBAConfig* config) {
278 return &config->configTable;
279}
280
281void GBAConfigFreeOpts(struct GBAOptions* opts) {
282 free(opts->bios);
283 opts->bios = 0;
284}