42 FILE *in = fopen(file, "r"); |
42 FILE *in = fopen(file, "r"); |
43 if(in == NULL) { |
43 if(in == NULL) { |
44 return NULL; |
44 return NULL; |
45 } |
45 } |
46 |
46 |
|
47 CxMempool *mp = cxBasicMempoolCreate(512); |
|
48 if(!mp) { |
|
49 fclose(in); |
|
50 return NULL; |
|
51 } |
|
52 |
47 CxBuffer buf; |
53 CxBuffer buf; |
48 cxBufferInit(&buf, NULL, 16384, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS); |
54 if(cxBufferInit(&buf, NULL, 16384, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { |
|
55 fclose(in); |
|
56 cxMempoolDestroy(mp); |
|
57 return NULL; |
|
58 } |
49 |
59 |
50 //ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); |
60 //ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); |
51 char readbuf[2048]; |
61 char readbuf[2048]; |
52 size_t r; |
62 size_t r; |
53 while((r = fread(readbuf, 1, 2048, in)) > 0) { |
63 while((r = fread(readbuf, 1, 2048, in)) > 0) { |
54 cxBufferWrite(readbuf, 1, r, &buf); |
64 cxBufferWrite(readbuf, 1, r, &buf); |
55 } |
65 } |
56 fclose(in); |
66 fclose(in); |
57 |
67 |
58 ServerConfig *scfg = serverconfig_parse(cx_strn(buf.space, buf.size)); |
68 ConfigParser2 parser; |
|
69 ZERO(&parser, sizeof(ConfigParser2)); |
|
70 parser.mp = mp; |
|
71 parser.allow_hierarchy = true; |
|
72 ServerConfig *scfg = serverconfig_parse(&parser, cx_strn(buf.space, buf.size)); |
59 |
73 |
60 cxBufferDestroy(&buf); |
74 cxBufferDestroy(&buf); |
61 return scfg; |
75 return scfg; |
62 } |
76 } |
63 |
77 |
188 elm->next = NULL; |
202 elm->next = NULL; |
189 cx_linked_list_prepend((void**)stack, NULL, -1, offsetof(ConfigNodeStack, next), elm); |
203 cx_linked_list_prepend((void**)stack, NULL, -1, offsetof(ConfigNodeStack, next), elm); |
190 return 0; |
204 return 0; |
191 } |
205 } |
192 |
206 |
193 ServerConfig* serverconfig_parse(cxstring content) { |
207 ServerConfig* serverconfig_parse(ConfigParser2 *parser, cxstring content) { |
194 CxMempool *mp = cxBasicMempoolCreate(512); |
208 CxMempool *mp = parser->mp; |
195 if(!mp) return NULL; |
|
196 CxAllocator *a = (CxAllocator*)mp->allocator; |
209 CxAllocator *a = (CxAllocator*)mp->allocator; |
197 |
210 |
198 ServerConfig *config = cxMalloc(a, sizeof(ServerConfig)); |
211 ServerConfig *config = cxMalloc(a, sizeof(ServerConfig)); |
199 if(!config) { |
212 if(!config) { |
200 cxMempoolDestroy(mp); |
213 cxMempoolDestroy(mp); |
246 ConfigNode *parent = node_stack->node; |
259 ConfigNode *parent = node_stack->node; |
247 if(current->type == CONFIG_NODE_CLOSE_OBJECT) { |
260 if(current->type == CONFIG_NODE_CLOSE_OBJECT) { |
248 // this is a newline after a object is closed with '}' |
261 // this is a newline after a object is closed with '}' |
249 // the line containing "}\n" should be added to the object |
262 // the line containing "}\n" should be added to the object |
250 parent->text_end = line_cp; |
263 parent->text_end = line_cp; |
|
264 // validate |
|
265 if(parser->validateObjEnd && parser->validateObjEnd(parser, parent)) { |
|
266 // validation failed |
|
267 err = 1; |
|
268 break; |
|
269 } |
251 // done with this object, remove it from the stack |
270 // done with this object, remove it from the stack |
252 ConfigNodeStack *remove_item = node_stack; |
271 ConfigNodeStack *remove_item = node_stack; |
253 node_stack = node_stack->next; |
272 node_stack = node_stack->next; |
254 cxFree(a, remove_item); |
273 cxFree(a, remove_item); |
255 } else if(current->type == CONFIG_NODE_OPEN_OBJECT) { |
274 } else if(current->type == CONFIG_NODE_OPEN_OBJECT) { |
259 cxFree(a, obj->text_begin.ptr); |
278 cxFree(a, obj->text_begin.ptr); |
260 cxFree(a, line_cp.ptr); |
279 cxFree(a, line_cp.ptr); |
261 obj->text_begin = new_textbegin; |
280 obj->text_begin = new_textbegin; |
262 } else { |
281 } else { |
263 // normal line containing a directive, space or comment |
282 // normal line containing a directive, space or comment |
|
283 if(parser->validateDirective && parser->validateDirective(parser, current)) { |
|
284 err = 1; |
|
285 break; |
|
286 } |
264 // add it to parent node |
287 // add it to parent node |
265 current->text_begin = line_cp; |
288 current->text_begin = line_cp; |
266 CFG_NODE_ADD(&parent->children_begin, &parent->children_end, current); |
289 CFG_NODE_ADD(&parent->children_begin, &parent->children_end, current); |
267 } |
290 } |
268 |
291 |
269 // obj points to the previous node that started as a directive |
292 // obj points to the previous node that started as a directive |
270 // the type is set to CONFIG_NODE_OBECT if it was followed by |
293 // the type is set to CONFIG_NODE_OBECT if it was followed by |
271 // a '{' character |
294 // a '{' character |
272 if(obj && obj->type == CONFIG_NODE_OBJECT) { |
295 if(obj && obj->type == CONFIG_NODE_OBJECT) { |
273 // new object started, add it to the stack |
296 // new object started |
|
297 if(parser->validateObjBegin && parser->validateObjBegin(parser, obj)) { |
|
298 // validation callback failed |
|
299 err = 1; |
|
300 break; |
|
301 } |
|
302 |
|
303 // add it to the stack |
274 nodestack_prepend(a, &node_stack, obj); |
304 nodestack_prepend(a, &node_stack, obj); |
275 obj = NULL; |
305 obj = NULL; |
276 } |
306 } |
277 |
307 |
278 current = cxCalloc(a, 1, sizeof(ConfigNode)); |
308 current = cxCalloc(a, 1, sizeof(ConfigNode)); |
284 case CFG_TOKEN: { |
314 case CFG_TOKEN: { |
285 // normal text token |
315 // normal text token |
286 // either a directive/obj name, parameter or { } |
316 // either a directive/obj name, parameter or { } |
287 |
317 |
288 if(!cx_strcmp(token.content, cx_str("{"))) { |
318 if(!cx_strcmp(token.content, cx_str("{"))) { |
|
319 // check if the parser allows an object hierarchy |
|
320 if(!parser->allow_hierarchy) { |
|
321 parser->error = CONFIG_PARSER_SYNTAX_ERROR; |
|
322 err = 1; |
|
323 break; |
|
324 } |
|
325 |
289 // obj is pointing to the previous node that started |
326 // obj is pointing to the previous node that started |
290 // a directive |
327 // a directive |
291 if(!obj) { |
328 if(!obj) { |
292 err = 1; |
329 err = 1; |
293 break; |
330 break; |
295 obj->type = CONFIG_NODE_OBJECT; |
332 obj->type = CONFIG_NODE_OBJECT; |
296 if(current != obj) { |
333 if(current != obj) { |
297 current->type = CONFIG_NODE_OPEN_OBJECT; |
334 current->type = CONFIG_NODE_OPEN_OBJECT; |
298 } |
335 } |
299 } else if(!cx_strcmp(token.content, cx_str("}"))) { |
336 } else if(!cx_strcmp(token.content, cx_str("}"))) { |
|
337 // check if the parser allows an object hierarchy |
|
338 if(!parser->allow_hierarchy) { |
|
339 parser->error = CONFIG_PARSER_SYNTAX_ERROR; |
|
340 err = 1; |
|
341 break; |
|
342 } |
|
343 |
300 obj_closed = 1; // force newline before next directive |
344 obj_closed = 1; // force newline before next directive |
301 obj = NULL; |
345 obj = NULL; |
302 current->type = CONFIG_NODE_CLOSE_OBJECT; |
346 current->type = CONFIG_NODE_CLOSE_OBJECT; |
303 } else { |
347 } else { |
304 if(obj_closed) { |
348 if(obj_closed) { |