Annotation of embedaddon/lighttpd/src/configparser.y, revision 1.1.1.1
1.1 misho 1: %token_prefix TK_
2: %extra_argument {config_t *ctx}
3: %name configparser
4:
5: %include {
6: #include "configfile.h"
7: #include "buffer.h"
8: #include "array.h"
9:
10: #include <assert.h>
11: #include <stdio.h>
12: #include <string.h>
13:
14: static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
15: if (isnew) {
16: dc->context_ndx = ctx->all_configs->used;
17: assert(dc->context_ndx > ctx->current->context_ndx);
18: array_insert_unique(ctx->all_configs, (data_unset *)dc);
19: dc->parent = ctx->current;
20: array_insert_unique(dc->parent->childs, (data_unset *)dc);
21: }
22: if (ctx->configs_stack->used > 0 && ctx->current->context_ndx == 0) {
23: fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
24: exit(-1);
25: }
26: array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
27: ctx->current = dc;
28: }
29:
30: static data_config *configparser_pop(config_t *ctx) {
31: data_config *old = ctx->current;
32: ctx->current = (data_config *) array_pop(ctx->configs_stack);
33: return old;
34: }
35:
36: /* return a copied variable */
37: static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
38: data_unset *du;
39: data_config *dc;
40:
41: #if 0
42: fprintf(stderr, "get var %s\n", key->ptr);
43: #endif
44: for (dc = ctx->current; dc; dc = dc->parent) {
45: #if 0
46: fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
47: array_print(dc->value, 0);
48: #endif
49: if (NULL != (du = array_get_element(dc->value, key->ptr))) {
50: return du->copy(du);
51: }
52: }
53: return NULL;
54: }
55:
56: /* op1 is to be eat/return by this function if success, op1->key is not cared
57: op2 is left untouch, unreferenced
58: */
59: data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
60: /* type mismatch */
61: if (op1->type != op2->type) {
62: if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
63: data_string *ds = (data_string *)op1;
64: buffer_append_long(ds->value, ((data_integer*)op2)->value);
65: return op1;
66: } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
67: data_string *ds = data_string_init();
68: buffer_append_long(ds->value, ((data_integer*)op1)->value);
69: buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
70: op1->free(op1);
71: return (data_unset *)ds;
72: } else {
73: fprintf(stderr, "data type mismatch, cannot merge\n");
74: return NULL;
75: }
76: }
77:
78: switch (op1->type) {
79: case TYPE_STRING:
80: buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
81: break;
82: case TYPE_INTEGER:
83: ((data_integer *)op1)->value += ((data_integer *)op2)->value;
84: break;
85: case TYPE_ARRAY: {
86: array *dst = ((data_array *)op1)->value;
87: array *src = ((data_array *)op2)->value;
88: data_unset *du;
89: size_t i;
90:
91: for (i = 0; i < src->used; i ++) {
92: du = (data_unset *)src->data[i];
93: if (du) {
94: array_insert_unique(dst, du->copy(du));
95: }
96: }
97: break;
98: default:
99: assert(0);
100: break;
101: }
102: }
103: return op1;
104: }
105:
106: }
107:
108: %parse_failure {
109: ctx->ok = 0;
110: }
111:
112: input ::= metalines.
113: metalines ::= metalines metaline.
114: metalines ::= .
115: metaline ::= varline.
116: metaline ::= global.
117: metaline ::= condlines(A) EOL. { A = NULL; }
118: metaline ::= include.
119: metaline ::= include_shell.
120: metaline ::= EOL.
121:
122: %type value {data_unset *}
123: %type expression {data_unset *}
124: %type aelement {data_unset *}
125: %type condline {data_config *}
126: %type condlines {data_config *}
127: %type global {data_config *}
128: %type aelements {array *}
129: %type array {array *}
130: %type key {buffer *}
131: %type stringop {buffer *}
132:
133: %type cond {config_cond_t }
134:
135: %destructor value { $$->free($$); }
136: %destructor expression { $$->free($$); }
137: %destructor aelement { $$->free($$); }
138: %destructor aelements { array_free($$); }
139: %destructor array { array_free($$); }
140: %destructor key { buffer_free($$); }
141: %destructor stringop { buffer_free($$); }
142:
143: %token_type {buffer *}
144: %token_destructor { buffer_free($$); }
145:
146: varline ::= key(A) ASSIGN expression(B). {
147: if (ctx->ok) {
148: buffer_copy_string_buffer(B->key, A);
149: if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
150: fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
151: ctx->current->context_ndx,
152: ctx->current->key->ptr, A->ptr);
153: ctx->ok = 0;
154: } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
155: array_insert_unique(ctx->current->value, B);
156: B = NULL;
157: } else {
158: fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
159: ctx->current->context_ndx,
160: ctx->current->key->ptr, B->key->ptr);
161: ctx->ok = 0;
162: B->free(B);
163: B = NULL;
164: }
165: }
166: buffer_free(A);
167: A = NULL;
168: }
169:
170: varline ::= key(A) APPEND expression(B). {
171: array *vars = ctx->current->value;
172: data_unset *du;
173:
174: if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
175: fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
176: ctx->current->context_ndx,
177: ctx->current->key->ptr, A->ptr);
178: ctx->ok = 0;
179: } else if (NULL != (du = array_get_element(vars, A->ptr))) {
180: /* exists in current block */
181: du = configparser_merge_data(du, B);
182: if (NULL == du) {
183: ctx->ok = 0;
184: }
185: else {
186: buffer_copy_string_buffer(du->key, A);
187: array_replace(vars, du);
188: }
189: B->free(B);
190: } else if (NULL != (du = configparser_get_variable(ctx, A))) {
191: du = configparser_merge_data(du, B);
192: if (NULL == du) {
193: ctx->ok = 0;
194: }
195: else {
196: buffer_copy_string_buffer(du->key, A);
197: array_insert_unique(ctx->current->value, du);
198: }
199: B->free(B);
200: } else {
201: buffer_copy_string_buffer(B->key, A);
202: array_insert_unique(ctx->current->value, B);
203: }
204: buffer_free(A);
205: A = NULL;
206: B = NULL;
207: }
208:
209: key(A) ::= LKEY(B). {
210: if (strchr(B->ptr, '.') == NULL) {
211: A = buffer_init_string("var.");
212: buffer_append_string_buffer(A, B);
213: buffer_free(B);
214: B = NULL;
215: } else {
216: A = B;
217: B = NULL;
218: }
219: }
220:
221: expression(A) ::= expression(B) PLUS value(C). {
222: A = configparser_merge_data(B, C);
223: if (NULL == A) {
224: ctx->ok = 0;
225: }
226: B = NULL;
227: C->free(C);
228: C = NULL;
229: }
230:
231: expression(A) ::= value(B). {
232: A = B;
233: B = NULL;
234: }
235:
236: value(A) ::= key(B). {
237: A = NULL;
238: if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
239: char *env;
240:
241: if (NULL != (env = getenv(B->ptr + 4))) {
242: data_string *ds;
243: ds = data_string_init();
244: buffer_append_string(ds->value, env);
245: A = (data_unset *)ds;
246: }
247: else {
248: fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
249: ctx->ok = 0;
250: }
251: } else if (NULL == (A = configparser_get_variable(ctx, B))) {
252: fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
253: ctx->ok = 0;
254: }
255: if (!A) {
256: /* make a dummy so it won't crash */
257: A = (data_unset *)data_string_init();
258: }
259: buffer_free(B);
260: B = NULL;
261: }
262:
263: value(A) ::= STRING(B). {
264: A = (data_unset *)data_string_init();
265: buffer_copy_string_buffer(((data_string *)(A))->value, B);
266: buffer_free(B);
267: B = NULL;
268: }
269:
270: value(A) ::= INTEGER(B). {
271: A = (data_unset *)data_integer_init();
272: ((data_integer *)(A))->value = strtol(B->ptr, NULL, 10);
273: buffer_free(B);
274: B = NULL;
275: }
276: value(A) ::= array(B). {
277: A = (data_unset *)data_array_init();
278: array_free(((data_array *)(A))->value);
279: ((data_array *)(A))->value = B;
280: B = NULL;
281: }
282: array(A) ::= LPARAN RPARAN. {
283: A = array_init();
284: }
285: array(A) ::= LPARAN aelements(B) RPARAN. {
286: A = B;
287: B = NULL;
288: }
289:
290: aelements(A) ::= aelements(C) COMMA aelement(B). {
291: if (buffer_is_empty(B->key) ||
292: NULL == array_get_element(C, B->key->ptr)) {
293: array_insert_unique(C, B);
294: B = NULL;
295: } else {
296: fprintf(stderr, "Duplicate array-key: %s\n",
297: B->key->ptr);
298: ctx->ok = 0;
299: B->free(B);
300: B = NULL;
301: }
302:
303: A = C;
304: C = NULL;
305: }
306:
307: aelements(A) ::= aelements(C) COMMA. {
308: A = C;
309: C = NULL;
310: }
311:
312: aelements(A) ::= aelement(B). {
313: A = array_init();
314: array_insert_unique(A, B);
315: B = NULL;
316: }
317:
318: aelement(A) ::= expression(B). {
319: A = B;
320: B = NULL;
321: }
322: aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
323: buffer_copy_string_buffer(C->key, B);
324: buffer_free(B);
325: B = NULL;
326:
327: A = C;
328: C = NULL;
329: }
330:
331: eols ::= EOL.
332: eols ::= .
333:
334: globalstart ::= GLOBAL. {
335: data_config *dc;
336: dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
337: assert(dc);
338: configparser_push(ctx, dc, 0);
339: }
340:
341: global(A) ::= globalstart LCURLY metalines RCURLY. {
342: data_config *cur;
343:
344: cur = ctx->current;
345: configparser_pop(ctx);
346:
347: assert(cur && ctx->current);
348:
349: A = cur;
350: }
351:
352: condlines(A) ::= condlines(B) eols ELSE condline(C). {
353: if (B->context_ndx >= C->context_ndx) {
354: fprintf(stderr, "unreachable else condition\n");
355: ctx->ok = 0;
356: }
357: C->prev = B;
358: B->next = C;
359: A = C;
360: B = NULL;
361: C = NULL;
362: }
363:
364: condlines(A) ::= condline(B). {
365: A = B;
366: B = NULL;
367: }
368:
369: condline(A) ::= context LCURLY metalines RCURLY. {
370: data_config *cur;
371:
372: cur = ctx->current;
373: configparser_pop(ctx);
374:
375: assert(cur && ctx->current);
376:
377: A = cur;
378: }
379:
380: context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
381: data_config *dc;
382: buffer *b, *rvalue, *op;
383:
384: if (ctx->ok && D->type != TYPE_STRING) {
385: fprintf(stderr, "rvalue must be string");
386: ctx->ok = 0;
387: }
388:
389: switch(E) {
390: case CONFIG_COND_NE:
391: op = buffer_init_string("!=");
392: break;
393: case CONFIG_COND_EQ:
394: op = buffer_init_string("==");
395: break;
396: case CONFIG_COND_NOMATCH:
397: op = buffer_init_string("!~");
398: break;
399: case CONFIG_COND_MATCH:
400: op = buffer_init_string("=~");
401: break;
402: default:
403: assert(0);
404: return;
405: }
406:
407: b = buffer_init();
408: buffer_copy_string_buffer(b, ctx->current->key);
409: buffer_append_string(b, "/");
410: buffer_append_string_buffer(b, B);
411: buffer_append_string_buffer(b, C);
412: buffer_append_string_buffer(b, op);
413: rvalue = ((data_string*)D)->value;
414: buffer_append_string_buffer(b, rvalue);
415:
416: if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
417: configparser_push(ctx, dc, 0);
418: } else {
419: struct {
420: comp_key_t comp;
421: char *comp_key;
422: size_t len;
423: } comps[] = {
424: { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
425: { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
426: { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
427: { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
428: { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
429: { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
430: { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
431: { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
432: { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
433: { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
434: { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
435: { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
436: { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
437: { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
438: { COMP_UNSET, NULL, 0 },
439: };
440: size_t i;
441:
442: dc = data_config_init();
443:
444: buffer_copy_string_buffer(dc->key, b);
445: buffer_copy_string_buffer(dc->op, op);
446: buffer_copy_string_buffer(dc->comp_key, B);
447: buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
448: buffer_append_string_buffer(dc->comp_key, C);
449: buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
450: dc->cond = E;
451:
452: for (i = 0; comps[i].comp_key; i ++) {
453: if (buffer_is_equal_string(
454: dc->comp_key, comps[i].comp_key, comps[i].len)) {
455: dc->comp = comps[i].comp;
456: break;
457: }
458: }
459: if (COMP_UNSET == dc->comp) {
460: fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
461: ctx->ok = 0;
462: }
463:
464: switch(E) {
465: case CONFIG_COND_NE:
466: case CONFIG_COND_EQ:
467: dc->string = buffer_init_buffer(rvalue);
468: break;
469: case CONFIG_COND_NOMATCH:
470: case CONFIG_COND_MATCH: {
471: #ifdef HAVE_PCRE_H
472: const char *errptr;
473: int erroff, captures;
474:
475: if (NULL == (dc->regex =
476: pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
477: dc->string = buffer_init_string(errptr);
478: dc->cond = CONFIG_COND_UNSET;
479:
480: fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
481: rvalue->ptr, errptr, erroff);
482:
483: ctx->ok = 0;
484: } else if (NULL == (dc->regex_study =
485: pcre_study(dc->regex, 0, &errptr)) &&
486: errptr != NULL) {
487: fprintf(stderr, "studying regex failed: %s -> %s\n",
488: rvalue->ptr, errptr);
489: ctx->ok = 0;
490: } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) {
491: fprintf(stderr, "getting capture count for regex failed: %s\n",
492: rvalue->ptr);
493: ctx->ok = 0;
494: } else if (captures > 9) {
495: fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
496: rvalue->ptr);
497: ctx->ok = 0;
498: } else {
499: dc->string = buffer_init_buffer(rvalue);
500: }
501: #else
502: fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
503: "(perhaps just a missing pcre-devel package ?) \n",
504: B->ptr, C->ptr);
505: ctx->ok = 0;
506: #endif
507: break;
508: }
509:
510: default:
511: fprintf(stderr, "unknown condition for $%s[%s]\n",
512: B->ptr, C->ptr);
513: ctx->ok = 0;
514: break;
515: }
516:
517: configparser_push(ctx, dc, 1);
518: }
519:
520: buffer_free(b);
521: buffer_free(op);
522: buffer_free(B);
523: B = NULL;
524: buffer_free(C);
525: C = NULL;
526: D->free(D);
527: D = NULL;
528: }
529: cond(A) ::= EQ. {
530: A = CONFIG_COND_EQ;
531: }
532: cond(A) ::= MATCH. {
533: A = CONFIG_COND_MATCH;
534: }
535: cond(A) ::= NE. {
536: A = CONFIG_COND_NE;
537: }
538: cond(A) ::= NOMATCH. {
539: A = CONFIG_COND_NOMATCH;
540: }
541:
542: stringop(A) ::= expression(B). {
543: A = NULL;
544: if (ctx->ok) {
545: if (B->type == TYPE_STRING) {
546: A = buffer_init_buffer(((data_string*)B)->value);
547: } else if (B->type == TYPE_INTEGER) {
548: A = buffer_init();
549: buffer_copy_long(A, ((data_integer *)B)->value);
550: } else {
551: fprintf(stderr, "operand must be string");
552: ctx->ok = 0;
553: }
554: }
555: B->free(B);
556: B = NULL;
557: }
558:
559: include ::= INCLUDE stringop(A). {
560: if (ctx->ok) {
561: if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
562: ctx->ok = 0;
563: }
564: buffer_free(A);
565: A = NULL;
566: }
567: }
568:
569: include_shell ::= INCLUDE_SHELL stringop(A). {
570: if (ctx->ok) {
571: if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
572: ctx->ok = 0;
573: }
574: buffer_free(A);
575: A = NULL;
576: }
577: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>