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