all repos — mgba @ 7a9807f030b80c3c38b6587a385ad7d2e44d16f7

mGBA Game Boy Advance Emulator

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
 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_u(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, "useBios", &fakeBool)) {
194		opts->useBios = fakeBool;
195	}
196	if (_lookupIntValue(config, "audioSync", &fakeBool)) {
197		opts->audioSync = fakeBool;
198	}
199	if (_lookupIntValue(config, "videoSync", &fakeBool)) {
200		opts->videoSync = fakeBool;
201	}
202	if (_lookupIntValue(config, "lockAspectRatio", &fakeBool)) {
203		opts->lockAspectRatio = fakeBool;
204	}
205	if (_lookupIntValue(config, "resampleVideo", &fakeBool)) {
206		opts->resampleVideo = fakeBool;
207	}
208	if (_lookupIntValue(config, "skipBios", &fakeBool)) {
209		opts->skipBios = fakeBool;
210	}
211	if (_lookupIntValue(config, "rewindEnable", &fakeBool)) {
212		opts->rewindEnable = fakeBool;
213	}
214
215	_lookupIntValue(config, "fullscreen", &opts->fullscreen);
216	_lookupIntValue(config, "width", &opts->width);
217	_lookupIntValue(config, "height", &opts->height);
218
219	char* idleOptimization = 0;
220	if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) {
221		if (strcasecmp(idleOptimization, "ignore") == 0) {
222			opts->idleOptimization = IDLE_LOOP_IGNORE;
223		} else if (strcasecmp(idleOptimization, "remove") == 0) {
224			opts->idleOptimization = IDLE_LOOP_REMOVE;
225		} else if (strcasecmp(idleOptimization, "detect") == 0) {
226			opts->idleOptimization = IDLE_LOOP_DETECT;
227		}
228		free(idleOptimization);
229	}
230}
231
232void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* opts) {
233	ConfigurationSetValue(&config->defaultsTable, 0, "bios", opts->bios);
234	ConfigurationSetIntValue(&config->defaultsTable, 0, "skipBios", opts->skipBios);
235	ConfigurationSetIntValue(&config->defaultsTable, 0, "useBios", opts->useBios);
236	ConfigurationSetIntValue(&config->defaultsTable, 0, "logLevel", opts->logLevel);
237	ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip);
238	ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable);
239	ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity);
240	ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval);
241	ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget);
242	ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers);
243	ConfigurationSetIntValue(&config->defaultsTable, 0, "audioSync", opts->audioSync);
244	ConfigurationSetIntValue(&config->defaultsTable, 0, "videoSync", opts->videoSync);
245	ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen);
246	ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width);
247	ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height);
248	ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio);
249	ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo);
250
251	switch (opts->idleOptimization) {
252	case IDLE_LOOP_IGNORE:
253		ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "ignore");
254		break;
255	case IDLE_LOOP_REMOVE:
256		ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "remove");
257		break;
258	case IDLE_LOOP_DETECT:
259		ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "detect");
260		break;
261	}
262}
263
264// These two are basically placeholders in case the internal layout changes, e.g. for loading separate files
265struct Configuration* GBAConfigGetInput(struct GBAConfig* config) {
266	return &config->configTable;
267}
268
269struct Configuration* GBAConfigGetOverrides(struct GBAConfig* config) {
270	return &config->configTable;
271}
272
273void GBAConfigFreeOpts(struct GBAOptions* opts) {
274	free(opts->bios);
275	opts->bios = 0;
276}