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"
20 #define ENTRYTYPE_BLOCK 1
21 #define ENTRYTYPE_STRING 2
22 #define ENTRYTYPE_INTEGER 3
28 struct ConfigEntry *next;
31 static struct ConfigEntry *root_entry = NULL;
33 static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element);
34 static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry);
36 int loadConfig(const char *filename) {
38 f = fopen(filename, "rb");
43 fseek (f, 0, SEEK_END);
47 // allocate memory to contain the whole file:
48 char *buffer = (char*) malloc (sizeof(char)*lSize + 1);
54 // copy the file into the buffer:
55 size_t result = fread (buffer, 1, lSize, f);
56 if (result != lSize) {
64 // now parse the config file...
68 root_entry = malloc(sizeof(*root_entry));
69 if (!root_entry) return 0;
70 parse_config_recursive(root_entry, buffer, 1);
77 #define PARSER_FLAG_ESCAPED 0x01
78 #define PARSER_FLAG_BLOCK 0x02
79 #define PARSER_FLAG_STRING 0x04
80 #define PARSER_FLAG_EXPECT_END 0x08
81 #define PARSER_FLAG_NEXTCHAR 0x10
82 #define PARSER_FLAG_INTEGER 0x20
83 #define PARSER_FLAG_EOBN 0x40 /* End of Block name */
84 #define PARSER_FLAG_COMMAND 0x80
85 static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element) {
87 int type = (root_element ? ENTRYTYPE_BLOCK : 0);
90 struct ConfigEntry *sub_entrys = NULL;
92 if(flags & PARSER_FLAG_NEXTCHAR) {
97 flags |= PARSER_FLAG_NEXTCHAR;
98 if(flags & PARSER_FLAG_EOBN) {
99 flags &= ~(PARSER_FLAG_EOBN | PARSER_FLAG_NEXTCHAR);
100 struct ConfigEntry *new_entry = malloc(sizeof(*new_entry));
101 if (!new_entry) return buffer;
102 new_entry->name = strdup(cbuf);
103 buffer = parse_config_recursive(new_entry, buffer, 0);
105 new_entry->next = sub_entrys;
107 new_entry->next = NULL;
108 sub_entrys = new_entry;
109 centry->value = sub_entrys;
111 if(flags & PARSER_FLAG_ESCAPED) {
112 cbuf[cbufpos++] = *buffer;
113 flags &= ~PARSER_FLAG_ESCAPED;
116 if(flags & PARSER_FLAG_EXPECT_END) {
123 if(flags & PARSER_FLAG_STRING) {
125 cbuf[cbufpos] = '\0';
126 flags &= ~PARSER_FLAG_STRING;
127 if(type == ENTRYTYPE_STRING) {
128 flags |= PARSER_FLAG_EXPECT_END;
129 centry->value = strdup(cbuf);
130 } else if(type == ENTRYTYPE_BLOCK) {
131 flags |= PARSER_FLAG_EOBN;
133 } else if(*buffer == '\\')
134 flags |= PARSER_FLAG_ESCAPED;
136 cbuf[cbufpos++] = *buffer;
139 if(flags & PARSER_FLAG_INTEGER) {
140 if(!isdigit(*buffer)) {
141 cbuf[cbufpos] = '\0';
142 flags &= ~PARSER_FLAG_INTEGER;
143 if(type == ENTRYTYPE_INTEGER) {
144 flags |= PARSER_FLAG_EXPECT_END;
145 int *intbuf = malloc(sizeof(int));
146 *intbuf = atoi(cbuf);
147 centry->value = intbuf;
154 cbuf[cbufpos++] = *buffer;
157 if(flags & PARSER_FLAG_COMMAND) {
158 int found_command = 0;
163 buffer = strchr(buffer, '\r');
165 buffer = strchr(tmp_buffer, '\n');
167 buffer = tmp_buffer + strlen(tmp_buffer)-1;
171 //simple search for the next */
172 buffer = strstr(buffer, "*/")+1;
175 flags &= ~PARSER_FLAG_COMMAND;
181 flags |= PARSER_FLAG_ESCAPED;
184 if(!(flags & PARSER_FLAG_STRING)) {
185 flags |= PARSER_FLAG_COMMAND;
189 flags |= PARSER_FLAG_BLOCK;
190 type = ENTRYTYPE_BLOCK;
193 if(flags & PARSER_FLAG_BLOCK)
194 flags &= ~PARSER_FLAG_BLOCK;
195 flags |= PARSER_FLAG_EXPECT_END;
198 flags |= PARSER_FLAG_STRING;
200 type = ENTRYTYPE_STRING;
217 type = ENTRYTYPE_INTEGER;
218 flags |= PARSER_FLAG_INTEGER;
220 cbuf[cbufpos++] = *buffer;
227 return buffer; //end of the buffer
230 int get_int_field(char *field_path) {
231 struct ConfigEntry *centry = root_entry;
232 char *a, *b = field_path;
233 struct ConfigEntry *subentry;
234 while((a = strstr(b, ".")) && centry) {
235 if(centry->type == ENTRYTYPE_BLOCK) {
237 for(subentry = centry->value; subentry; subentry = subentry->next) {
238 if(!stricmplen(subentry->name, b, a-b)) {
250 if(centry->type == ENTRYTYPE_BLOCK) {
252 for(subentry = centry->value; subentry; subentry = subentry->next) {
253 if(!stricmp(subentry->name, b)) {
263 if(centry->type == ENTRYTYPE_INTEGER)
264 return ((int *)centry->value)[0];
269 char *get_string_field(char *field_path) {
270 struct ConfigEntry *centry = root_entry;
271 char *a, *b = field_path;
272 struct ConfigEntry *subentry;
273 while((a = strstr(b, ".")) && centry) {
274 if(centry->type == ENTRYTYPE_BLOCK) {
276 for(subentry = centry->value; subentry; subentry = subentry->next) {
277 if(!stricmplen(subentry->name, b, a-b)) {
289 if(centry->type == ENTRYTYPE_BLOCK) {
291 for(subentry = centry->value; subentry; subentry = subentry->next) {
292 if(!stricmp(subentry->name, b)) {
302 if(centry->type == ENTRYTYPE_STRING)
303 return centry->value;
308 char **get_all_fieldnames(char *block_path) {
309 struct ConfigEntry *centry = root_entry;
310 char *a, *b = block_path;
311 struct ConfigEntry *subentry;
312 while((a = strstr(b, ".")) && centry) {
313 if(centry->type == ENTRYTYPE_BLOCK) {
315 for(subentry = centry->value; subentry; subentry = subentry->next) {
316 if(!stricmplen(subentry->name, b, a-b)) {
328 if(centry->type == ENTRYTYPE_BLOCK) {
330 for(subentry = centry->value; subentry; subentry = subentry->next) {
331 if(!stricmp(subentry->name, b)) {
341 if(centry->type != ENTRYTYPE_BLOCK) return NULL;
343 for(subentry = centry->value; subentry; subentry = subentry->next) {
346 char **fieldnames = calloc(count+1, sizeof(char *));
348 for(subentry = centry->value; subentry; subentry = subentry->next) {
349 fieldnames[count++] = subentry->name;
354 void free_loaded_config() {
356 free_entry_rekursiv(root_entry, 1);
361 static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry) {
362 if(centry->type == ENTRYTYPE_BLOCK) {
363 struct ConfigEntry *subentry, *nextentry;
364 for(subentry = centry->value; subentry; subentry = nextentry) {
365 nextentry = subentry->next;
366 free_entry_rekursiv(subentry, 0);
368 } else if(centry->type == ENTRYTYPE_STRING) {
370 } else if(centry->type == ENTRYTYPE_INTEGER) {