src/server/config/serverconfig.c

changeset 415
d938228c382e
parent 367
1592224f6059
child 417
90805bb9fbd6
equal deleted inserted replaced
414:99a34860c105 415:d938228c382e
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29 29
30 #include "serverconfig.h" 30 #include "serverconfig.h"
31 #include "conf.h"
31 32
32 #include <stdio.h> 33 #include <stdio.h>
33 #include <stdlib.h> 34 #include <stdlib.h>
34 #include <string.h> 35 #include <string.h>
35 #include <ctype.h> 36 #include <ctype.h>
36 37
37 #include <ucx/buffer.h> 38 #include <cx/buffer.h>
38 #include <ucx/utils.h> 39 #include <cx/utils.h>
39 40
40 ServerConfig* serverconfig_load(const char *file) { 41 ServerConfig* serverconfig_load(const char *file) {
41 FILE *in = fopen(file, "r"); 42 FILE *in = fopen(file, "r");
42 if(in == NULL) { 43 if(in == NULL) {
43 return NULL; 44 return NULL;
44 } 45 }
45 46
46 UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); 47 CxBuffer buf;
47 if(!buf) { 48 cxBufferInit(&buf, NULL, 16384, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS);
48 fclose(in); 49
49 return NULL; 50 //ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write);
50 } 51 char readbuf[2048];
51 52 size_t r;
52 ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); 53 while((r = fread(readbuf, 1, 2048, in)) > 0) {
54 cxBufferWrite(readbuf, 1, r, &buf);
55 }
53 fclose(in); 56 fclose(in);
54 57
55 ServerConfig *scfg = serverconfig_parse(scstrn(buf->space, buf->size)); 58 ServerConfig *scfg = serverconfig_parse(cx_strn(buf.space, buf.size));
56 59
57 ucx_buffer_free(buf); 60 cxBufferDestroy(&buf);
58 return scfg; 61 return scfg;
59 } 62 }
60 63
61 64
62 static CFGToken get_next_token(scstr_t content, int *pos) { 65 static CFGToken get_next_token(cxstring content, int *pos) {
63 CFGToken token = { {NULL, 0}, CFG_NO_TOKEN }; 66 CFGToken token = { {NULL, 0}, CFG_NO_TOKEN };
64 CFGTokenType type = CFG_TOKEN; 67 CFGTokenType type = CFG_TOKEN;
65 68
66 int start = *pos; 69 int start = *pos;
67 70
128 if(token_begin < 0) { 131 if(token_begin < 0) {
129 return token; // error 132 return token; // error
130 } 133 }
131 134
132 token.type = type; 135 token.type = type;
133 token.content = scstrsubsl(content, token_begin, token_end - token_begin); 136 token.content = cx_strsubsl(content, token_begin, token_end - token_begin);
134 return token; 137 return token;
135 } 138 }
136 139
137 /* 140 /*
138 static void test_print_config(ConfigNode *parent) { 141 static void test_print_config(ConfigNode *parent) {
154 } 157 }
155 } 158 }
156 } 159 }
157 */ 160 */
158 161
159 static void config_arg_set_value(UcxAllocator *a, ConfigArg *arg, CFGToken token) { 162 static void config_arg_set_value(CxAllocator *a, ConfigParam *arg, CFGToken token) {
160 scstr_t nv = scstrchr(token.content, '='); 163 cxstring nv = cx_strchr(token.content, '=');
161 if(!nv.ptr) { 164 if(!nv.ptr) {
162 arg->value = sstrdup_a(a, token.content); 165 arg->value = cx_strdup_a(a, token.content);
163 } else { 166 } else {
164 intptr_t eq = (intptr_t)(nv.ptr - token.content.ptr); 167 intptr_t eq = (intptr_t)(nv.ptr - token.content.ptr);
165 scstr_t name = token.content; 168 cxstring name = token.content;
166 name.length = (size_t)eq; 169 name.length = (size_t)eq;
167 170
168 scstr_t value = nv; 171 cxstring value = nv;
169 value.ptr++; 172 value.ptr++;
170 value.length--; 173 value.length--;
171 if(value.length > 1 && value.ptr[0] == '"' && value.ptr[value.length-1] == '"') { 174 if(value.length > 1 && value.ptr[0] == '"' && value.ptr[value.length-1] == '"') {
172 value.ptr++; 175 value.ptr++;
173 value.length -= 2; // remove quote 176 value.length -= 2; // remove quote
174 } 177 }
175 178
176 arg->name = sstrdup_a(a, name); 179 arg->name = cx_strdup_a(a, name);
177 arg->value = sstrdup_a(a, value); 180 arg->value = cx_strdup_a(a, value);
178 } 181 }
179 } 182 }
180 183
181 ServerConfig* serverconfig_parse(scstr_t content) { 184 static int nodestack_prepend(CxAllocator *a, ConfigNodeStack **stack, ConfigNode *node) {
182 UcxMempool *mp = ucx_mempool_new(512); 185 ConfigNodeStack *elm = cxMalloc(a, sizeof(ConfigNodeStack));
186 if(!elm) return 1;
187 elm->node = node;
188 elm->next = NULL;
189 cx_linked_list_prepend((void**)stack, NULL, -1, offsetof(ConfigNodeStack, next), elm);
190 return 0;
191 }
192
193 ServerConfig* serverconfig_parse(cxstring content) {
194 CxMempool *mp = cxBasicMempoolCreate(512);
183 if(!mp) return NULL; 195 if(!mp) return NULL;
184 UcxAllocator *a = mp->allocator; 196 CxAllocator *a = (CxAllocator*)mp->allocator;
185 197
186 ServerConfig *config = ucx_mempool_malloc(mp, sizeof(ServerConfig)); 198 ServerConfig *config = cxMalloc(a, sizeof(ServerConfig));
187 if(!config) { 199 if(!config) {
188 ucx_mempool_destroy(mp); 200 cxMempoolDestroy(mp);
189 return NULL; 201 return NULL;
190 } 202 }
191 config->mp = mp; 203 config->mp = mp;
192 204
193 // PARSE: 205 // PARSE:
197 // '{' converts directive to object and following directives will 209 // '{' converts directive to object and following directives will
198 // be placed into the object 210 // be placed into the object
199 int pos = 0; // needed for tokenizer 211 int pos = 0; // needed for tokenizer
200 CFGToken token; 212 CFGToken token;
201 213
202 ConfigNode *root_obj = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); 214 ConfigNode *root_obj = cxCalloc(a, 1, sizeof(ConfigNode));
203 root_obj->type = CONFIG_NODE_OBJECT; 215 root_obj->type = CONFIG_NODE_OBJECT;
204 216
205 UcxList *node_stack = ucx_list_prepend(NULL, root_obj); 217 ConfigNodeStack *node_stack = cxMalloc(a, sizeof(ConfigNodeStack));
206 218 node_stack->node = root_obj;
207 ConfigNode *current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); 219 node_stack->next = NULL;
220
221 ConfigNode *current = cxCalloc(a, 1, sizeof(ConfigNode));
208 current->type = CONFIG_NODE_SPACE; 222 current->type = CONFIG_NODE_SPACE;
209 ConfigNode *obj = NULL; 223 ConfigNode *obj = NULL;
210 int obj_closed = 0; 224 int obj_closed = 0;
211 225
212 int text_start = 0; 226 int text_start = 0;
213 int err = 0; 227 int err = 0;
214 while((token = get_next_token(content, &pos)).type != CFG_NO_TOKEN) { 228 while((token = get_next_token(content, &pos)).type != CFG_NO_TOKEN) {
215 //printf("%s [%.*s]\n", token_type_str(token.type), (int)token.content.length, token.content.ptr); 229 //printf("%s [%.*s]\n", token_type_str(token.type), (int)token.content.length, token.content.ptr);
216 230
217 switch(token.type) { 231 switch(token.type) {
218 case CFG_NO_TOKEN: break; 232 case CFG_NO_TOKEN: break;
219 case CFG_TOKEN_COMMENT: { 233 case CFG_TOKEN_COMMENT: {
220 if(current->type == CONFIG_NODE_SPACE) { 234 if(current->type == CONFIG_NODE_SPACE) {
221 current->type = CONFIG_NODE_COMMENT; 235 current->type = CONFIG_NODE_COMMENT;
222 } 236 }
223 break; 237 break;
224 } 238 }
225 case CFG_TOKEN_SPACE: break; 239 case CFG_TOKEN_SPACE: break;
226 case CFG_TOKEN_NEWLINE: { 240 case CFG_TOKEN_NEWLINE: {
227 scstr_t line = scstrsubsl(content, text_start, pos - text_start); 241 cxstring line = cx_strsubsl(content, text_start, pos - text_start);
228 text_start = pos; 242 text_start = pos;
229 243
230 sstr_t line_cp = sstrdup_a(a, line); 244 cxmutstr line_cp = cx_strdup_a(a, line);
231 245
232 ConfigNode *parent = node_stack->data; 246 ConfigNode *parent = node_stack->node;
233 if(current->type == CONFIG_NODE_CLOSE_OBJECT) { 247 if(current->type == CONFIG_NODE_CLOSE_OBJECT) {
248 // this is a newline after a object is closed with '}'
249 // the line containing "}\n" should be added to the object
234 parent->text_end = line_cp; 250 parent->text_end = line_cp;
235 node_stack = ucx_list_remove_a(a, node_stack, node_stack); 251 // done with this object, remove it from the stack
252 ConfigNodeStack *remove_item = node_stack;
253 node_stack = node_stack->next;
254 cxFree(a, remove_item);
236 } else if(current->type == CONFIG_NODE_OPEN_OBJECT) { 255 } else if(current->type == CONFIG_NODE_OPEN_OBJECT) {
237 sstr_t new_textbegin = sstrcat_a(a, 2, obj->text_begin, line_cp); 256 // newline after a object is opened with '{'
238 alfree(a, obj->text_begin.ptr); 257 // append '{' to the object text
239 alfree(a, line_cp.ptr); 258 cxmutstr new_textbegin = cx_strcat_a(a, 2, obj->text_begin, line_cp);
259 cxFree(a, obj->text_begin.ptr);
260 cxFree(a, line_cp.ptr);
240 obj->text_begin = new_textbegin; 261 obj->text_begin = new_textbegin;
241 } else { 262 } else {
263 // normal line containing a directive, space or comment
264 // add it to parent node
242 current->text_begin = line_cp; 265 current->text_begin = line_cp;
243 ConfigNode *parent = node_stack->data; 266 CFG_NODE_ADD(&parent->children_begin, &parent->children_end, current);
244 parent->children = ucx_list_append_a(a, parent->children, current);
245 } 267 }
246 268
269 // 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
271 // a '{' character
247 if(obj && obj->type == CONFIG_NODE_OBJECT) { 272 if(obj && obj->type == CONFIG_NODE_OBJECT) {
248 node_stack = ucx_list_prepend_a(a, node_stack, obj); 273 // new object started, add it to the stack
274 nodestack_prepend(a, &node_stack, obj);
249 obj = NULL; 275 obj = NULL;
250 } 276 }
251 277
252 current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode)); 278 current = cxCalloc(a, 1, sizeof(ConfigNode));
253 current->type = CONFIG_NODE_SPACE; 279 current->type = CONFIG_NODE_SPACE;
254 280
255 obj_closed = 0; 281 obj_closed = 0;
256 break; 282 break;
257 } 283 }
258 case CFG_TOKEN: { 284 case CFG_TOKEN: {
259 if(!sstrcmp(token.content, S("{"))) { 285 // normal text token
286 // either a directive/obj name, parameter or { }
287
288 if(!cx_strcmp(token.content, cx_str("{"))) {
289 // obj is pointing to the previous node that started
290 // a directive
260 if(!obj) { 291 if(!obj) {
261 err = 1; 292 err = 1;
262 break; 293 break;
263 } 294 }
264 obj->type = CONFIG_NODE_OBJECT; 295 obj->type = CONFIG_NODE_OBJECT;
265 if(current != obj) { 296 if(current != obj) {
266 current->type = CONFIG_NODE_OPEN_OBJECT; 297 current->type = CONFIG_NODE_OPEN_OBJECT;
267 } 298 }
268 } else if(!sstrcmp(token.content, S("}"))) { 299 } else if(!cx_strcmp(token.content, cx_str("}"))) {
269 obj_closed = 1; // force newline before next directive 300 obj_closed = 1; // force newline before next directive
270 obj = NULL; 301 obj = NULL;
271 current->type = CONFIG_NODE_CLOSE_OBJECT; 302 current->type = CONFIG_NODE_CLOSE_OBJECT;
272 } else { 303 } else {
273 if(obj_closed) { 304 if(obj_closed) {
274 err = 1; 305 err = 1;
275 break; 306 break;
276 } 307 }
277 308
278 if(!current->name.ptr) { 309 if(!current->name.ptr) {
279 current->name = sstrdup_a(a, token.content); 310 // currently this could be a directive or object
311 current->name = cx_strdup_a(a, token.content);
280 current->type = CONFIG_NODE_DIRECTIVE; 312 current->type = CONFIG_NODE_DIRECTIVE;
281 obj = current; 313 obj = current; // potential object
282 } else { 314 } else {
283 ConfigArg *arg = ucx_mempool_calloc(mp, 1, sizeof(ConfigArg)); 315 // name already set, therefore this token must
316 // be a parameter
317 ConfigParam *arg = cxCalloc(a, 1, sizeof(ConfigParam));
284 config_arg_set_value(a, arg, token); 318 config_arg_set_value(a, arg, token);
285 current->args = ucx_list_append_a(a, current->args, arg); 319 CFG_PARAM_ADD(&current->args, NULL, arg);
286 } 320 }
287 } 321 }
288 break; 322 break;
289 } 323 }
290 } 324 }
294 } 328 }
295 } 329 }
296 330
297 if(pos < content.length || err) { 331 if(pos < content.length || err) {
298 // content not fully parsed because of an error 332 // content not fully parsed because of an error
299 ucx_mempool_destroy(mp); 333 cxMempoolDestroy(mp);
300 return NULL; 334 return NULL;
301 } 335 }
302 336
303 //test_print_config(&root_obj); 337 //test_print_config(&root_obj);
304 config->root = root_obj; 338 config->root = root_obj;
305 config->tab = sstrdup_a(a, SC("\t")); 339 config->tab = cx_strdup_a(a, cx_str("\t"));
306 340
307 return config; 341 return config;
308 } 342 }
309 343
310 void serverconfig_free(ServerConfig *cfg) { 344 void serverconfig_free(ServerConfig *cfg) {
311 ucx_mempool_destroy(cfg->mp); 345 cxMempoolDestroy(cfg->mp);
312 } 346 }
313 347
314 ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, scstr_t name) { 348 ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, cxstring name) {
315 UCX_FOREACH(elm, parent->children) { 349 for(ConfigNode *node=parent->children_begin;node;node=node->next) {
316 ConfigNode *node = elm->data; 350 if(node->type == type && !cx_strcasecmp(cx_strcast(node->name), name)) {
317 if(node->type == type && !sstrcasecmp(node->name, name)) {
318 return node; 351 return node;
319 } 352 }
320 } 353 }
321 return NULL; 354 return NULL;
322 } 355 }
323 356
324 UcxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, scstr_t name) { 357 CxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, cxstring name) {
325 UcxList *nodes = NULL; 358 CxList *nodes = cxPointerLinkedListCreate(cxDefaultAllocator, cx_cmp_ptr);
326 359
327 UCX_FOREACH(elm, parent->children) { 360 for(ConfigNode *node=parent->children_begin;node;node=node->next) {
328 ConfigNode *node = elm->data; 361 if(node->type == type && !cx_strcasecmp(cx_strcast(node->name), name)) {
329 if(node->type == type && !sstrcasecmp(node->name, name)) { 362 cxListAdd(nodes, node);
330 nodes = ucx_list_append(nodes, node);
331 } 363 }
332 } 364 }
333 365
334 return nodes; 366 return nodes;
335 } 367 }
336 368
337 scstr_t serverconfig_directive_value(ConfigNode *obj, scstr_t name) { 369 cxstring serverconfig_directive_value(ConfigNode *obj, cxstring name) {
338 ConfigNode *node = serverconfig_get_node(obj, CONFIG_NODE_DIRECTIVE, name); 370 ConfigNode *node = serverconfig_get_node(obj, CONFIG_NODE_DIRECTIVE, name);
339 if(node && ucx_list_size(node->args) == 1) { 371 if(node && CFG_NUM_PARAMS(node->args) == 1) {
340 ConfigArg *arg = node->args->data; 372 ConfigParam *arg = node->args;
341 return SCSTR(arg->value); 373 return (cxstring){ arg->value.ptr, arg->value.length };
342 } 374 }
343 return scstrn(NULL, 0); 375 return (cxstring){ NULL, 0 };
344 } 376 }
345 377
346 sstr_t serverconfig_arg_name_value(UcxAllocator *a, scstr_t str, scstr_t *name) { 378 cxmutstr serverconfig_arg_name_value(CxAllocator *a, cxstring str, cxstring *name) {
347 int valstart = 0; 379 int valstart = 0;
348 for(int i=0;i<str.length;i++) { 380 for(int i=0;i<str.length;i++) {
349 if(str.ptr[i] == '=') { 381 if(str.ptr[i] == '=') {
350 if(name) { 382 if(name) {
351 name->ptr = str.ptr; 383 name->ptr = str.ptr;
354 valstart = i + 1; 386 valstart = i + 1;
355 break; 387 break;
356 } 388 }
357 } 389 }
358 390
359 sstr_t ret; 391 cxmutstr ret;
360 return ret; 392 return ret;
361 } 393 }

mercurial