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