added new self-made config parser with new config style
[NeonServV5.git] / src / ConfigParser.c
1 /* ConfigParser.c - NeonServ v5.2
2  * Copyright (C) 2011  Philipp Kreil (pk910)
3  * 
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.
8  * 
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.
13  * 
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/>. 
16  */
17
18 #include "ConfigParser.h"
19
20 #define ENTRYTYPE_BLOCK   1
21 #define ENTRYTYPE_STRING  2
22 #define ENTRYTYPE_INTEGER 3
23
24 struct ConfigEntry {
25     char *name;
26     int type;
27     void *value;
28     struct ConfigEntry *next;
29 };
30
31 static struct ConfigEntry *root_entry = NULL;
32
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);
35
36 int loadConfig(const char *filename) {
37     FILE *f;
38     f = fopen(filename, "rb");
39     if(!f) return 0;
40     
41     // obtain file size:
42     long lSize;
43     fseek (f, 0, SEEK_END);
44     lSize = ftell(f);
45     rewind(f);
46     
47     // allocate memory to contain the whole file:
48     char *buffer = (char*) malloc (sizeof(char)*lSize + 1);
49     if (buffer == NULL) return 0;
50     
51     // copy the file into the buffer:
52     size_t result = fread (buffer, 1, lSize, f);
53     if (result != lSize) return 0;
54     buffer[lSize] = '\0';
55     
56     // now parse the config file...
57     if(root_entry) {
58         free_loaded_config();
59     }
60     root_entry = malloc(sizeof(*root_entry));
61     if (!root_entry) return 0;
62     parse_config_recursive(root_entry, buffer, 1);
63     
64     // free the buffer...
65     free(buffer);
66     return 1;
67 }
68
69 #define PARSER_FLAG_ESCAPED    0x01
70 #define PARSER_FLAG_BLOCK      0x02
71 #define PARSER_FLAG_STRING     0x04
72 #define PARSER_FLAG_EXPECT_END 0x08
73 #define PARSER_FLAG_NEXTCHAR   0x10
74 #define PARSER_FLAG_INTEGER    0x20
75 #define PARSER_FLAG_EOBN       0x40 /* End of Block name */
76 #define PARSER_FLAG_COMMAND    0x80
77 static char *parse_config_recursive(struct ConfigEntry *centry, char *buffer, int root_element) {
78     int flags = 0;
79     int type = (root_element ? ENTRYTYPE_BLOCK : 0);
80     char cbuf[1024];
81     int cbufpos = 0;
82     struct ConfigEntry *sub_entrys = NULL;
83     while(*buffer) {
84         if(flags & PARSER_FLAG_NEXTCHAR) {
85             buffer++;
86             if(*buffer == '\0')
87                 break;
88         }
89         flags |= PARSER_FLAG_NEXTCHAR;
90         if(flags & PARSER_FLAG_EOBN) {
91             flags &= ~(PARSER_FLAG_EOBN | PARSER_FLAG_NEXTCHAR);
92             struct ConfigEntry *new_entry = malloc(sizeof(*new_entry));
93             if (!new_entry) return buffer;
94             new_entry->name = strdup(cbuf);
95             buffer = parse_config_recursive(new_entry, buffer, 0);
96             if(sub_entrys)
97                 new_entry->next = sub_entrys;
98             else
99                 new_entry->next = NULL;
100             sub_entrys = new_entry;
101             centry->value = sub_entrys;
102         }
103         if(flags & PARSER_FLAG_ESCAPED) {
104             cbuf[cbufpos++] = *buffer;
105             flags &= ~PARSER_FLAG_ESCAPED;
106             continue;
107         }
108         if(flags & PARSER_FLAG_EXPECT_END) {
109             if(*buffer == ';') {
110                 centry->type = type;
111                 return (buffer+1);
112             }
113             continue;
114         }
115         if(flags & PARSER_FLAG_STRING) {
116             if(*buffer == '"') {
117                 cbuf[cbufpos] = '\0';
118                 flags &= ~PARSER_FLAG_STRING;
119                 if(type == ENTRYTYPE_STRING) {
120                     flags |= PARSER_FLAG_EXPECT_END;
121                     centry->value = strdup(cbuf);
122                 } else if(type == ENTRYTYPE_BLOCK) {
123                     flags |= PARSER_FLAG_EOBN;
124                 }
125             } else if(*buffer == '\\')
126                 flags |= PARSER_FLAG_ESCAPED;
127             else
128                 cbuf[cbufpos++] = *buffer;
129             continue;
130         }
131         if(flags & PARSER_FLAG_INTEGER) {
132             if(!isdigit(*buffer)) {
133                 cbuf[cbufpos] = '\0';
134                 flags &= ~PARSER_FLAG_INTEGER;
135                 if(type == ENTRYTYPE_INTEGER) {
136                     flags |= PARSER_FLAG_EXPECT_END;
137                     int *intbuf = malloc(sizeof(int));
138                     *intbuf = atoi(cbuf);
139                     centry->value = intbuf;
140                 }
141                 if(*buffer == ';') {
142                     centry->type = type;
143                     return (buffer+1);
144                 }
145             } else
146                 cbuf[cbufpos++] = *buffer;
147             continue;
148         }
149         if(flags & PARSER_FLAG_COMMAND) {
150             int found_command = 0;
151             switch(*buffer) {
152                 case '/':
153                     buffer = strstr(buffer, "\n");
154                     found_command = 1;
155                     break;
156                 case '*':
157                     //simple search for the next */
158                     buffer = strstr(buffer, "*/")+1;
159                     found_command = 1;
160             }
161             flags &= ~PARSER_FLAG_COMMAND;
162             if(found_command)
163                 continue;
164         }
165         switch(*buffer) {
166             case '\\':
167                 flags |= PARSER_FLAG_ESCAPED;
168                 break;
169             case '/':
170                 if(!(flags & PARSER_FLAG_STRING)) {
171                     flags |= PARSER_FLAG_COMMAND;
172                 }
173                 break;
174             case '{':
175                 flags |= PARSER_FLAG_BLOCK;
176                 type = ENTRYTYPE_BLOCK;
177                 break;
178             case '}':
179                 if(flags & PARSER_FLAG_BLOCK)
180                     flags &= ~PARSER_FLAG_BLOCK;
181                 flags |= PARSER_FLAG_EXPECT_END;
182                 break;
183             case '"':
184                 flags |= PARSER_FLAG_STRING;
185                 if(!type)
186                     type = ENTRYTYPE_STRING;
187                 cbufpos = 0;
188                 break;
189             case ';':
190                 centry->type = type;
191                 return (buffer+1);
192             case '0':
193             case '1':
194             case '2':
195             case '3':
196             case '4':
197             case '5':
198             case '6':
199             case '7':
200             case '8':
201             case '9':
202                 if(!type)
203                     type = ENTRYTYPE_INTEGER;
204                 flags |= PARSER_FLAG_INTEGER;
205                 cbufpos = 0;
206                 cbuf[cbufpos++] = *buffer;
207                 break;
208             default:
209                 break;
210         }
211     }
212     centry->type = type;
213     return buffer; //end of the buffer
214 }
215
216 int get_int_field(char *field_path) {
217     struct ConfigEntry *centry = root_entry;
218     char *a, *b = field_path;
219     struct ConfigEntry *subentry;
220     while((a = strstr(b, ".")) && centry) {
221         if(centry->type == ENTRYTYPE_BLOCK) {
222             int found = 0;
223             for(subentry = centry->value; subentry; subentry = subentry->next) {
224                 if(!stricmplen(subentry->name, b, a-b)) {
225                     centry = subentry;
226                     found = 1;
227                     break;
228                 }
229             }
230             if(!found)
231                 return 0;
232         } else
233             return 0;
234         b = a+1;
235     }
236     if(centry->type == ENTRYTYPE_BLOCK) {
237         int found = 0;
238         for(subentry = centry->value; subentry; subentry = subentry->next) {
239             if(!stricmp(subentry->name, b)) {
240                 centry = subentry;
241                 found = 1;
242                 break;
243             }
244         }
245         if(!found)
246             return 0;
247     } else
248         return 0;
249     if(centry->type == ENTRYTYPE_INTEGER)
250         return ((int *)centry->value)[0];
251     else
252         return 0;
253 }
254
255 char *get_string_field(char *field_path) {
256     struct ConfigEntry *centry = root_entry;
257     char *a, *b = field_path;
258     struct ConfigEntry *subentry;
259     while((a = strstr(b, ".")) && centry) {
260         if(centry->type == ENTRYTYPE_BLOCK) {
261             int found = 0;
262             for(subentry = centry->value; subentry; subentry = subentry->next) {
263                 if(!stricmplen(subentry->name, b, a-b)) {
264                     centry = subentry;
265                     found = 1;
266                     break;
267                 }
268             }
269             if(!found)
270                 return NULL;
271         } else
272             return NULL;
273         b = a+1;
274     }
275     if(centry->type == ENTRYTYPE_BLOCK) {
276         int found = 0;
277         for(subentry = centry->value; subentry; subentry = subentry->next) {
278             if(!stricmp(subentry->name, b)) {
279                 centry = subentry;
280                 found = 1;
281                 break;
282             }
283         }
284         if(!found)
285             return NULL;
286     } else
287         return NULL;
288     if(centry->type == ENTRYTYPE_STRING)
289         return centry->value;
290     else
291         return NULL;
292 }
293
294 void free_loaded_config() {
295     if(root_entry) {
296         free_entry_rekursiv(root_entry, 1);
297         root_entry = NULL;
298     }
299 }
300
301 static void free_entry_rekursiv(struct ConfigEntry *centry, int is_root_entry) {
302     if(centry->type == ENTRYTYPE_BLOCK) {
303         struct ConfigEntry *subentry, *nextentry;
304         for(subentry = centry->value; subentry; subentry = nextentry) {
305             nextentry = subentry->next;
306             free_entry_rekursiv(subentry, 0);
307         }
308     } else if(centry->type == ENTRYTYPE_STRING) {
309         free(centry->value);
310     } else if(centry->type == ENTRYTYPE_INTEGER) {
311         free(centry->value);
312     }
313     if(!is_root_entry)
314         free(centry->name);
315     free(centry);
316 }