all repos — mgba @ 120020b0e39de4086495187f06c503fab2ed19e1

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