src/server/config/objconf.c

changeset 16
a9bbd82d2dce
child 17
d2a97bbeb57d
equal deleted inserted replaced
15:cff9c4101dd7 16:a9bbd82d2dce
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2011 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "objconf.h"
30
31 #include <string.h>
32
33 /* dev notes:
34 *
35 * to free ObjectConfig, free:
36 * line dlist
37 * mempool
38 * object
39 */
40
41 ObjectConfig *load_object_config(char *file) {
42 FILE *in = fopen(file, "r");
43 if(in == NULL) {
44 return NULL;
45 }
46
47 ObjectConfig *conf = malloc(sizeof(ObjectConfig));
48 conf->parser.parse = objconf_parse;
49 conf->file = file;
50
51 int r = cfg_parse_basic_file((ConfigParser*)conf, in);
52 if(r != 0) {
53 // TODO: free
54 return NULL;
55 }
56
57 return conf;
58 }
59
60
61
62 int objconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) {
63 ObjectConfig *conf = p;
64
65 begin->type = objconf_get_line_type(line);
66 switch(begin->type) {
67 case LINE_BEGIN_TAG: {
68 ConfigTag *tag = objconf_parse_begin_tag(line, conf->parser.mp);
69 if(tag == NULL) {
70 fprintf(stderr, "Parse error!\n");
71 exit(-1); // TODO: better error handling
72 }
73 tag->begin = begin;
74 tag->end = end;
75 tag->type_num = objconf_get_tag_type(tag->name);
76 //printf("line {%s}\n", sstrdub(ll).ptr);
77 if(objconf_on_begin_tag(conf, tag) != 0) {
78 fprintf(stderr, "1error!\n");
79 exit(-1);
80 }
81 break;
82 }
83 case LINE_END_TAG: {
84 sstr_t tag = objconf_get_end_tag_name(line);
85 if(objconf_on_end_tag(conf, tag) != 0) {
86 fprintf(stderr, "2error!\n");
87 exit(-1);
88 }
89
90 break;
91 }
92 case LINE_DIRECTIVE: {
93 ConfigDirective *dir = objconf_parse_directive(
94 line,
95 conf->parser.mp);
96 dir->begin = begin;
97 dir->end = end;
98 if(objconf_on_directive(conf, dir) != 0) {
99 fprintf(stderr, "3error!\n");
100 exit(-1);
101 }
102 }
103 }
104 return 0;
105 }
106
107 int objconf_on_begin_tag(ObjectConfig *conf, ConfigTag *tag) {
108 if(tag->type_num != TAG_OBJECT) {
109 ConfigParserLevel *l = conf->levels->data;
110 if(l->tag->type_num != TAG_OBJECT) {
111 tag->parent = l->tag;
112 }
113 }
114
115
116 switch(tag->type_num) {
117 case TAG_OBJECT: {
118 ConfigObject *obj = OBJ_NEW_N(conf->parser.mp, ConfigObject);
119 obj->begin = tag->begin;
120 obj->end = tag->end;
121
122 obj->name = cfg_param_get(tag->param, sstr("name"));
123 obj->ppath = cfg_param_get(tag->param, sstr("ppath"));
124
125 conf->obj = obj;
126 conf->objects = ucx_dlist_append(conf->objects, obj);
127
128 // create tree level object
129 ConfigParserLevel *lvl = OBJ_NEW(conf->parser.mp, ConfigParserLevel);
130 lvl->iftag = NULL;
131 lvl->levelnum = 1;
132 lvl->tag = tag;
133 conf->levels = ucx_list_prepend(conf->levels, lvl);
134
135 break;
136 }
137 case TAG_IF: {
138 // create tree level object
139 ConfigParserLevel *last_lvl = conf->levels->data;
140
141 ConfigParserLevel *lvl = OBJ_NEW(conf->parser.mp, ConfigParserLevel);
142 lvl->iftag = NULL;
143 lvl->levelnum = last_lvl->levelnum + 1;
144 lvl->tag = tag;
145 conf->levels = ucx_list_prepend(conf->levels, lvl);
146 last_lvl->iftag = tag;
147
148 break;
149 }
150 case TAG_ELSEIF: {
151 }
152 case TAG_ELSE: {
153 // create tree level object
154 ConfigParserLevel *last_lvl = conf->levels->data;
155 tag->iftag = last_lvl->iftag;
156
157 ConfigParserLevel *lvl = OBJ_NEW(
158 conf->parser.mp,
159 ConfigParserLevel);
160
161 lvl->iftag = last_lvl->tag;
162 lvl->levelnum = last_lvl->levelnum + 1;
163 lvl->tag = tag;
164 conf->levels = ucx_list_prepend(conf->levels, lvl);
165
166 break;
167 }
168 case TAG_CLIENT: {
169 // create tree level object
170
171 // TODO
172
173 break;
174 }
175 default: {
176 printf("unknown tag\n");
177 return 1;
178 }
179 }
180
181 return 0;
182 }
183
184 int objconf_on_end_tag(ObjectConfig *conf, sstr_t tagname) {
185 int type = objconf_get_tag_type(tagname);
186 if(type == -1) {
187 fprintf(stderr, "unknown tag\n");
188 return 1;
189 } else {
190 if(type == TAG_OBJECT) {
191 conf->obj = NULL;
192 }
193
194 // remove level
195 conf->levels = ucx_list_remove(conf->levels, conf->levels);
196 }
197
198 return 0;
199 }
200
201 int objconf_on_directive(ObjectConfig *conf, ConfigDirective *dir) {
202 ConfigParserLevel *lvl = conf->levels->data;
203
204 // check if we have a condition for the directive
205 // if the level tag is not an object tag, use it as condition
206 if(lvl->tag->type_num != TAG_OBJECT) {
207 dir->condition = lvl->tag;
208 }
209
210 // add directive to current object
211 conf->obj->directives[dir->type_num] = ucx_dlist_append(
212 conf->obj->directives[dir->type_num],
213 dir);
214
215 return 0;
216 }
217
218 /*
219 * checks if the line contains a begin/end tag or a directive
220 */
221 int objconf_get_line_type(sstr_t line) {
222 if(line.length < 3) {
223 // this line is to short to be correct
224 return LINE_ERROR;
225 }
226
227 if(line.ptr[0] == '<') {
228 // start or end tag
229 // TODO: check for space between '<' and '/'
230 if(line.ptr[1] == '/') {
231 return LINE_END_TAG;
232 } else {
233 return LINE_BEGIN_TAG;
234 }
235 } else {
236 return LINE_DIRECTIVE;
237 }
238 }
239
240 ConfigTag* objconf_parse_begin_tag(sstr_t line, UcxMempool *mp) {
241 if(line.length < 4) {
242 return NULL; // this line can't contain a valid tag
243 }
244
245 if(line.ptr[0] != '<' || line.ptr[line.length - 1] != '>') {
246 return NULL; // syntax error
247 }
248
249 sstr_t name;
250 name.ptr = line.ptr + 1;
251 int i;
252 for(i=1;i<line.length - 1;i++) {
253 if(line.ptr[i] < 33) { // char is space
254 name.length = i - 1;
255 break;
256 }
257 }
258 if(name.length < 1) {
259 return NULL; // syntax error
260 }
261
262 // create tag object
263 ConfigTag *tag = OBJ_NEW(mp, ConfigTag);
264 tag->name = sstrdub_mp(mp, name);
265 tag->param = NULL;
266
267 // parse parameters
268 sstr_t param_str;
269 param_str.ptr = line.ptr + i;
270 param_str.length = line.length - name.length - 2;
271 param_str = sstrtrim(param_str);
272 if(param_str.length <= 0) {
273 return tag; // no parameters
274 }
275
276 sstr_t pname;
277 sstr_t pvalue;
278 for(;;) {
279 param_str = cfg_param(param_str, &pname, &pvalue);
280 if(pname.length <= 0) {
281 break;
282 }
283
284 // create param object
285 ConfigParam *param = OBJ_NEW(mp, ConfigParam);
286 param->name = sstrdub_mp(mp, pname);
287 if(pvalue.length > 0) {
288 param->value = sstrdub_mp(mp, pvalue);
289 } else {
290 param->value.ptr = NULL;
291 param->value.length = 0;
292 }
293
294 // add param to list
295 tag->param = ucx_list_append(tag->param, param);
296 }
297
298 return tag;
299 }
300
301 /*
302 * returns the name of the ending tag
303 * on error, this functions returns a zero length string
304 */
305 sstr_t objconf_get_end_tag_name(sstr_t line) {
306 sstr_t ns;
307 ns.ptr = NULL;
308 ns.length = 0;
309
310 if(line.length < 4) {
311 // minimum of 4 chars: </a>
312 return ns;
313 }
314
315 sstr_t name;
316 name.ptr = line.ptr + 2;
317 name.length = line.length - 3;
318
319 // check for </ > frame
320 if(line.ptr[0] != '<'
321 || line.ptr[1] != '/'
322 || line.ptr[line.length - 1] != '>')
323 {
324 return ns;
325 }
326
327 return sstrtrim(name);
328 }
329
330 /*
331 * parses a line containing a directive and returns a ConfigDirective object
332 * or NULL if an error occurs
333 */
334 ConfigDirective* objconf_parse_directive(sstr_t line, UcxMempool *mp) {
335 if(line.length < 6) {
336 return NULL; // line too short
337 }
338
339 sstr_t name;
340
341 int i;
342 for(i=0;i<line.length;i++) {
343 if(line.ptr[i] < 33) {
344 break;
345 }
346 }
347 name.ptr = line.ptr;
348 name.length = i;
349
350 // create directive object
351 ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective);
352 directive->directive_type = sstrdub_mp(mp, name);
353 directive->type_num = cfg_get_directive_type_num(name);
354 directive->condition = NULL; // set later by main parsing function
355 directive->param = NULL;
356
357 sstr_t param_str;
358 param_str.ptr = name.ptr + i;
359 param_str.length = line.length - i;
360 param_str = sstrtrim(param_str);
361 sstr_t pname;
362 sstr_t pvalue;
363 for(;;) {
364 param_str = cfg_param(param_str, &pname, &pvalue);
365 if(pname.length <= 0) {
366 break;
367 }
368
369 // create param object
370 ConfigParam *param = OBJ_NEW(mp, ConfigParam);
371 param->name = sstrdub_mp(mp, pname);
372 if(pvalue.length > 0) {
373 param->value = sstrdub_mp(mp, pvalue);
374 } else {
375 param->value.ptr = NULL;
376 param->value.length = 0;
377 }
378
379 // add param to list
380 directive->param = ucx_list_append(directive->param, param);
381 }
382
383 return directive;
384 }
385
386 int objconf_get_tag_type(sstr_t tag) {
387 if(!sstrcmp(tag, sstr("Object"))) {
388 return TAG_OBJECT;
389 } else if(!sstrcmp(tag, sstr("If"))) {
390 return TAG_IF;
391 } else if(!sstrcmp(tag, sstr("ElseIf"))) {
392 return TAG_ELSEIF;
393 } else if(!sstrcmp(tag, sstr("Else"))) {
394 return TAG_ELSE;
395 } else if(!sstrcmp(tag, sstr("Client"))) {
396 return TAG_CLIENT;
397 }
398 return -1;
399 }

mercurial