2 %extra_argument
{config_t
*ctx
}
7 #include "configfile.h"
17 static void configparser_push
(config_t
*ctx
, data_config
*dc
, int isnew
) {
19 dc
->context_ndx
= ctx
->all_configs
->used
;
20 force_assert
(dc
->context_ndx
> ctx
->current
->context_ndx
);
21 array_insert_unique
(ctx
->all_configs
, (data_unset
*)dc
);
22 dc
->parent
= ctx
->current
;
23 vector_config_weak_push
(&dc
->parent
->children
, dc
);
25 if
(ctx
->configs_stack.used
> 0 && ctx
->current
->context_ndx
== 0) {
26 fprintf
(stderr
, "Cannot use conditionals inside a global { ... } block\n");
29 vector_config_weak_push
(&ctx
->configs_stack
, ctx
->current
);
33 static data_config
*configparser_pop
(config_t
*ctx
) {
34 data_config
*old
= ctx
->current
;
35 ctx
->current
= vector_config_weak_pop
(&ctx
->configs_stack
);
39 /* return a copied variable */
40 static data_unset
*configparser_get_variable
(config_t
*ctx
, const buffer
*key
) {
45 fprintf
(stderr
, "get var %s\n", key
->ptr
);
47 for
(dc
= ctx
->current
; dc
; dc
= dc
->parent
) {
49 fprintf
(stderr
, "get var on block: %s\n", dc
->key
->ptr
);
50 array_print
(dc
->value
, 0);
52 if
(NULL
!= (du
= array_get_element
(dc
->value
, key
->ptr
))) {
59 /* op1 is to be eat/return by this function if success, op1->key is not cared
60 op2 is left untouch, unreferenced
62 data_unset
*configparser_merge_data
(data_unset
*op1
, const data_unset
*op2
) {
64 if
(op1
->type
!= op2
->type
) {
65 if
(op1
->type
== TYPE_STRING
&& op2
->type
== TYPE_INTEGER
) {
66 data_string
*ds
= (data_string
*)op1
;
67 buffer_append_int
(ds
->value
, ((data_integer
*)op2
)->value
);
69 } else if
(op1
->type
== TYPE_INTEGER
&& op2
->type
== TYPE_STRING
) {
70 data_string
*ds
= data_string_init
();
71 buffer_append_int
(ds
->value
, ((data_integer
*)op1
)->value
);
72 buffer_append_string_buffer
(ds
->value
, ((data_string
*)op2
)->value
);
74 return
(data_unset
*)ds
;
76 fprintf
(stderr
, "data type mismatch, cannot merge\n");
84 buffer_append_string_buffer
(((data_string
*)op1
)->value
, ((data_string
*)op2
)->value
);
87 ((data_integer
*)op1
)->value
+= ((data_integer
*)op2
)->value
;
90 array
*dst
= ((data_array
*)op1
)->value
;
91 array
*src
= ((data_array
*)op2
)->value
;
95 for
(i
= 0; i
< src
->used
; i
++) {
96 du
= (data_unset
*)src
->data
[i
];
98 if
(du
->is_index_key || buffer_is_empty
(du
->key
) ||
!array_get_element
(dst
, du
->key
->ptr
)) {
99 array_insert_unique
(dst
, du
->copy
(du
));
101 fprintf
(stderr
, "Duplicate array-key '%s'\n", du
->key
->ptr
);
123 metalines
::= metalines metaline.
125 metaline
::= varline.
127 metaline
::= condlines
(A
) EOL.
{ A
= NULL
; }
128 metaline
::= include.
129 metaline
::= include_shell.
132 %type value
{data_unset
*}
133 %type expression
{data_unset
*}
134 %type aelement
{data_unset
*}
135 %type condline
{data_config
*}
136 %type condlines
{data_config
*}
137 %type aelements
{array
*}
138 %type array
{array
*}
140 %type stringop
{buffer
*}
142 %type cond
{config_cond_t
}
144 %destructor value
{ if
($$
) $$
->free
($$
); }
145 %destructor expression
{ if
($$
) $$
->free
($$
); }
146 %destructor aelement
{ if
($$
) $$
->free
($$
); }
147 %destructor aelements
{ array_free
($$
); }
148 %destructor array
{ array_free
($$
); }
149 %destructor key
{ buffer_free
($$
); }
150 %destructor stringop
{ buffer_free
($$
); }
152 %token_type
{buffer
*}
153 %token_destructor
{ buffer_free
($$
); }
155 varline
::= key
(A
) ASSIGN expression
(B
).
{
157 buffer_copy_buffer
(B
->key
, A
);
158 if
(strncmp
(A
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
159 fprintf
(stderr
, "Setting env variable is not supported in conditional %d %s: %s\n",
160 ctx
->current
->context_ndx
,
161 ctx
->current
->key
->ptr
, A
->ptr
);
163 } else if
(NULL
== array_get_element
(ctx
->current
->value
, B
->key
->ptr
)) {
164 array_insert_unique
(ctx
->current
->value
, B
);
167 fprintf
(stderr
, "Duplicate config variable in conditional %d %s: %s\n",
168 ctx
->current
->context_ndx
,
169 ctx
->current
->key
->ptr
, B
->key
->ptr
);
179 varline
::= key
(A
) APPEND expression
(B
).
{
181 array
*vars
= ctx
->current
->value
;
184 if
(strncmp
(A
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
185 fprintf
(stderr
, "Appending env variable is not supported in conditional %d %s: %s\n",
186 ctx
->current
->context_ndx
,
187 ctx
->current
->key
->ptr
, A
->ptr
);
189 } else if
(NULL
!= (du
= array_extract_element
(vars
, A
->ptr
)) || NULL
!= (du
= configparser_get_variable
(ctx
, A
))) {
190 du
= configparser_merge_data
(du
, B
);
195 buffer_copy_buffer
(du
->key
, A
);
196 array_insert_unique
(ctx
->current
->value
, du
);
200 buffer_copy_buffer
(B
->key
, A
);
201 array_insert_unique
(ctx
->current
->value
, B
);
209 key
(A
) ::= LKEY
(B
).
{
210 if
(strchr
(B
->ptr
, '.') == NULL
) {
211 A
= buffer_init_string
("var.");
212 buffer_append_string_buffer
(A
, B
);
221 expression
(A
) ::= expression
(B
) PLUS value
(C
).
{
224 A
= configparser_merge_data
(B
, C
);
234 expression
(A
) ::= value
(B
).
{
239 value
(A
) ::= key
(B
).
{
242 if
(strncmp
(B
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
245 if
(NULL
!= (env
= getenv
(B
->ptr
+ 4))) {
247 ds
= data_string_init
();
248 buffer_append_string
(ds
->value
, env
);
249 A
= (data_unset
*)ds
;
252 fprintf
(stderr
, "Undefined env variable: %s\n", B
->ptr
+ 4);
255 } else if
(NULL
== (A
= configparser_get_variable
(ctx
, B
))) {
256 fprintf
(stderr
, "Undefined config variable: %s\n", B
->ptr
);
264 value
(A
) ::= STRING
(B
).
{
265 A
= (data_unset
*)data_string_init
();
266 buffer_copy_buffer
(((data_string
*)(A
))->value
, B
);
271 value
(A
) ::= INTEGER
(B
).
{
273 A
= (data_unset
*)data_integer_init
();
275 ((data_integer
*)(A
))->value
= strtol
(B
->ptr
, &endptr
, 10);
276 /* skip trailing whitespace */
277 if
(endptr
!= B
->ptr
) while
(isspace
(*endptr
)) endptr
++;
278 if
(0 != errno ||
*endptr
!= '\0') {
279 fprintf
(stderr
, "error parsing number: '%s'\n", B
->ptr
);
285 value
(A
) ::= array
(B
).
{
286 A
= (data_unset
*)data_array_init
();
287 array_free
(((data_array
*)(A
))->value
);
288 ((data_array
*)(A
))->value
= B
;
291 array
(A
) ::= LPARAN RPARAN.
{
294 array
(A
) ::= LPARAN aelements
(B
) RPARAN.
{
299 aelements
(A
) ::= aelements
(C
) COMMA aelement
(B
).
{
302 if
(buffer_is_empty
(B
->key
) ||
303 NULL
== array_get_element
(C
, B
->key
->ptr
)) {
304 array_insert_unique
(C
, B
);
307 fprintf
(stderr
, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
319 aelements
(A
) ::= aelements
(C
) COMMA.
{
324 aelements
(A
) ::= aelement
(B
).
{
328 array_insert_unique
(A
, B
);
333 aelement
(A
) ::= expression
(B
).
{
337 aelement
(A
) ::= stringop
(B
) ARRAY_ASSIGN expression
(C
).
{
340 buffer_copy_buffer
(C
->key
, B
);
352 globalstart
::= GLOBAL.
{
354 dc
= (data_config
*)array_get_element
(ctx
->srv
->config_context
, "global");
356 configparser_push
(ctx
, dc
, 0);
359 global
::= globalstart LCURLY metalines RCURLY.
{
360 force_assert
(ctx
->current
);
361 configparser_pop
(ctx
);
362 force_assert
(ctx
->current
);
365 condlines
(A
) ::= condlines
(B
) eols ELSE condline
(C
).
{
368 if
(B
->context_ndx
>= C
->context_ndx
) {
369 fprintf
(stderr
, "unreachable else condition\n");
380 condlines
(A
) ::= condline
(B
).
{
385 condline
(A
) ::= context LCURLY metalines RCURLY.
{
391 configparser_pop
(ctx
);
393 force_assert
(cur
&& ctx
->current
);
399 context
::= DOLLAR SRVVARNAME
(B
) LBRACKET stringop
(C
) RBRACKET cond
(E
) expression
(D
).
{
401 buffer
*b
, *rvalue
, *op
;
403 if
(ctx
->ok
&& D
->type
!= TYPE_STRING
) {
404 fprintf
(stderr
, "rvalue must be string");
411 op
= buffer_init_string
("!=");
414 op
= buffer_init_string
("==");
416 case CONFIG_COND_NOMATCH
:
417 op
= buffer_init_string
("!~");
419 case CONFIG_COND_MATCH
:
420 op
= buffer_init_string
("=~");
424 return
; /* unreachable */
428 buffer_copy_buffer
(b
, ctx
->current
->key
);
429 buffer_append_string
(b
, "/");
430 buffer_append_string_buffer
(b
, B
);
431 buffer_append_string_buffer
(b
, C
);
432 buffer_append_string_buffer
(b
, op
);
433 rvalue
= ((data_string
*)D
)->value
;
434 buffer_append_string_buffer
(b
, rvalue
);
436 if
(NULL
!= (dc
= (data_config
*)array_get_element
(ctx
->all_configs
, b
->ptr
))) {
437 configparser_push
(ctx
, dc
, 0);
439 static const struct {
444 { COMP_SERVER_SOCKET
, CONST_STR_LEN
("SERVER[\"socket\"]" ) },
445 { COMP_HTTP_URL
, CONST_STR_LEN
("HTTP[\"url\"]" ) },
446 { COMP_HTTP_HOST
, CONST_STR_LEN
("HTTP[\"host\"]" ) },
447 { COMP_HTTP_REFERER
, CONST_STR_LEN
("HTTP[\"referer\"]" ) },
448 { COMP_HTTP_USER_AGENT
, CONST_STR_LEN
("HTTP[\"useragent\"]" ) },
449 { COMP_HTTP_USER_AGENT
, CONST_STR_LEN
("HTTP[\"user-agent\"]" ) },
450 { COMP_HTTP_LANGUAGE
, CONST_STR_LEN
("HTTP[\"language\"]" ) },
451 { COMP_HTTP_COOKIE
, CONST_STR_LEN
("HTTP[\"cookie\"]" ) },
452 { COMP_HTTP_REMOTE_IP
, CONST_STR_LEN
("HTTP[\"remoteip\"]" ) },
453 { COMP_HTTP_REMOTE_IP
, CONST_STR_LEN
("HTTP[\"remote-ip\"]" ) },
454 { COMP_HTTP_QUERY_STRING
, CONST_STR_LEN
("HTTP[\"querystring\"]") },
455 { COMP_HTTP_QUERY_STRING
, CONST_STR_LEN
("HTTP[\"query-string\"]") },
456 { COMP_HTTP_REQUEST_METHOD
, CONST_STR_LEN
("HTTP[\"request-method\"]") },
457 { COMP_HTTP_SCHEME
, CONST_STR_LEN
("HTTP[\"scheme\"]" ) },
458 { COMP_UNSET
, NULL
, 0 },
462 dc
= data_config_init
();
464 buffer_copy_buffer
(dc
->key
, b
);
465 buffer_copy_buffer
(dc
->op
, op
);
466 buffer_copy_buffer
(dc
->comp_key
, B
);
467 buffer_append_string_len
(dc
->comp_key
, CONST_STR_LEN
("[\""));
468 buffer_append_string_buffer
(dc
->comp_key
, C
);
469 buffer_append_string_len
(dc
->comp_key
, CONST_STR_LEN
("\"]"));
472 for
(i
= 0; comps
[i
].comp_key
; i
++) {
473 if
(buffer_is_equal_string
(
474 dc
->comp_key
, comps
[i
].comp_key
, comps
[i
].len
)) {
475 dc
->comp
= comps
[i
].comp
;
479 if
(COMP_UNSET
== dc
->comp
) {
480 fprintf
(stderr
, "error comp_key %s", dc
->comp_key
->ptr
);
486 dc
->string = buffer_init_buffer
(rvalue
);
488 case CONFIG_COND_NOMATCH
:
489 case CONFIG_COND_MATCH
: {
492 int erroff
, captures
;
494 if
(NULL
== (dc
->regex
=
495 pcre_compile
(rvalue
->ptr
, 0, &errptr
, &erroff
, NULL
))) {
496 dc
->string = buffer_init_string
(errptr
);
497 dc
->cond
= CONFIG_COND_UNSET
;
499 fprintf
(stderr
, "parsing regex failed: %s -> %s at offset %d\n",
500 rvalue
->ptr
, errptr
, erroff
);
503 } else if
(NULL
== (dc
->regex_study
=
504 pcre_study
(dc
->regex
, 0, &errptr
)) &&
506 fprintf
(stderr
, "studying regex failed: %s -> %s\n",
507 rvalue
->ptr
, errptr
);
509 } else if
(0 != (pcre_fullinfo
(dc
->regex
, dc
->regex_study
, PCRE_INFO_CAPTURECOUNT
, &captures
))) {
510 fprintf
(stderr
, "getting capture count for regex failed: %s\n",
513 } else if
(captures
> 9) {
514 fprintf
(stderr
, "Too many captures in regex, use (?:...) instead of (...): %s\n",
518 dc
->string = buffer_init_buffer
(rvalue
);
521 fprintf
(stderr
, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
522 "(perhaps just a missing pcre-devel package ?) \n",
530 fprintf
(stderr
, "unknown condition for $%s[%s]\n",
537 configparser_push
(ctx
, dc
, 1);
539 dc
->free
((data_unset
*) dc
);
557 A
= CONFIG_COND_MATCH
;
562 cond
(A
) ::= NOMATCH.
{
563 A
= CONFIG_COND_NOMATCH
;
566 stringop
(A
) ::= expression
(B
).
{
569 if
(B
->type
== TYPE_STRING
) {
570 A
= buffer_init_buffer
(((data_string
*)B
)->value
);
571 } else if
(B
->type
== TYPE_INTEGER
) {
573 buffer_copy_int
(A
, ((data_integer
*)B
)->value
);
575 fprintf
(stderr
, "operand must be string");
583 include
::= INCLUDE stringop
(A
).
{
585 if
(0 != config_parse_file
(ctx
->srv
, ctx
, A
->ptr
)) {
593 include_shell
::= INCLUDE_SHELL stringop
(A
).
{
595 if
(0 != config_parse_cmd
(ctx
->srv
, ctx
, A
->ptr
)) {