all repos — mgba @ 6363a0817886183fefdcd544b190ef809bbb951d

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