all repos — mgba @ 42a2a5737b62b020cf577af4abb20ffa4419b8ea

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