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}