removed unused code in bots.c
[NeonServV5.git] / src / ConfigParser.c
1 /* ConfigParser.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  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) {
50         fclose(f);
51         return 0;
52     }
53     
54     // copy the file into the buffer:
55     size_t result = fread (buffer, 1, lSize, f);
56     if (result != lSize) {
57         fclose(f);
58         return 0;
59     }
60     buffer[lSize] = '\0';
61     
62     fclose(f);
63     
64     // now parse the config file...
65     if(root_entry) {
66         free_loaded_config();
67     }
68     root_entry = malloc(sizeof(*root_entry));
69     if (!root_entry) return 0;
70     parse_config_recursive(root_entry, buffer, 1);
71     
72     // free the buffer...
73     free(buffer);
74     return 1;
75 }
76
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) {
86     int flags = 0;
87     int type = (root_element ? ENTRYTYPE_BLOCK : 0);
88     char cbuf[1024];
89     int cbufpos = 0;
90     struct ConfigEntry *sub_entrys = NULL;
91     while(*buffer) {
92         if(flags & PARSER_FLAG_NEXTCHAR) {
93             buffer++;
94             if(*buffer == '\0')
95                 break;
96         }
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);
104             if(sub_entrys)
105                 new_entry->next = sub_entrys;
106             else
107                 new_entry->next = NULL;
108             sub_entrys = new_entry;
109             centry->value = sub_entrys;
110         }
111         if(flags & PARSER_FLAG_ESCAPED) {
112             cbuf[cbufpos++] = *buffer;
113             flags &= ~PARSER_FLAG_ESCAPED;
114             continue;
115         }
116         if(flags & PARSER_FLAG_EXPECT_END) {
117             if(*buffer == ';') {
118                 centry->type = type;
119                 return (buffer+1);
120             }
121             continue;
122         }
123         if(flags & PARSER_FLAG_STRING) {
124             if(*buffer == '"') {
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;
132                 }
133             } else if(*buffer == '\\')
134                 flags |= PARSER_FLAG_ESCAPED;
135             else
136                 cbuf[cbufpos++] = *buffer;
137             continue;
138         }
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;
148                 }
149                 if(*buffer == ';') {
150                     centry->type = type;
151                     return (buffer+1);
152                 }
153             } else
154                 cbuf[cbufpos++] = *buffer;
155             continue;
156         }
157         if(flags & PARSER_FLAG_COMMAND) {
158             int found_command = 0;
159             char *tmp_buffer;
160             switch(*buffer) {
161                 case '/':
162                     tmp_buffer = buffer;
163                     buffer = strchr(buffer, '\r');
164                     if(!buffer)
165                         buffer = strchr(tmp_buffer, '\n');
166                     if(!buffer)
167                         buffer = tmp_buffer + strlen(tmp_buffer)-1;
168                     found_command = 1;
169                     break;
170                 case '*':
171                     //simple search for the next */
172                     buffer = strstr(buffer, "*/")+1;
173                     found_command = 1;
174             }
175             flags &= ~PARSER_FLAG_COMMAND;
176             if(found_command)
177                 continue;
178         }
179         switch(*buffer) {
180             case '\\':
181                 flags |= PARSER_FLAG_ESCAPED;
182                 break;
183             case '/':
184                 if(!(flags & PARSER_FLAG_STRING)) {
185                     flags |= PARSER_FLAG_COMMAND;
186                 }
187                 break;
188             case '{':
189                 flags |= PARSER_FLAG_BLOCK;
190                 type = ENTRYTYPE_BLOCK;
191                 break;
192             case '}':
193                 if(flags & PARSER_FLAG_BLOCK)
194                     flags &= ~PARSER_FLAG_BLOCK;
195                 flags |= PARSER_FLAG_EXPECT_END;
196                 break;
197             case '"':
198                 flags |= PARSER_FLAG_STRING;
199                 if(!type)
200                     type = ENTRYTYPE_STRING;
201                 cbufpos = 0;
202                 break;
203             case ';':
204                 centry->type = type;
205                 return (buffer+1);
206             case '0':
207             case '1':
208             case '2':
209             case '3':
210             case '4':
211             case '5':
212             case '6':
213             case '7':
214             case '8':
215             case '9':
216                 if(!type)
217                     type = ENTRYTYPE_INTEGER;
218                 flags |= PARSER_FLAG_INTEGER;
219                 cbufpos = 0;
220                 cbuf[cbufpos++] = *buffer;
221                 break;
222             default:
223                 break;
224         }
225     }
226     centry->type = type;
227     return buffer; //end of the buffer
228 }
229
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) {
236             int found = 0;
237             for(subentry = centry->value; subentry; subentry = subentry->next) {
238                 if(!stricmplen(subentry->name, b, a-b)) {
239                     centry = subentry;
240                     found = 1;
241                     break;
242                 }
243             }
244             if(!found)
245                 return 0;
246         } else
247             return 0;
248         b = a+1;
249     }
250     if(centry->type == ENTRYTYPE_BLOCK) {
251         int found = 0;
252         for(subentry = centry->value; subentry; subentry = subentry->next) {
253             if(!stricmp(subentry->name, b)) {
254                 centry = subentry;
255                 found = 1;
256                 break;
257             }
258         }
259         if(!found)
260             return 0;
261     } else
262         return 0;
263     if(centry->type == ENTRYTYPE_INTEGER)
264         return ((int *)centry->value)[0];
265     else
266         return 0;
267 }
268
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) {
275             int found = 0;
276             for(subentry = centry->value; subentry; subentry = subentry->next) {
277                 if(!stricmplen(subentry->name, b, a-b)) {
278                     centry = subentry;
279                     found = 1;
280                     break;
281                 }
282             }
283             if(!found)
284                 return NULL;
285         } else
286             return NULL;
287         b = a+1;
288     }
289     if(centry->type == ENTRYTYPE_BLOCK) {
290         int found = 0;
291         for(subentry = centry->value; subentry; subentry = subentry->next) {
292             if(!stricmp(subentry->name, b)) {
293                 centry = subentry;
294                 found = 1;
295                 break;
296             }
297         }
298         if(!found)
299             return NULL;
300     } else
301         return NULL;
302     if(centry->type == ENTRYTYPE_STRING)
303         return centry->value;
304     else
305         return NULL;
306 }
307
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) {
314             int found = 0;
315             for(subentry = centry->value; subentry; subentry = subentry->next) {
316                 if(!stricmplen(subentry->name, b, a-b)) {
317                     centry = subentry;
318                     found = 1;
319                     break;
320                 }
321             }
322             if(!found)
323                 return NULL;
324         } else
325             return NULL;
326         b = a+1;
327     }
328     if(centry->type == ENTRYTYPE_BLOCK) {
329         int found = 0;
330         for(subentry = centry->value; subentry; subentry = subentry->next) {
331             if(!stricmp(subentry->name, b)) {
332                 centry = subentry;
333                 found = 1;
334                 break;
335             }
336         }
337         if(!found)
338             return NULL;
339     } else
340         return NULL;
341     if(centry->type != ENTRYTYPE_BLOCK) return NULL;
342     int count = 0;
343     for(subentry = centry->value; subentry; subentry = subentry->next) {
344         count++;
345     }
346     char **fieldnames = calloc(count+1, sizeof(char *));
347     count = 0;
348     for(subentry = centry->value; subentry; subentry = subentry->next) {
349         fieldnames[count++] = subentry->name;
350     }
351     return fieldnames;
352 }
353
354 void free_loaded_config() {
355     if(root_entry) {
356         free_entry_rekursiv(root_entry, 1);
357         root_entry = NULL;
358     }
359 }
360
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);
367         }
368     } else if(centry->type == ENTRYTYPE_STRING) {
369         free(centry->value);
370     } else if(centry->type == ENTRYTYPE_INTEGER) {
371         free(centry->value);
372     }
373     if(!is_root_entry)
374         free(centry->name);
375     free(centry);
376 }