all repos — mgba @ 1f204c8eefe74322cf49c827cbb43a12c960c994

mGBA Game Boy Advance Emulator

src/util/configuration.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 "configuration.h"
  7
  8#include "util/formatting.h"
  9#include "util/string.h"
 10#include "util/vfs.h"
 11
 12#include "third-party/inih/ini.h"
 13
 14#include <float.h>
 15
 16struct ConfigurationSectionHandlerData {
 17	void (*handler)(const char* section, void* data);
 18	void* data;
 19};
 20
 21static void _tableDeinit(void* table) {
 22	TableDeinit(table);
 23	free(table);
 24}
 25
 26static void _sectionDeinit(void* string) {
 27	free(string);
 28}
 29
 30static int _iniRead(void* configuration, const char* section, const char* key, const char* value) {
 31	if (section && !section[0]) {
 32		section = 0;
 33	}
 34	ConfigurationSetValue(configuration, section, key, value);
 35	return 1;
 36}
 37
 38static void _keyHandler(const char* key, void* value, void* user) {
 39	char line[256];
 40	struct VFile* vf = user;
 41	size_t len = snprintf(line, sizeof(line), "%s=%s\n", key, (const char*) value);
 42	if (len >= sizeof(line)) {
 43		len = sizeof(line) - 1;
 44	}
 45	vf->write(vf, line, len);
 46}
 47
 48static void _sectionHandler(const char* key, void* section, void* user) {
 49	char line[256];
 50	struct VFile* vf = user;
 51	size_t len = snprintf(line, sizeof(line), "[%s]\n", key);
 52	if (len >= sizeof(line)) {
 53		len = sizeof(line) - 1;
 54	}
 55	vf->write(vf, line, len);
 56	HashTableEnumerate(section, _keyHandler, user);
 57	vf->write(vf, "\n", 1);
 58}
 59
 60static void _sectionEnumHandler(const char* key, void* section, void* user) {
 61	struct ConfigurationSectionHandlerData* data = user;
 62	UNUSED(section);
 63	data->handler(key, data->data);
 64}
 65
 66void ConfigurationInit(struct Configuration* configuration) {
 67	HashTableInit(&configuration->sections, 0, _tableDeinit);
 68	HashTableInit(&configuration->root, 0, _sectionDeinit);
 69}
 70
 71void ConfigurationDeinit(struct Configuration* configuration) {
 72	HashTableDeinit(&configuration->sections);
 73	HashTableDeinit(&configuration->root);
 74}
 75
 76void ConfigurationSetValue(struct Configuration* configuration, const char* section, const char* key, const char* value) {
 77	struct Table* currentSection = &configuration->root;
 78	if (section) {
 79		currentSection = HashTableLookup(&configuration->sections, section);
 80		if (!currentSection) {
 81			if (value) {
 82				currentSection = malloc(sizeof(*currentSection));
 83				HashTableInit(currentSection, 0, _sectionDeinit);
 84				HashTableInsert(&configuration->sections, section, currentSection);
 85			} else {
 86				return;
 87			}
 88		}
 89	}
 90	if (value) {
 91		HashTableInsert(currentSection, key, strdup(value));
 92	} else {
 93		HashTableRemove(currentSection, key);
 94	}
 95}
 96
 97void ConfigurationSetIntValue(struct Configuration* configuration, const char* section, const char* key, int value) {
 98	char charValue[12];
 99	sprintf(charValue, "%i", value);
100	ConfigurationSetValue(configuration, section, key, charValue);
101}
102
103void ConfigurationSetUIntValue(struct Configuration* configuration, const char* section, const char* key, unsigned value) {
104	char charValue[12];
105	sprintf(charValue, "%u", value);
106	ConfigurationSetValue(configuration, section, key, charValue);
107}
108
109void ConfigurationSetFloatValue(struct Configuration* configuration, const char* section, const char* key, float value) {
110	char charValue[16];
111	ftostr_u(charValue, sizeof(charValue), value);
112	ConfigurationSetValue(configuration, section, key, charValue);
113}
114
115void ConfigurationClearValue(struct Configuration* configuration, const char* section, const char* key) {
116	struct Table* currentSection = &configuration->root;
117	if (section) {
118		currentSection = HashTableLookup(&configuration->sections, section);
119		if (!currentSection) {
120			return;
121		}
122	}
123	HashTableRemove(currentSection, key);
124}
125
126bool ConfigurationHasSection(const struct Configuration* configuration, const char* section) {
127	return HashTableLookup(&configuration->sections, section);
128}
129
130const char* ConfigurationGetValue(const struct Configuration* configuration, const char* section, const char* key) {
131	const struct Table* currentSection = &configuration->root;
132	if (section) {
133		currentSection = HashTableLookup(&configuration->sections, section);
134		if (!currentSection) {
135			return 0;
136		}
137	}
138	return HashTableLookup(currentSection, key);
139}
140
141static char* _vfgets(char* stream, int size, void* user) {
142	struct VFile* vf = user;
143	if (vf->readline(vf, stream, size) > 0) {
144		return stream;
145	}
146	return 0;
147}
148
149bool ConfigurationRead(struct Configuration* configuration, const char* path) {
150	struct VFile* vf = VFileOpen(path, O_RDONLY);
151	if (!vf) {
152		return false;
153	}
154	bool res = ConfigurationReadVFile(configuration, vf);
155	vf->close(vf);
156	return res;
157}
158
159bool ConfigurationReadVFile(struct Configuration* configuration, struct VFile* vf) {
160	HashTableClear(&configuration->root);
161	HashTableClear(&configuration->sections);
162	return ini_parse_stream(_vfgets, vf, _iniRead, configuration) == 0;
163}
164
165bool ConfigurationWrite(const struct Configuration* configuration, const char* path) {
166	struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC);
167	if (!vf) {
168		return false;
169	}
170	HashTableEnumerate(&configuration->root, _keyHandler, vf);
171	HashTableEnumerate(&configuration->sections, _sectionHandler, vf);
172	vf->close(vf);
173	return true;
174}
175
176bool ConfigurationWriteSection(const struct Configuration* configuration, const char* path, const char* section) {
177	const struct Table* currentSection = &configuration->root;
178	struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_APPEND);
179	if (!vf) {
180		return false;
181	}
182	if (section) {
183		currentSection = HashTableLookup(&configuration->sections, section);
184		char line[256];
185		size_t len = snprintf(line, sizeof(line), "[%s]\n", section);
186		if (len >= sizeof(line)) {
187			len = sizeof(line) - 1;
188		}
189		vf->write(vf, line, len);
190	}
191	if (currentSection) {
192		HashTableEnumerate(currentSection, _sectionHandler, vf);
193	}
194	vf->close(vf);
195	return true;
196}
197
198void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user) {
199	struct ConfigurationSectionHandlerData handlerData = { handler, user };
200	HashTableEnumerate(&configuration->sections, _sectionEnumHandler, &handlerData);
201}