1 /* ConfigParser.c - NeonServ v5.6
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "ConfigParser.h"
21 #define ENTRYTYPE_BLOCK 1
22 #define ENTRYTYPE_STRING 2
23 #define ENTRYTYPE_INTEGER 3
29 struct ConfigEntry *next;
32 static struct ConfigEntry *root_entry = NULL;
34 static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element);
35 static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry);
37 int loadConfig(const char *filename) {
39 f = fopen(filename, "rb");
44 fseek (f, 0, SEEK_END);
48 // allocate memory to contain the whole file:
49 char *buffer = (char*) malloc (sizeof(char)*lSize + 1);
55 // copy the file into the buffer:
56 size_t result = fread (buffer, 1, lSize, f);
57 if (result != lSize) {
65 // now parse the config file...
69 root_entry = malloc(sizeof(*root_entry));
70 if (!root_entry) return 0;
71 parse_config_recursive(root_entry, buffer, 1);
78 #define PARSER_FLAG_ESCAPED 0x01
79 #define PARSER_FLAG_BLOCK 0x02
80 #define PARSER_FLAG_STRING 0x04
81 #define PARSER_FLAG_EXPECT_END 0x08
82 #define PARSER_FLAG_NEXTCHAR 0x10
83 #define PARSER_FLAG_INTEGER 0x20
84 #define PARSER_FLAG_EOBN 0x40 /* End of Block name */
85 #define PARSER_FLAG_COMMAND 0x80
86 static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element) {
88 int type = (root_element ? ENTRYTYPE_BLOCK : 0);
91 struct ConfigEntry *sub_entrys = NULL;
93 if(flags & PARSER_FLAG_NEXTCHAR) {
98 flags |= PARSER_FLAG_NEXTCHAR;
99 if(flags & PARSER_FLAG_EOBN) {
100 flags &= ~(PARSER_FLAG_EOBN | PARSER_FLAG_NEXTCHAR);
101 struct ConfigEntry *new_entry = malloc(sizeof(*new_entry));
102 if (!new_entry) return buffer;
103 new_entry->name = strdup(cbuf);
104 buffer = parse_config_recursive(new_entry, buffer, 0);
106 new_entry->next = sub_entrys;
108 new_entry->next = NULL;
109 sub_entrys = new_entry;
110 centry->value = sub_entrys;
112 if(flags & PARSER_FLAG_ESCAPED) {
113 cbuf[cbufpos++] = *buffer;
114 flags &= ~PARSER_FLAG_ESCAPED;
117 if(flags & PARSER_FLAG_EXPECT_END) {
124 if(flags & PARSER_FLAG_STRING) {
126 cbuf[cbufpos] = '\0';
127 flags &= ~PARSER_FLAG_STRING;
128 if(type == ENTRYTYPE_STRING) {
129 flags |= PARSER_FLAG_EXPECT_END;
130 centry->value = strdup(cbuf);
131 } else if(type == ENTRYTYPE_BLOCK) {
132 flags |= PARSER_FLAG_EOBN;
134 } else if(*buffer == '\\')
135 flags |= PARSER_FLAG_ESCAPED;
137 cbuf[cbufpos++] = *buffer;
140 if(flags & PARSER_FLAG_INTEGER) {
141 if(!isdigit(*buffer)) {
142 cbuf[cbufpos] = '\0';
143 flags &= ~PARSER_FLAG_INTEGER;
144 if(type == ENTRYTYPE_INTEGER) {
145 flags |= PARSER_FLAG_EXPECT_END;
146 int *intbuf = malloc(sizeof(int));
147 *intbuf = atoi(cbuf);
148 centry->value = intbuf;
155 cbuf[cbufpos++] = *buffer;
158 if(flags & PARSER_FLAG_COMMAND) {
159 int found_command = 0;
164 buffer = strchr(buffer, '\r');
166 buffer = strchr(tmp_buffer, '\n');
168 buffer = tmp_buffer + strlen(tmp_buffer)-1;
172 //simple search for the next */
173 buffer = strstr(buffer, "*/")+1;
176 flags &= ~PARSER_FLAG_COMMAND;
182 flags |= PARSER_FLAG_ESCAPED;
185 if(!(flags & PARSER_FLAG_STRING)) {
186 flags |= PARSER_FLAG_COMMAND;
190 flags |= PARSER_FLAG_BLOCK;
191 type = ENTRYTYPE_BLOCK;
194 if(flags & PARSER_FLAG_BLOCK)
195 flags &= ~PARSER_FLAG_BLOCK;
196 flags |= PARSER_FLAG_EXPECT_END;
199 flags |= PARSER_FLAG_STRING;
201 type = ENTRYTYPE_STRING;
218 type = ENTRYTYPE_INTEGER;
219 flags |= PARSER_FLAG_INTEGER;
221 cbuf[cbufpos++] = *buffer;
228 return buffer; //end of the buffer
231 int get_int_field(char *field_path) {
232 struct ConfigEntry *centry = root_entry;
233 char *a, *b = field_path;
234 struct ConfigEntry *subentry;
235 while((a = strstr(b, ".")) && centry) {
236 if(centry->type == ENTRYTYPE_BLOCK) {
238 for(subentry = centry->value; subentry; subentry = subentry->next) {
239 if(!stricmplen(subentry->name, b, a-b)) {
251 if(centry->type == ENTRYTYPE_BLOCK) {
253 for(subentry = centry->value; subentry; subentry = subentry->next) {
254 if(!stricmp(subentry->name, b)) {
264 if(centry->type == ENTRYTYPE_INTEGER)
265 return ((int *)centry->value)[0];
270 char *get_string_field(char *field_path) {
271 struct ConfigEntry *centry = root_entry;
272 char *a, *b = field_path;
273 struct ConfigEntry *subentry;
274 while((a = strstr(b, ".")) && centry) {
275 if(centry->type == ENTRYTYPE_BLOCK) {
277 for(subentry = centry->value; subentry; subentry = subentry->next) {
278 if(!stricmplen(subentry->name, b, a-b)) {
290 if(centry->type == ENTRYTYPE_BLOCK) {
292 for(subentry = centry->value; subentry; subentry = subentry->next) {
293 if(!stricmp(subentry->name, b)) {
303 if(centry->type == ENTRYTYPE_STRING)
304 return centry->value;
309 char **get_all_fieldnames(char *block_path) {
310 struct ConfigEntry *centry = root_entry;
311 char *a, *b = block_path;
312 struct ConfigEntry *subentry;
313 while((a = strstr(b, ".")) && centry) {
314 if(centry->type == ENTRYTYPE_BLOCK) {
316 for(subentry = centry->value; subentry; subentry = subentry->next) {
317 if(!stricmplen(subentry->name, b, a-b)) {
329 if(centry->type == ENTRYTYPE_BLOCK) {
331 for(subentry = centry->value; subentry; subentry = subentry->next) {
332 if(!stricmp(subentry->name, b)) {
342 if(centry->type != ENTRYTYPE_BLOCK) return NULL;
344 for(subentry = centry->value; subentry; subentry = subentry->next) {
347 char **fieldnames = calloc(count+1, sizeof(char *));
349 for(subentry = centry->value; subentry; subentry = subentry->next) {
350 fieldnames[count++] = subentry->name;
355 void free_loaded_config() {
357 free_entry_rekursiv(root_entry, 1);
362 static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry) {
363 if(centry->type == ENTRYTYPE_BLOCK) {
364 struct ConfigEntry *subentry, *nextentry;
365 for(subentry = centry->value; subentry; subentry = nextentry) {
366 nextentry = subentry->next;
367 free_entry_rekursiv(subentry, 0);
369 } else if(centry->type == ENTRYTYPE_STRING) {
371 } else if(centry->type == ENTRYTYPE_INTEGER) {