[mod_auth] require digest uri= match original URI
[lighttpd.git] / src / configparser.y
blob60b6a67c46144a8373069babdfb2372a9af39036
1 %token_prefix TK_
2 %extra_argument {config_t *ctx}
3 %name configparser
5 %include {
6 #include "first.h"
7 #include "base.h"
8 #include "configfile.h"
9 #include "buffer.h"
10 #include "array.h"
11 #include "request.h" /* http_request_host_normalize() */
13 #include <ctype.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
19 static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
20 if (isnew) {
21 dc->context_ndx = ctx->all_configs->used;
22 force_assert(dc->context_ndx > ctx->current->context_ndx);
23 array_insert_unique(ctx->all_configs, (data_unset *)dc);
24 dc->parent = ctx->current;
25 vector_config_weak_push(&dc->parent->children, dc);
27 if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) {
28 fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
29 exit(-1);
31 vector_config_weak_push(&ctx->configs_stack, ctx->current);
32 ctx->current = dc;
35 static data_config *configparser_pop(config_t *ctx) {
36 data_config *old = ctx->current;
37 ctx->current = vector_config_weak_pop(&ctx->configs_stack);
38 return old;
41 /* return a copied variable */
42 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
43 data_unset *du;
44 data_config *dc;
46 #if 0
47 fprintf(stderr, "get var %s\n", key->ptr);
48 #endif
49 for (dc = ctx->current; dc; dc = dc->parent) {
50 #if 0
51 fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
52 array_print(dc->value, 0);
53 #endif
54 if (NULL != (du = array_get_element_klen(dc->value, CONST_BUF_LEN(key)))) {
55 du = du->fn->copy(du);
56 buffer_clear(du->key);
57 return du;
60 return NULL;
63 /* op1 is to be eat/return by this function if success, op1->key is not cared
64 op2 is left untouch, unreferenced
66 static data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
67 /* type mismatch */
68 if (op1->type != op2->type) {
69 if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
70 data_string *ds = (data_string *)op1;
71 buffer_append_int(ds->value, ((data_integer*)op2)->value);
72 return op1;
73 } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
74 data_string *ds = data_string_init();
75 buffer_append_int(ds->value, ((data_integer*)op1)->value);
76 buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
77 op1->fn->free(op1);
78 return (data_unset *)ds;
79 } else {
80 fprintf(stderr, "data type mismatch, cannot merge\n");
81 op1->fn->free(op1);
82 return NULL;
86 switch (op1->type) {
87 case TYPE_STRING:
88 buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
89 break;
90 case TYPE_INTEGER:
91 ((data_integer *)op1)->value += ((data_integer *)op2)->value;
92 break;
93 case TYPE_ARRAY: {
94 array *dst = ((data_array *)op1)->value;
95 array *src = ((data_array *)op2)->value;
96 data_unset *du;
97 size_t i;
99 for (i = 0; i < src->used; i ++) {
100 du = (data_unset *)src->data[i];
101 if (du) {
102 if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element_klen(dst, CONST_BUF_LEN(du->key))) {
103 array_insert_unique(dst, du->fn->copy(du));
104 } else {
105 fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr);
106 op1->fn->free(op1);
107 return NULL;
111 break;
112 default:
113 force_assert(0);
114 break;
117 return op1;
120 static int configparser_remoteip_normalize_compat(buffer *rvalue) {
121 /* $HTTP["remoteip"] IPv6 accepted with or without '[]' for config compat
122 * http_request_host_normalize() expects IPv6 with '[]',
123 * and config processing at runtime expects COMP_HTTP_REMOTE_IP
124 * compared without '[]', so strip '[]' after normalization */
125 buffer *b = buffer_init();
126 int rc;
128 if (rvalue->ptr[0] != '[') {
129 buffer_append_string_len(b, CONST_STR_LEN("["));
130 buffer_append_string_buffer(b, rvalue);
131 buffer_append_string_len(b, CONST_STR_LEN("]"));
132 } else {
133 buffer_append_string_buffer(b, rvalue);
136 rc = http_request_host_normalize(b, 0);
138 if (0 == rc) {
139 /* remove surrounding '[]' */
140 size_t blen = buffer_string_length(b);
141 if (blen > 1) buffer_copy_string_len(rvalue, b->ptr+1, blen-2);
144 buffer_free(b);
145 return rc;
150 %parse_failure {
151 ctx->ok = 0;
154 input ::= metalines.
155 metalines ::= metalines metaline.
156 metalines ::= .
157 metaline ::= varline.
158 metaline ::= global.
159 metaline ::= condlines(A) EOL. { A = NULL; }
160 metaline ::= include.
161 metaline ::= include_shell.
162 metaline ::= EOL.
164 %type value {data_unset *}
165 %type expression {data_unset *}
166 %type aelement {data_unset *}
167 %type condline {data_config *}
168 %type cond_else {data_config *}
169 %type condlines {data_config *}
170 %type aelements {array *}
171 %type array {array *}
172 %type key {buffer *}
173 %type stringop {buffer *}
175 %type cond {config_cond_t }
177 %destructor value { if ($$) $$->fn->free($$); }
178 %destructor expression { if ($$) $$->fn->free($$); }
179 %destructor aelement { if ($$) $$->fn->free($$); }
180 %destructor aelements { array_free($$); }
181 %destructor array { array_free($$); }
182 %destructor key { buffer_free($$); }
183 %destructor stringop { buffer_free($$); }
185 %token_type {buffer *}
186 %token_destructor { buffer_free($$); }
188 varline ::= key(A) ASSIGN expression(B). {
189 if (ctx->ok) {
190 buffer_copy_buffer(B->key, A);
191 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
192 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
193 ctx->current->context_ndx,
194 ctx->current->key->ptr, A->ptr);
195 ctx->ok = 0;
196 } else if (NULL == array_get_element_klen(ctx->current->value, CONST_BUF_LEN(B->key))) {
197 array_insert_unique(ctx->current->value, B);
198 B = NULL;
199 } else {
200 fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
201 ctx->current->context_ndx,
202 ctx->current->key->ptr, B->key->ptr);
203 ctx->ok = 0;
206 buffer_free(A);
207 A = NULL;
208 if (B) B->fn->free(B);
209 B = NULL;
212 varline ::= key(A) FORCE_ASSIGN expression(B). {
213 if (ctx->ok) {
214 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
215 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
216 ctx->current->context_ndx,
217 ctx->current->key->ptr, A->ptr);
218 ctx->ok = 0;
219 } else {
220 buffer_copy_buffer(B->key, A);
221 array_replace(ctx->current->value, B);
222 B = NULL;
225 buffer_free(A);
226 A = NULL;
227 if (B) B->fn->free(B);
228 B = NULL;
231 varline ::= key(A) APPEND expression(B). {
232 if (ctx->ok) {
233 array *vars = ctx->current->value;
234 data_unset *du;
236 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
237 fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
238 ctx->current->context_ndx,
239 ctx->current->key->ptr, A->ptr);
240 ctx->ok = 0;
241 } else if (NULL != (du = array_extract_element_klen(vars, CONST_BUF_LEN(A))) || NULL != (du = configparser_get_variable(ctx, A))) {
242 du = configparser_merge_data(du, B);
243 if (NULL == du) {
244 ctx->ok = 0;
246 else {
247 buffer_copy_buffer(du->key, A);
248 array_insert_unique(ctx->current->value, du);
250 } else {
251 buffer_copy_buffer(B->key, A);
252 array_insert_unique(ctx->current->value, B);
253 B = NULL;
256 buffer_free(A);
257 A = NULL;
258 if (B) B->fn->free(B);
259 B = NULL;
262 key(A) ::= LKEY(B). {
263 if (strchr(B->ptr, '.') == NULL) {
264 A = buffer_init_string("var.");
265 buffer_append_string_buffer(A, B);
266 } else {
267 A = B;
268 B = NULL;
270 buffer_free(B);
271 B = NULL;
274 expression(A) ::= expression(B) PLUS value(C). {
275 A = NULL;
276 if (ctx->ok) {
277 A = configparser_merge_data(B, C);
278 B = NULL;
279 if (NULL == A) {
280 ctx->ok = 0;
283 if (B) B->fn->free(B);
284 B = NULL;
285 if (C) C->fn->free(C);
286 C = NULL;
289 expression(A) ::= value(B). {
290 A = B;
291 B = NULL;
294 value(A) ::= key(B). {
295 A = NULL;
296 if (ctx->ok) {
297 if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
298 char *env;
300 if (NULL != (env = getenv(B->ptr + 4))) {
301 data_string *ds;
302 ds = data_string_init();
303 buffer_append_string(ds->value, env);
304 A = (data_unset *)ds;
306 else {
307 fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
308 ctx->ok = 0;
310 } else if (NULL == (A = configparser_get_variable(ctx, B))) {
311 fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
312 ctx->ok = 0;
315 buffer_free(B);
316 B = NULL;
319 value(A) ::= STRING(B). {
320 buffer *b;
321 A = (data_unset *)data_string_init();
322 b = ((data_string *)(A))->value;
323 buffer_free(b);
324 ((data_string *)(A))->value = B;
325 B = NULL;
328 value(A) ::= INTEGER(B). {
329 char *endptr;
330 A = (data_unset *)data_integer_init();
331 errno = 0;
332 ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10);
333 /* skip trailing whitespace */
334 if (endptr != B->ptr) while (isspace(*endptr)) endptr++;
335 if (0 != errno || *endptr != '\0') {
336 fprintf(stderr, "error parsing number: '%s'\n", B->ptr);
337 ctx->ok = 0;
339 buffer_free(B);
340 B = NULL;
342 value(A) ::= array(B). {
343 A = (data_unset *)data_array_init();
344 array_free(((data_array *)(A))->value);
345 ((data_array *)(A))->value = B;
346 B = NULL;
348 array(A) ::= LPARAN RPARAN. {
349 A = array_init();
351 array(A) ::= LPARAN aelements(B) RPARAN. {
352 A = B;
353 B = NULL;
356 aelements(A) ::= aelements(C) COMMA aelement(B). {
357 A = NULL;
358 if (ctx->ok) {
359 if (buffer_is_empty(B->key) ||
360 NULL == array_get_element_klen(C, CONST_BUF_LEN(B->key))) {
361 array_insert_unique(C, B);
362 B = NULL;
363 } else {
364 fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
365 B->key->ptr);
366 ctx->ok = 0;
369 A = C;
370 C = NULL;
372 array_free(C);
373 C = NULL;
374 if (B) B->fn->free(B);
375 B = NULL;
378 aelements(A) ::= aelements(C) COMMA. {
379 A = C;
380 C = NULL;
383 aelements(A) ::= aelement(B). {
384 A = NULL;
385 if (ctx->ok) {
386 A = array_init();
387 array_insert_unique(A, B);
388 B = NULL;
390 if (B) B->fn->free(B);
391 B = NULL;
394 aelement(A) ::= expression(B). {
395 A = B;
396 B = NULL;
398 aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
399 A = NULL;
400 if (ctx->ok) {
401 buffer_copy_buffer(C->key, B);
403 A = C;
404 C = NULL;
406 if (C) C->fn->free(C);
407 C = NULL;
408 buffer_free(B);
409 B = NULL;
412 eols ::= EOL.
413 eols ::= .
415 globalstart ::= GLOBAL. {
416 data_config *dc;
417 dc = (data_config *)array_get_element_klen(ctx->srv->config_context, CONST_STR_LEN("global"));
418 force_assert(dc);
419 configparser_push(ctx, dc, 0);
422 global ::= globalstart LCURLY metalines RCURLY. {
423 force_assert(ctx->current);
424 configparser_pop(ctx);
425 force_assert(ctx->current);
428 condlines(A) ::= condlines(B) eols ELSE condline(C). {
429 A = NULL;
430 if (ctx->ok) {
431 if (B->context_ndx >= C->context_ndx) {
432 fprintf(stderr, "unreachable else condition\n");
433 ctx->ok = 0;
435 if (B->cond == CONFIG_COND_ELSE) {
436 fprintf(stderr, "unreachable condition following else catch-all\n");
437 ctx->ok = 0;
439 C->prev = B;
440 B->next = C;
441 A = C;
443 B = NULL;
444 C = NULL;
447 condlines(A) ::= condlines(B) eols ELSE cond_else(C). {
448 A = NULL;
449 if (ctx->ok) {
450 if (B->context_ndx >= C->context_ndx) {
451 fprintf(stderr, "unreachable else condition\n");
452 ctx->ok = 0;
454 if (B->cond == CONFIG_COND_ELSE) {
455 fprintf(stderr, "unreachable condition following else catch-all\n");
456 ctx->ok = 0;
459 if (ctx->ok) {
460 size_t pos;
461 data_config *dc;
462 dc = (data_config *)array_extract_element_klen(ctx->all_configs, CONST_BUF_LEN(C->key));
463 force_assert(C == dc);
464 buffer_copy_buffer(C->key, B->key);
465 C->comp = B->comp;
466 /*buffer_copy_buffer(C->comp_key, B->comp_key);*/
467 /*C->string = buffer_init_buffer(B->string);*/
468 pos = buffer_string_length(C->key)-buffer_string_length(B->string)-2;
469 switch(B->cond) {
470 case CONFIG_COND_NE:
471 C->key->ptr[pos] = '='; /* opposite cond */
472 /*buffer_copy_string_len(C->op, CONST_STR_LEN("=="));*/
473 break;
474 case CONFIG_COND_EQ:
475 C->key->ptr[pos] = '!'; /* opposite cond */
476 /*buffer_copy_string_len(C->op, CONST_STR_LEN("!="));*/
477 break;
478 case CONFIG_COND_NOMATCH:
479 C->key->ptr[pos] = '='; /* opposite cond */
480 /*buffer_copy_string_len(C->op, CONST_STR_LEN("=~"));*/
481 break;
482 case CONFIG_COND_MATCH:
483 C->key->ptr[pos] = '!'; /* opposite cond */
484 /*buffer_copy_string_len(C->op, CONST_STR_LEN("!~"));*/
485 break;
486 default: /* should not happen; CONFIG_COND_ELSE checked further above */
487 force_assert(0);
490 if (NULL == (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(C->key)))) {
491 /* re-insert into ctx->all_configs with new C->key */
492 array_insert_unique(ctx->all_configs, (data_unset *)C);
493 C->prev = B;
494 B->next = C;
495 } else {
496 fprintf(stderr, "unreachable else condition\n");
497 ctx->ok = 0;
498 C->fn->free((data_unset *)C);
499 C = dc;
502 A = C;
504 B = NULL;
505 C = NULL;
508 condlines(A) ::= condline(B). {
509 A = B;
510 B = NULL;
513 condline(A) ::= context LCURLY metalines RCURLY. {
514 A = NULL;
515 if (ctx->ok) {
516 data_config *cur;
518 cur = ctx->current;
519 configparser_pop(ctx);
521 force_assert(cur && ctx->current);
523 A = cur;
527 cond_else(A) ::= context_else LCURLY metalines RCURLY. {
528 A = NULL;
529 if (ctx->ok) {
530 data_config *cur;
532 cur = ctx->current;
533 configparser_pop(ctx);
535 force_assert(cur && ctx->current);
537 A = cur;
541 context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
542 data_config *dc;
543 buffer *b = NULL, *rvalue, *op = NULL;
545 if (ctx->ok && D->type != TYPE_STRING) {
546 fprintf(stderr, "rvalue must be string");
547 ctx->ok = 0;
550 if (ctx->ok) {
551 switch(E) {
552 case CONFIG_COND_NE:
553 op = buffer_init_string("!=");
554 break;
555 case CONFIG_COND_EQ:
556 op = buffer_init_string("==");
557 break;
558 case CONFIG_COND_NOMATCH:
559 op = buffer_init_string("!~");
560 break;
561 case CONFIG_COND_MATCH:
562 op = buffer_init_string("=~");
563 break;
564 default:
565 force_assert(0);
566 return; /* unreachable */
569 b = buffer_init();
570 buffer_copy_buffer(b, ctx->current->key);
571 buffer_append_string_len(b, CONST_STR_LEN("/"));
572 buffer_append_string_buffer(b, B);
573 buffer_append_string_buffer(b, C);
574 buffer_append_string_buffer(b, op);
575 rvalue = ((data_string*)D)->value;
576 buffer_append_string_buffer(b, rvalue);
578 if (NULL != (dc = (data_config *)array_get_element_klen(ctx->all_configs, CONST_BUF_LEN(b)))) {
579 configparser_push(ctx, dc, 0);
580 } else {
581 static const struct {
582 comp_key_t comp;
583 char *comp_key;
584 size_t len;
585 } comps[] = {
586 { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
587 { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
588 { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
589 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"referer\"]" ) },
590 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
591 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
592 { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
593 { COMP_HTTP_REQUEST_HEADER,CONST_STR_LEN("HTTP[\"cookie\"]" ) },
594 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
595 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
596 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
597 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
598 { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
599 { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
600 { COMP_UNSET, NULL, 0 },
602 size_t i;
604 dc = data_config_init();
606 buffer_copy_buffer(dc->key, b);
607 buffer_copy_buffer(dc->op, op);
608 buffer_copy_buffer(dc->comp_tag, C);
609 buffer_copy_buffer(dc->comp_key, B);
610 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
611 buffer_append_string_buffer(dc->comp_key, C);
612 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
613 dc->cond = E;
615 for (i = 0; comps[i].comp_key; i ++) {
616 if (buffer_is_equal_string(
617 dc->comp_key, comps[i].comp_key, comps[i].len)) {
618 dc->comp = comps[i].comp;
619 break;
622 if (COMP_UNSET == dc->comp) {
623 if (buffer_is_equal_string(B, CONST_STR_LEN("REQUEST_HEADER"))) {
624 dc->comp = COMP_HTTP_REQUEST_HEADER;
626 else {
627 fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
628 ctx->ok = 0;
631 else if (COMP_HTTP_LANGUAGE == dc->comp) {
632 dc->comp = COMP_HTTP_REQUEST_HEADER;
633 buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("Accept-Language"));
635 else if (COMP_HTTP_USER_AGENT == dc->comp) {
636 dc->comp = COMP_HTTP_REQUEST_HEADER;
637 buffer_copy_string_len(dc->comp_tag, CONST_STR_LEN("User-Agent"));
639 else if (COMP_HTTP_REMOTE_IP == dc->comp
640 && (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE)) {
641 char * const slash = strchr(rvalue->ptr, '/'); /* CIDR mask */
642 char * const colon = strchr(rvalue->ptr, ':'); /* IPv6 */
643 if (NULL != slash && slash == rvalue->ptr){/*(skip AF_UNIX /path/file)*/
645 else if (NULL != slash) {
646 char *nptr;
647 const unsigned long nm_bits = strtoul(slash + 1, &nptr, 10);
648 if (*nptr || 0 == nm_bits || nm_bits > (NULL != colon ? 128 : 32)) {
649 /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
650 fprintf(stderr, "invalid or missing netmask: %s\n", rvalue->ptr);
651 ctx->ok = 0;
653 else {
654 int rc;
655 buffer_string_set_length(rvalue, (size_t)(slash - rvalue->ptr)); /*(truncate)*/
656 rc = (NULL == colon)
657 ? http_request_host_normalize(rvalue, 0)
658 : configparser_remoteip_normalize_compat(rvalue);
659 buffer_append_string_len(rvalue, CONST_STR_LEN("/"));
660 buffer_append_int(rvalue, (int)nm_bits);
661 if (0 != rc) {
662 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
663 ctx->ok = 0;
667 else {
668 int rc = (NULL == colon)
669 ? http_request_host_normalize(rvalue, 0)
670 : configparser_remoteip_normalize_compat(rvalue);
671 if (0 != rc) {
672 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
673 ctx->ok = 0;
677 else if (COMP_SERVER_SOCKET == dc->comp) {
678 /*(redundant with parsing in network.c; not actually required here)*/
679 if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
680 && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')) {
681 if (http_request_host_normalize(rvalue, 0)) {
682 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
683 ctx->ok = 0;
687 else if (COMP_HTTP_HOST == dc->comp) {
688 if (dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) {
689 if (http_request_host_normalize(rvalue, 0)) {
690 fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
691 ctx->ok = 0;
696 dc->string = buffer_init_buffer(rvalue);
698 if (ctx->ok) switch(E) {
699 case CONFIG_COND_NE:
700 case CONFIG_COND_EQ:
701 break;
702 case CONFIG_COND_NOMATCH:
703 case CONFIG_COND_MATCH: {
704 if (!data_config_pcre_compile(dc)) {
705 ctx->ok = 0;
707 break;
710 default:
711 fprintf(stderr, "unknown condition for $%s[%s]\n",
712 B->ptr, C->ptr);
713 ctx->ok = 0;
714 break;
717 if (ctx->ok) {
718 configparser_push(ctx, dc, 1);
719 } else {
720 dc->fn->free((data_unset*) dc);
725 buffer_free(b);
726 buffer_free(op);
727 buffer_free(B);
728 B = NULL;
729 buffer_free(C);
730 C = NULL;
731 if (D) D->fn->free(D);
732 D = NULL;
735 context_else ::= . {
736 if (ctx->ok) {
737 data_config *dc = data_config_init();
738 buffer_copy_buffer(dc->key, ctx->current->key);
739 buffer_append_string_len(dc->key, CONST_STR_LEN("/"));
740 buffer_append_string_len(dc->key, CONST_STR_LEN("else_tmp_token"));
741 dc->cond = CONFIG_COND_ELSE;
742 configparser_push(ctx, dc, 1);
746 cond(A) ::= EQ. {
747 A = CONFIG_COND_EQ;
749 cond(A) ::= MATCH. {
750 A = CONFIG_COND_MATCH;
752 cond(A) ::= NE. {
753 A = CONFIG_COND_NE;
755 cond(A) ::= NOMATCH. {
756 A = CONFIG_COND_NOMATCH;
759 stringop(A) ::= expression(B). {
760 A = NULL;
761 if (ctx->ok) {
762 if (B->type == TYPE_STRING) {
763 A = ((data_string*)B)->value;
764 ((data_string*)B)->value = NULL;
765 } else if (B->type == TYPE_INTEGER) {
766 A = buffer_init();
767 buffer_copy_int(A, ((data_integer *)B)->value);
768 } else {
769 fprintf(stderr, "operand must be string");
770 ctx->ok = 0;
773 if (B) B->fn->free(B);
774 B = NULL;
777 include ::= INCLUDE stringop(A). {
778 if (ctx->ok) {
779 if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
780 ctx->ok = 0;
783 buffer_free(A);
784 A = NULL;
787 include_shell ::= INCLUDE_SHELL stringop(A). {
788 if (ctx->ok) {
789 if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
790 ctx->ok = 0;
793 buffer_free(A);
794 A = NULL;