xref: /lighttpd1.4/src/configparser.y (revision 782fa347)
1bcdc6a3bSJan Kneschke %token_prefix TK_
2bcdc6a3bSJan Kneschke %extra_argument {config_t *ctx}
3bcdc6a3bSJan Kneschke %name configparser
4bcdc6a3bSJan Kneschke 
5bcdc6a3bSJan Kneschke %include {
6*782fa347SGlenn Strauss #define NDEBUG
78abd06a7SGlenn Strauss #include "first.h"
804d76e7aSGlenn Strauss #include "base.h"
9bcdc6a3bSJan Kneschke #include "configfile.h"
10bcdc6a3bSJan Kneschke #include "buffer.h"
11bcdc6a3bSJan Kneschke #include "array.h"
122e0676fdSGlenn Strauss #include "http_header.h" /* http_header_hkey_get() */
13e8dd8fdbSGlenn Strauss #include "request.h" /* http_request_host_normalize() */
148073d5feSJan Kneschke 
15f5453290SGlenn Strauss #include <ctype.h>
16f5453290SGlenn Strauss #include <errno.h>
17e8c1efd5SGlenn Strauss #include <stdlib.h>
1822e8b456SStefan Bühler #include <stdio.h>
1922e8b456SStefan Bühler #include <string.h>
2022e8b456SStefan Bühler 
21*782fa347SGlenn Strauss /*(missing declarations in generated configparser.c)*/
22*782fa347SGlenn Strauss static void configparserInit(void *yypRawParser);
23*782fa347SGlenn Strauss static void configparserFinalize(void *p);
24*782fa347SGlenn Strauss /*(missing declarations in generated configparser.c; defined but not used)*/
25*782fa347SGlenn Strauss static inline int configparserFallback(int iToken)
26*782fa347SGlenn Strauss   __attribute_unused__;
27*782fa347SGlenn Strauss #ifndef NDEBUG
28*782fa347SGlenn Strauss static inline void configparserTrace(FILE *TraceFILE, char *zTracePrompt)
29*782fa347SGlenn Strauss   __attribute_unused__;
30*782fa347SGlenn Strauss #endif
31*782fa347SGlenn Strauss 
32cf3e3012SGlenn Strauss __attribute_pure__
configparser_get_data_config(const array * a,const char * k,const size_t klen)3383535bbeSGlenn Strauss static data_config * configparser_get_data_config(const array *a, const char *k, const size_t klen) {
3483535bbeSGlenn Strauss   return (data_config *)array_get_data_unset(a, k, klen);
3583535bbeSGlenn Strauss }
3683535bbeSGlenn Strauss 
378626edfaSGlenn Strauss __attribute_noinline__
configparser_push_data_config_list(data_config_list * v,data_config * dc)388626edfaSGlenn Strauss static void configparser_push_data_config_list(data_config_list *v, data_config *dc) {
398626edfaSGlenn Strauss     if (v->size == v->used) {
408626edfaSGlenn Strauss         ck_realloc_u32((void **)&v->data, v->size, 4, sizeof(*v->data));
418626edfaSGlenn Strauss         v->size += 4;
428626edfaSGlenn Strauss     }
438626edfaSGlenn Strauss     v->data[v->used++] = dc;
448626edfaSGlenn Strauss }
458626edfaSGlenn Strauss 
configparser_push(config_t * ctx,data_config * dc,int isnew)468073d5feSJan Kneschke static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
478073d5feSJan Kneschke   if (isnew) {
488073d5feSJan Kneschke     dc->context_ndx = ctx->all_configs->used;
4907dd0bd0SStefan Bühler     force_assert(dc->context_ndx > ctx->current->context_ndx);
508073d5feSJan Kneschke     array_insert_unique(ctx->all_configs, (data_unset *)dc);
516e78c2c8SJan Kneschke     dc->parent = ctx->current;
528626edfaSGlenn Strauss     configparser_push_data_config_list(&dc->parent->children, dc);
538073d5feSJan Kneschke   }
545c68caa6SStefan Bühler   if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) {
55e294fffbSStefan Bühler     fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
56e294fffbSStefan Bühler     exit(-1);
57e294fffbSStefan Bühler   }
588626edfaSGlenn Strauss   configparser_push_data_config_list(&ctx->configs_stack, ctx->current);
598073d5feSJan Kneschke   ctx->current = dc;
608073d5feSJan Kneschke }
618073d5feSJan Kneschke 
configparser_pop(config_t * ctx)628073d5feSJan Kneschke static data_config *configparser_pop(config_t *ctx) {
638073d5feSJan Kneschke   data_config *old = ctx->current;
648626edfaSGlenn Strauss   force_assert(ctx->configs_stack.used);
658626edfaSGlenn Strauss   ctx->current = ctx->configs_stack.data[--ctx->configs_stack.used];
66b3e80a13SGlenn Strauss   force_assert(old && ctx->current);
678073d5feSJan Kneschke   return old;
688073d5feSJan Kneschke }
698073d5feSJan Kneschke 
70360aba36SJan Kneschke /* return a copied variable */
configparser_get_variable(config_t * ctx,const buffer * key)71360aba36SJan Kneschke static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
7283535bbeSGlenn Strauss   const data_unset *du;
736e78c2c8SJan Kneschke   data_config *dc;
746e78c2c8SJan Kneschke 
756e78c2c8SJan Kneschke #if 0
766e78c2c8SJan Kneschke   fprintf(stderr, "get var %s\n", key->ptr);
776e78c2c8SJan Kneschke #endif
78360aba36SJan Kneschke   for (dc = ctx->current; dc; dc = dc->parent) {
796e78c2c8SJan Kneschke #if 0
80ad9b7e00SGlenn Strauss     fprintf(stderr, "get var on block: %s\n", dc->key.ptr);
816b85d74cSJan Kneschke     array_print(dc->value, 0);
826e78c2c8SJan Kneschke #endif
83af3df29aSGlenn Strauss     if (NULL != (du = array_get_element_klen(dc->value, BUF_PTR_LEN(key)))) {
8483535bbeSGlenn Strauss       data_unset *du_copy = du->fn->copy(du);
85ad9b7e00SGlenn Strauss       buffer_clear(&du_copy->key);
8683535bbeSGlenn Strauss       return du_copy;
876e78c2c8SJan Kneschke     }
886e78c2c8SJan Kneschke   }
89360aba36SJan Kneschke   return NULL;
906e78c2c8SJan Kneschke }
916e78c2c8SJan Kneschke 
92c97dc808SmOo /* op1 is to be eat/return by this function if success, op1->key is not cared
936e78c2c8SJan Kneschke    op2 is left untouch, unreferenced
946e78c2c8SJan Kneschke  */
configparser_merge_data(data_unset * op1,const data_unset * op2)95fb9b8ad8SGlenn Strauss static data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
966e78c2c8SJan Kneschke   /* type mismatch */
976e78c2c8SJan Kneschke   if (op1->type != op2->type) {
986e78c2c8SJan Kneschke     if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
996e78c2c8SJan Kneschke       data_string *ds = (data_string *)op1;
100601c572cSGlenn Strauss       buffer_append_int(&ds->value, ((data_integer*)op2)->value);
1016e78c2c8SJan Kneschke       return op1;
1026517c89dSJan Kneschke     } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
1034f8f83eaSGlenn Strauss       data_string *ds = array_data_string_init();
104601c572cSGlenn Strauss       buffer_append_int(&ds->value, ((data_integer*)op1)->value);
105601c572cSGlenn Strauss       buffer_append_string_buffer(&ds->value, &((data_string*)op2)->value);
1068c7f1dfbSGlenn Strauss       op1->fn->free(op1);
1076e78c2c8SJan Kneschke       return (data_unset *)ds;
1086517c89dSJan Kneschke     } else {
1094df22f2aSStefan Bühler       fprintf(stderr, "data type mismatch, cannot merge\n");
1108c7f1dfbSGlenn Strauss       op1->fn->free(op1);
1116e78c2c8SJan Kneschke       return NULL;
1126e78c2c8SJan Kneschke     }
1136e78c2c8SJan Kneschke   }
1146e78c2c8SJan Kneschke 
1156e78c2c8SJan Kneschke   switch (op1->type) {
1166e78c2c8SJan Kneschke     case TYPE_STRING:
117601c572cSGlenn Strauss       buffer_append_string_buffer(&((data_string *)op1)->value, &((data_string *)op2)->value);
1186e78c2c8SJan Kneschke       break;
1196e78c2c8SJan Kneschke     case TYPE_INTEGER:
1206e78c2c8SJan Kneschke       ((data_integer *)op1)->value += ((data_integer *)op2)->value;
1216e78c2c8SJan Kneschke       break;
1226e78c2c8SJan Kneschke     case TYPE_ARRAY: {
123c2238256SGlenn Strauss       array *dst = &((data_array *)op1)->value;
124c2238256SGlenn Strauss       array *src = &((data_array *)op2)->value;
1257ff6adc4SGlenn Strauss       const data_unset *du, *ddu;
1266e78c2c8SJan Kneschke       size_t i;
1276e78c2c8SJan Kneschke 
1286e78c2c8SJan Kneschke       for (i = 0; i < src->used; i ++) {
1296e78c2c8SJan Kneschke         du = (data_unset *)src->data[i];
1306e78c2c8SJan Kneschke         if (du) {
131af3df29aSGlenn Strauss           if (buffer_is_unset(&du->key)
132af3df29aSGlenn Strauss               || !(ddu = array_get_element_klen(dst, BUF_PTR_LEN(&du->key)))){
1338c7f1dfbSGlenn Strauss             array_insert_unique(dst, du->fn->copy(du));
13443da5818SGlenn Strauss           } else {
135ad9b7e00SGlenn Strauss             fprintf(stderr, "Duplicate array-key '%s'\n", du->key.ptr);
1367ff6adc4SGlenn Strauss             if (ddu->type == du->type) {
1377ff6adc4SGlenn Strauss               /*(ignore if new key/value pair matches existing key/value)*/
1387ff6adc4SGlenn Strauss               if (du->type == TYPE_STRING
1397ff6adc4SGlenn Strauss                   && buffer_is_equal(&((data_string *)du)->value,
1407ff6adc4SGlenn Strauss                                      &((data_string *)ddu)->value))
1417ff6adc4SGlenn Strauss                   continue;
1427ff6adc4SGlenn Strauss               if (du->type == TYPE_INTEGER
1437ff6adc4SGlenn Strauss                   && ((data_integer*)du)->value == ((data_integer*)ddu)->value)
1447ff6adc4SGlenn Strauss                   continue;
1457ff6adc4SGlenn Strauss             }
1468c7f1dfbSGlenn Strauss             op1->fn->free(op1);
14743da5818SGlenn Strauss             return NULL;
14843da5818SGlenn Strauss           }
1496e78c2c8SJan Kneschke         }
1506e78c2c8SJan Kneschke       }
1516e78c2c8SJan Kneschke       break;
1527ff6adc4SGlenn Strauss     }
1536e78c2c8SJan Kneschke     default:
15407dd0bd0SStefan Bühler       force_assert(0);
1556e78c2c8SJan Kneschke       break;
1566e78c2c8SJan Kneschke   }
1576e78c2c8SJan Kneschke   return op1;
1586e78c2c8SJan Kneschke }
1596e78c2c8SJan Kneschke 
160cf3e3012SGlenn Strauss __attribute_pure__
161cf3e3012SGlenn Strauss static comp_key_t
configparser_comp_key_id(const buffer * const obj_tag,const buffer * const comp_tag)162cf3e3012SGlenn Strauss configparser_comp_key_id(const buffer * const obj_tag, const buffer * const comp_tag)
163cf3e3012SGlenn Strauss {
164cf3e3012SGlenn Strauss   /* $REQUEST_HEADER["..."] */
165cf3e3012SGlenn Strauss   /* $SERVER["socket"] */
166cf3e3012SGlenn Strauss   /* $HTTP["..."] */
167cf3e3012SGlenn Strauss   if (buffer_eq_slen(obj_tag, CONST_STR_LEN("REQUEST_HEADER")))
168cf3e3012SGlenn Strauss     return COMP_HTTP_REQUEST_HEADER;
169cf3e3012SGlenn Strauss   else if (buffer_eq_slen(obj_tag, CONST_STR_LEN("SERVER")))
170cf3e3012SGlenn Strauss     return (buffer_eq_slen(comp_tag, CONST_STR_LEN("socket")))
171cf3e3012SGlenn Strauss       ? COMP_SERVER_SOCKET
172cf3e3012SGlenn Strauss       : COMP_UNSET;
173cf3e3012SGlenn Strauss   else if (buffer_eq_slen(obj_tag, CONST_STR_LEN("HTTP"))) {
174cf3e3012SGlenn Strauss     static const struct {
175cf3e3012SGlenn Strauss       comp_key_t comp;
176cf3e3012SGlenn Strauss       uint32_t len;
177cf3e3012SGlenn Strauss       const char *comp_tag;
178cf3e3012SGlenn Strauss     } comps[] = {
179cf3e3012SGlenn Strauss       { COMP_HTTP_URL,            CONST_LEN_STR("url"           ) },
180cf3e3012SGlenn Strauss       { COMP_HTTP_HOST,           CONST_LEN_STR("host"          ) },
181cf3e3012SGlenn Strauss       { COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("referer"       ) },
182cf3e3012SGlenn Strauss       { COMP_HTTP_USER_AGENT,     CONST_LEN_STR("useragent"     ) },
183cf3e3012SGlenn Strauss       { COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("user-agent"    ) },
184cf3e3012SGlenn Strauss       { COMP_HTTP_LANGUAGE,       CONST_LEN_STR("language"      ) },
185cf3e3012SGlenn Strauss       { COMP_HTTP_REQUEST_HEADER, CONST_LEN_STR("cookie"        ) },
186cf3e3012SGlenn Strauss       { COMP_HTTP_REMOTE_IP,      CONST_LEN_STR("remoteip"      ) },
187cf3e3012SGlenn Strauss       { COMP_HTTP_REMOTE_IP,      CONST_LEN_STR("remote-ip"     ) },
188cf3e3012SGlenn Strauss       { COMP_HTTP_QUERY_STRING,   CONST_LEN_STR("querystring"   ) },
189cf3e3012SGlenn Strauss       { COMP_HTTP_QUERY_STRING,   CONST_LEN_STR("query-string"  ) },
190cf3e3012SGlenn Strauss       { COMP_HTTP_REQUEST_METHOD, CONST_LEN_STR("request-method") },
191cf3e3012SGlenn Strauss       { COMP_HTTP_SCHEME,         CONST_LEN_STR("scheme"        ) }
192cf3e3012SGlenn Strauss     };
193cf3e3012SGlenn Strauss 
194cf3e3012SGlenn Strauss     for (uint32_t i = 0; i < sizeof(comps)/sizeof(comps[0]); ++i) {
195cf3e3012SGlenn Strauss       if (buffer_eq_slen(comp_tag, comps[i].comp_tag, comps[i].len))
196cf3e3012SGlenn Strauss         return comps[i].comp;
197cf3e3012SGlenn Strauss     }
198cf3e3012SGlenn Strauss   }
199cf3e3012SGlenn Strauss   return COMP_UNSET;
200cf3e3012SGlenn Strauss }
201cf3e3012SGlenn Strauss 
202dcb5f231SGlenn Strauss static config_cond_t
configparser_simplify_regex(buffer * const b)203dcb5f231SGlenn Strauss configparser_simplify_regex(buffer * const b)
204cf3e3012SGlenn Strauss {
205dcb5f231SGlenn Strauss     /* translate simple regex anchored with ^ and/or $ to simpler match types
206dcb5f231SGlenn Strauss      * (note: skips if regex contains any '\\', even if some could be removed,
207dcb5f231SGlenn Strauss      *  though we special-case "\.ext"; skips if other '.' found in str)
20836e64317SGlenn Strauss      * (currently assumes CONFIG_COND_MATCH input, not CONFIG_COND_NOMATCH) */
209dcb5f231SGlenn Strauss     uint32_t len = buffer_clen(b);
210dcb5f231SGlenn Strauss     config_cond_t cond = CONFIG_COND_MATCH;
211dcb5f231SGlenn Strauss     int off = 0;
212dcb5f231SGlenn Strauss     if (len && b->ptr[len-1] == '$') {
213dcb5f231SGlenn Strauss         cond = CONFIG_COND_SUFFIX;
214dcb5f231SGlenn Strauss         if (b->ptr[0] == '\\' && b->ptr[1] == '.')
215dcb5f231SGlenn Strauss             off = 2;
216dcb5f231SGlenn Strauss         else if (b->ptr[0] == '^') {
217dcb5f231SGlenn Strauss             off = 1;
218dcb5f231SGlenn Strauss             cond = CONFIG_COND_EQ;
219dcb5f231SGlenn Strauss         }
220dcb5f231SGlenn Strauss         --len;
221dcb5f231SGlenn Strauss     }
222dcb5f231SGlenn Strauss     else if (b->ptr[0] == '^') {
223dcb5f231SGlenn Strauss         off = 1;
224dcb5f231SGlenn Strauss         cond = CONFIG_COND_PREFIX;
225dcb5f231SGlenn Strauss     }
226dcb5f231SGlenn Strauss     else
227dcb5f231SGlenn Strauss         return CONFIG_COND_MATCH;
228dcb5f231SGlenn Strauss 
229dcb5f231SGlenn Strauss     static const char regex_chars[] = "\\^$.|?*+()[]{}";
230dcb5f231SGlenn Strauss     if (strcspn(b->ptr+off, regex_chars) != len - off)
231dcb5f231SGlenn Strauss         return CONFIG_COND_MATCH;
232dcb5f231SGlenn Strauss     if (off) { /*(remove only first char if (off == 2) to keep '.' in "\.")*/
233dcb5f231SGlenn Strauss         memmove(b->ptr, b->ptr+1, len-1);
234dcb5f231SGlenn Strauss         --len;
235dcb5f231SGlenn Strauss     }
236dcb5f231SGlenn Strauss     buffer_truncate(b, len);
237dcb5f231SGlenn Strauss     return cond;
238dcb5f231SGlenn Strauss }
239dcb5f231SGlenn Strauss 
240dcb5f231SGlenn Strauss static void
configparser_parse_condition(config_t * const ctx,const buffer * const obj_tag,const buffer * const comp_tag,config_cond_t cond,buffer * const rvalue)241dcb5f231SGlenn Strauss configparser_parse_condition(config_t * const ctx, const buffer * const obj_tag, const buffer * const comp_tag, config_cond_t cond, buffer * const rvalue)
242dcb5f231SGlenn Strauss {
243dcb5f231SGlenn Strauss     const comp_key_t comp = configparser_comp_key_id(obj_tag, comp_tag);
244dcb5f231SGlenn Strauss     if (cond == CONFIG_COND_MATCH && comp != COMP_SERVER_SOCKET)
245dcb5f231SGlenn Strauss         cond = configparser_simplify_regex(rvalue);
246dcb5f231SGlenn Strauss 
247cf3e3012SGlenn Strauss     const char *op = NULL;
248cf3e3012SGlenn Strauss     switch(cond) {
249cf3e3012SGlenn Strauss     case CONFIG_COND_NE:      op = "!="; break;
250cf3e3012SGlenn Strauss     case CONFIG_COND_EQ:      op = "=="; break;
251cf3e3012SGlenn Strauss     case CONFIG_COND_NOMATCH: op = "!~"; break;
252cf3e3012SGlenn Strauss     case CONFIG_COND_MATCH:   op = "=~"; break;
25339c31278SGlenn Strauss     case CONFIG_COND_PREFIX:  op = "=^"; break;
25439c31278SGlenn Strauss     case CONFIG_COND_SUFFIX:  op = "=$"; break;
255cf3e3012SGlenn Strauss     default:
256cf3e3012SGlenn Strauss       force_assert(0);
257cf3e3012SGlenn Strauss       return; /* unreachable */
258cf3e3012SGlenn Strauss     }
259cf3e3012SGlenn Strauss 
260af3df29aSGlenn Strauss     const uint32_t comp_offset = buffer_clen(&ctx->current->key)+3;
261cf3e3012SGlenn Strauss     buffer * const tb = ctx->srv->tmp_buf;
262dc01487eSGlenn Strauss     buffer_clear(tb);
263dc01487eSGlenn Strauss     struct const_iovec iov[] = {
264af3df29aSGlenn Strauss       { BUF_PTR_LEN(&ctx->current->key) }
265dc01487eSGlenn Strauss      ,{ CONST_STR_LEN(" / ") }   /* comp_offset */
266dc01487eSGlenn Strauss      ,{ CONST_STR_LEN("$") }
267af3df29aSGlenn Strauss      ,{ BUF_PTR_LEN(obj_tag) } /*(HTTP, REQUEST_HEADER, SERVER)*/
268dc01487eSGlenn Strauss      ,{ CONST_STR_LEN("[\"") }
269af3df29aSGlenn Strauss      ,{ BUF_PTR_LEN(comp_tag) }
270dc01487eSGlenn Strauss      ,{ CONST_STR_LEN("\"] ") }
271dc01487eSGlenn Strauss      ,{ op, 2 }
272dc01487eSGlenn Strauss      ,{ CONST_STR_LEN(" \"") }
273af3df29aSGlenn Strauss      ,{ BUF_PTR_LEN(rvalue) }
274dc01487eSGlenn Strauss      ,{ CONST_STR_LEN("\"") }
275dc01487eSGlenn Strauss     };
276dc01487eSGlenn Strauss     buffer_append_iovec(tb, iov, sizeof(iov)/sizeof(*iov));
277cf3e3012SGlenn Strauss 
278cf3e3012SGlenn Strauss     data_config *dc;
279cf3e3012SGlenn Strauss     if (NULL != (dc = configparser_get_data_config(ctx->all_configs,
280af3df29aSGlenn Strauss                                                    BUF_PTR_LEN(tb)))) {
281cf3e3012SGlenn Strauss       configparser_push(ctx, dc, 0);
282cf3e3012SGlenn Strauss     }
283cf3e3012SGlenn Strauss     else {
284cf3e3012SGlenn Strauss       dc = data_config_init();
285cf3e3012SGlenn Strauss       dc->cond = cond;
286dcb5f231SGlenn Strauss       dc->comp = comp;
287cf3e3012SGlenn Strauss 
288cf3e3012SGlenn Strauss       buffer_copy_buffer(&dc->key, tb);
289cf3e3012SGlenn Strauss       buffer_copy_buffer(&dc->comp_tag, comp_tag);
290cf3e3012SGlenn Strauss       dc->comp_key = dc->key.ptr + comp_offset;
291cf3e3012SGlenn Strauss 
292cf3e3012SGlenn Strauss       if (COMP_UNSET == dc->comp) {
293cf3e3012SGlenn Strauss           fprintf(stderr, "error comp_key %s", dc->comp_key);
294cf3e3012SGlenn Strauss           ctx->ok = 0;
295cf3e3012SGlenn Strauss       }
296cf3e3012SGlenn Strauss       else if (COMP_HTTP_LANGUAGE == dc->comp) {
297cf3e3012SGlenn Strauss         dc->comp = COMP_HTTP_REQUEST_HEADER;
298cf3e3012SGlenn Strauss         buffer_copy_string_len(&dc->comp_tag, CONST_STR_LEN("Accept-Language"));
299cf3e3012SGlenn Strauss       }
300cf3e3012SGlenn Strauss       else if (COMP_HTTP_USER_AGENT == dc->comp) {
301cf3e3012SGlenn Strauss         dc->comp = COMP_HTTP_REQUEST_HEADER;
302cf3e3012SGlenn Strauss         buffer_copy_string_len(&dc->comp_tag, CONST_STR_LEN("User-Agent"));
303cf3e3012SGlenn Strauss       }
304cf3e3012SGlenn Strauss       else if (COMP_HTTP_REMOTE_IP == dc->comp
30539c31278SGlenn Strauss                && (dc->cond == CONFIG_COND_EQ     ||
30639c31278SGlenn Strauss                    dc->cond == CONFIG_COND_NE     ||
30739c31278SGlenn Strauss                    dc->cond == CONFIG_COND_PREFIX ||
30839c31278SGlenn Strauss                    dc->cond == CONFIG_COND_SUFFIX)) {
3094b9da9f1SGlenn Strauss         if (!config_remoteip_normalize(rvalue, tb)) {
310cf3e3012SGlenn Strauss           fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
311cf3e3012SGlenn Strauss           ctx->ok = 0;
312cf3e3012SGlenn Strauss         }
313cf3e3012SGlenn Strauss       }
314cf3e3012SGlenn Strauss       else if (COMP_SERVER_SOCKET == dc->comp) {
315cf3e3012SGlenn Strauss         /*(redundant with parsing in network.c; not actually required here)*/
316cf3e3012SGlenn Strauss         if (rvalue->ptr[0] != ':' /*(network.c special-cases ":" and "[]")*/
31714bfa016SGlenn Strauss             && !(rvalue->ptr[0] == '[' && rvalue->ptr[1] == ']')
31814bfa016SGlenn Strauss             && !(rvalue->ptr[0] == '/' || rvalue->ptr[0] == '\\')) { /*(UDS)*/
319cf3e3012SGlenn Strauss           if (http_request_host_normalize(rvalue, 0)) {
320cf3e3012SGlenn Strauss             fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
321cf3e3012SGlenn Strauss             ctx->ok = 0;
322cf3e3012SGlenn Strauss           }
323cf3e3012SGlenn Strauss         }
324cf3e3012SGlenn Strauss       }
325cf3e3012SGlenn Strauss       else if (COMP_HTTP_HOST == dc->comp) {
32639c31278SGlenn Strauss         if (dc->cond == CONFIG_COND_EQ     ||
32739c31278SGlenn Strauss             dc->cond == CONFIG_COND_NE     ||
32839c31278SGlenn Strauss             dc->cond == CONFIG_COND_PREFIX ||
32939c31278SGlenn Strauss             dc->cond == CONFIG_COND_SUFFIX) {
330cf3e3012SGlenn Strauss           if (http_request_host_normalize(rvalue, 0)) {
331cf3e3012SGlenn Strauss             fprintf(stderr, "invalid IP addr: %s\n", rvalue->ptr);
332cf3e3012SGlenn Strauss             ctx->ok = 0;
333cf3e3012SGlenn Strauss           }
334cf3e3012SGlenn Strauss         }
335cf3e3012SGlenn Strauss       }
336cf3e3012SGlenn Strauss 
337cf3e3012SGlenn Strauss       if (COMP_HTTP_REQUEST_HEADER == dc->comp) {
338af3df29aSGlenn Strauss         dc->ext = http_header_hkey_get(BUF_PTR_LEN(&dc->comp_tag));
339cf3e3012SGlenn Strauss       }
340cf3e3012SGlenn Strauss 
3414b9da9f1SGlenn Strauss       buffer_move(&dc->string, rvalue);
342cf3e3012SGlenn Strauss 
343cf3e3012SGlenn Strauss       if (ctx->ok)
344cf3e3012SGlenn Strauss         configparser_push(ctx, dc, 1);
345cf3e3012SGlenn Strauss       else
346cf3e3012SGlenn Strauss         dc->fn->free((data_unset*) dc);
347cf3e3012SGlenn Strauss     }
348cf3e3012SGlenn Strauss }
349cf3e3012SGlenn Strauss 
350cf3e3012SGlenn Strauss static void
configparser_parse_else_condition(config_t * const ctx)351cf3e3012SGlenn Strauss configparser_parse_else_condition(config_t * const ctx)
352cf3e3012SGlenn Strauss {
353cf3e3012SGlenn Strauss     data_config * const dc = data_config_init();
354cf3e3012SGlenn Strauss     dc->cond = CONFIG_COND_ELSE;
355af3df29aSGlenn Strauss     buffer_append_str2(&dc->key, BUF_PTR_LEN(&ctx->current->key),
356dc01487eSGlenn Strauss                                  CONST_STR_LEN(" / "
357dc01487eSGlenn Strauss                                                "else_tmp_token"));
358cf3e3012SGlenn Strauss     configparser_push(ctx, dc, 1);
359cf3e3012SGlenn Strauss }
360cf3e3012SGlenn Strauss 
361bcdc6a3bSJan Kneschke }
362bcdc6a3bSJan Kneschke 
363bcdc6a3bSJan Kneschke %parse_failure {
364bcdc6a3bSJan Kneschke   ctx->ok = 0;
365bcdc6a3bSJan Kneschke }
366bcdc6a3bSJan Kneschke 
367bcdc6a3bSJan Kneschke input ::= metalines.
368bcdc6a3bSJan Kneschke metalines ::= metalines metaline.
369bcdc6a3bSJan Kneschke metalines ::= .
370bcdc6a3bSJan Kneschke metaline ::= varline.
371bf67fb14SmOo metaline ::= global.
condlines(A)3726517c89dSJan Kneschke metaline ::= condlines(A) EOL. { A = NULL; }
3736e78c2c8SJan Kneschke metaline ::= include.
37475c3a839SJan Kneschke metaline ::= include_shell.
375bcdc6a3bSJan Kneschke metaline ::= EOL.
376bcdc6a3bSJan Kneschke 
377bcdc6a3bSJan Kneschke %type       value                  {data_unset *}
3786e78c2c8SJan Kneschke %type       expression             {data_unset *}
379bcdc6a3bSJan Kneschke %type       aelement               {data_unset *}
3808073d5feSJan Kneschke %type       condline               {data_config *}
381ce24523bSGlenn Strauss %type       cond_else              {data_config *}
3828073d5feSJan Kneschke %type       condlines              {data_config *}
3836517c89dSJan Kneschke %type       aelements              {array *}
3846517c89dSJan Kneschke %type       array                  {array *}
3856517c89dSJan Kneschke %type       key                    {buffer *}
38675c3a839SJan Kneschke %type       stringop               {buffer *}
3876517c89dSJan Kneschke 
388bcdc6a3bSJan Kneschke %type       cond                   {config_cond_t }
3896517c89dSJan Kneschke 
3908c7f1dfbSGlenn Strauss %destructor value                  { if ($$) $$->fn->free($$); }
3918c7f1dfbSGlenn Strauss %destructor expression             { if ($$) $$->fn->free($$); }
3928c7f1dfbSGlenn Strauss %destructor aelement               { if ($$) $$->fn->free($$); }
3936517c89dSJan Kneschke %destructor aelements              { array_free($$); }
3946517c89dSJan Kneschke %destructor array                  { array_free($$); }
3956517c89dSJan Kneschke %destructor key                    { buffer_free($$); }
39675c3a839SJan Kneschke %destructor stringop               { buffer_free($$); }
3976517c89dSJan Kneschke 
3986517c89dSJan Kneschke %token_type                        {buffer *}
399*782fa347SGlenn Strauss %token_destructor                  { buffer_free($$); UNUSED(ctx); }
400bcdc6a3bSJan Kneschke 
key(A)4016e78c2c8SJan Kneschke varline ::= key(A) ASSIGN expression(B). {
402c97dc808SmOo   if (ctx->ok) {
403ad9b7e00SGlenn Strauss     buffer_copy_buffer(&B->key, A);
404a85ca5e0SJan Kneschke     if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
405a85ca5e0SJan Kneschke       fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
406a85ca5e0SJan Kneschke           ctx->current->context_ndx,
407ad9b7e00SGlenn Strauss           ctx->current->key.ptr, A->ptr);
408a85ca5e0SJan Kneschke       ctx->ok = 0;
409af3df29aSGlenn Strauss     } else if (NULL == array_get_element_klen(ctx->current->value, BUF_PTR_LEN(&B->key))) {
4108073d5feSJan Kneschke       array_insert_unique(ctx->current->value, B);
4116517c89dSJan Kneschke       B = NULL;
4124f14ff84SJan Kneschke     } else {
41340fb6ffeSmOo       fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
41440fb6ffeSmOo               ctx->current->context_ndx,
415ad9b7e00SGlenn Strauss               ctx->current->key.ptr, B->key.ptr);
4164f14ff84SJan Kneschke       ctx->ok = 0;
4174f14ff84SJan Kneschke     }
418c97dc808SmOo   }
419bcdc6a3bSJan Kneschke   buffer_free(A);
4206517c89dSJan Kneschke   A = NULL;
4218c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
42297526207SStefan Bühler   B = NULL;
423bcdc6a3bSJan Kneschke }
424bcdc6a3bSJan Kneschke 
key(A)425367e62c1SPhilip Prindeville varline ::= key(A) FORCE_ASSIGN expression(B). {
426367e62c1SPhilip Prindeville   if (ctx->ok) {
427367e62c1SPhilip Prindeville     if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
428367e62c1SPhilip Prindeville       fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
429367e62c1SPhilip Prindeville               ctx->current->context_ndx,
430ad9b7e00SGlenn Strauss               ctx->current->key.ptr, A->ptr);
431367e62c1SPhilip Prindeville       ctx->ok = 0;
432367e62c1SPhilip Prindeville     } else {
433ad9b7e00SGlenn Strauss       buffer_copy_buffer(&B->key, A);
434367e62c1SPhilip Prindeville       array_replace(ctx->current->value, B);
435367e62c1SPhilip Prindeville       B = NULL;
436367e62c1SPhilip Prindeville     }
437367e62c1SPhilip Prindeville   }
438367e62c1SPhilip Prindeville   buffer_free(A);
439367e62c1SPhilip Prindeville   A = NULL;
4408c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
44197526207SStefan Bühler   B = NULL;
442367e62c1SPhilip Prindeville }
443367e62c1SPhilip Prindeville 
key(A)4446e78c2c8SJan Kneschke varline ::= key(A) APPEND expression(B). {
445431559e5SStefan Bühler   if (ctx->ok) {
4466e78c2c8SJan Kneschke     array *vars = ctx->current->value;
4476e78c2c8SJan Kneschke     data_unset *du;
4486e78c2c8SJan Kneschke 
449a85ca5e0SJan Kneschke     if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
450a85ca5e0SJan Kneschke       fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
451a85ca5e0SJan Kneschke           ctx->current->context_ndx,
452ad9b7e00SGlenn Strauss           ctx->current->key.ptr, A->ptr);
453a85ca5e0SJan Kneschke       ctx->ok = 0;
454af3df29aSGlenn Strauss     } else if (NULL != (du = array_extract_element_klen(vars, BUF_PTR_LEN(A))) || NULL != (du = configparser_get_variable(ctx, A))) {
455f387d898SmOo       du = configparser_merge_data(du, B);
456f387d898SmOo       if (NULL == du) {
457f387d898SmOo         ctx->ok = 0;
458f387d898SmOo       }
459f387d898SmOo       else {
460ad9b7e00SGlenn Strauss         buffer_copy_buffer(&du->key, A);
4616e78c2c8SJan Kneschke         array_insert_unique(ctx->current->value, du);
462f387d898SmOo       }
4636b85d74cSJan Kneschke     } else {
464ad9b7e00SGlenn Strauss       buffer_copy_buffer(&B->key, A);
465a85ca5e0SJan Kneschke       array_insert_unique(ctx->current->value, B);
46697526207SStefan Bühler       B = NULL;
46797526207SStefan Bühler     }
4686e78c2c8SJan Kneschke   }
4696e78c2c8SJan Kneschke   buffer_free(A);
4706e78c2c8SJan Kneschke   A = NULL;
4718c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
4726e78c2c8SJan Kneschke   B = NULL;
4736e78c2c8SJan Kneschke }
4746e78c2c8SJan Kneschke 
key(A)475bcdc6a3bSJan Kneschke key(A) ::= LKEY(B). {
4766e78c2c8SJan Kneschke   if (strchr(B->ptr, '.') == NULL) {
477bade1c03SGlenn Strauss     buffer_copy_string((A = buffer_init()), "var.");
4786e78c2c8SJan Kneschke     buffer_append_string_buffer(A, B);
4796517c89dSJan Kneschke   } else {
480bcdc6a3bSJan Kneschke     A = B;
481bcdc6a3bSJan Kneschke     B = NULL;
482bcdc6a3bSJan Kneschke   }
48397526207SStefan Bühler   buffer_free(B);
48497526207SStefan Bühler   B = NULL;
4856e78c2c8SJan Kneschke }
4866e78c2c8SJan Kneschke 
expression(A)4876e78c2c8SJan Kneschke expression(A) ::= expression(B) PLUS value(C). {
488431559e5SStefan Bühler   A = NULL;
489431559e5SStefan Bühler   if (ctx->ok) {
490f387d898SmOo     A = configparser_merge_data(B, C);
49197526207SStefan Bühler     B = NULL;
492f387d898SmOo     if (NULL == A) {
493f387d898SmOo       ctx->ok = 0;
494f387d898SmOo     }
4956e78c2c8SJan Kneschke   }
4968c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
49797526207SStefan Bühler   B = NULL;
4988c7f1dfbSGlenn Strauss   if (C) C->fn->free(C);
49997526207SStefan Bühler   C = NULL;
500431559e5SStefan Bühler }
5016e78c2c8SJan Kneschke 
expression(A)5026e78c2c8SJan Kneschke expression(A) ::= value(B). {
5036e78c2c8SJan Kneschke   A = B;
5046e78c2c8SJan Kneschke   B = NULL;
5056e78c2c8SJan Kneschke }
5066e78c2c8SJan Kneschke 
value(A)5076e78c2c8SJan Kneschke value(A) ::= key(B). {
508a3dcc8b5SMarcus Rückert   A = NULL;
509431559e5SStefan Bühler   if (ctx->ok) {
510a85ca5e0SJan Kneschke     if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
511a85ca5e0SJan Kneschke       char *env;
512a85ca5e0SJan Kneschke 
513a85ca5e0SJan Kneschke       if (NULL != (env = getenv(B->ptr + 4))) {
514a85ca5e0SJan Kneschke         data_string *ds;
5154f8f83eaSGlenn Strauss         ds = array_data_string_init();
516601c572cSGlenn Strauss         buffer_append_string(&ds->value, env);
517a85ca5e0SJan Kneschke         A = (data_unset *)ds;
518a85ca5e0SJan Kneschke       }
519a85ca5e0SJan Kneschke       else {
520a85ca5e0SJan Kneschke         fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
521a85ca5e0SJan Kneschke         ctx->ok = 0;
522a85ca5e0SJan Kneschke       }
523a85ca5e0SJan Kneschke     } else if (NULL == (A = configparser_get_variable(ctx, B))) {
524a85ca5e0SJan Kneschke       fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
525a85ca5e0SJan Kneschke       ctx->ok = 0;
526a85ca5e0SJan Kneschke     }
52797526207SStefan Bühler   }
5286e78c2c8SJan Kneschke   buffer_free(B);
5296e78c2c8SJan Kneschke   B = NULL;
5306e78c2c8SJan Kneschke }
531bcdc6a3bSJan Kneschke 
value(A)532bcdc6a3bSJan Kneschke value(A) ::= STRING(B). {
5334f8f83eaSGlenn Strauss   A = (data_unset *)array_data_string_init();
5344f8f83eaSGlenn Strauss   /* assumes array_data_string_init() result does not need swap, buffer_free()*/
53548384c7eSGlenn Strauss   memcpy(&((data_string *)A)->value, B, sizeof(*B));
53648384c7eSGlenn Strauss   free(B);
53748384c7eSGlenn Strauss   B = NULL;
538bcdc6a3bSJan Kneschke }
539bcdc6a3bSJan Kneschke 
value(A)540bcdc6a3bSJan Kneschke value(A) ::= INTEGER(B). {
541f5453290SGlenn Strauss   char *endptr;
5424f8f83eaSGlenn Strauss   A = (data_unset *)array_data_integer_init();
543f5453290SGlenn Strauss   errno = 0;
544f5453290SGlenn Strauss   ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10);
545f5453290SGlenn Strauss   /* skip trailing whitespace */
54644686633SGlenn Strauss   if (endptr != B->ptr) while (isspace(*(unsigned char *)endptr)) endptr++;
547f5453290SGlenn Strauss   if (0 != errno || *endptr != '\0') {
548f5453290SGlenn Strauss     fprintf(stderr, "error parsing number: '%s'\n", B->ptr);
549f5453290SGlenn Strauss     ctx->ok = 0;
550f5453290SGlenn Strauss   }
551bcdc6a3bSJan Kneschke   buffer_free(B);
5526517c89dSJan Kneschke   B = NULL;
553bcdc6a3bSJan Kneschke }
value(A)554bcdc6a3bSJan Kneschke value(A) ::= array(B). {
5554f8f83eaSGlenn Strauss   A = (data_unset *)array_data_array_init();
5564f8f83eaSGlenn Strauss   /* assumes array_data_array_init() result does not need swap, array_free() */
55748384c7eSGlenn Strauss   memcpy(&((data_array *)(A))->value, B, sizeof(*B));
55848384c7eSGlenn Strauss   free(B);
5596517c89dSJan Kneschke   B = NULL;
560bcdc6a3bSJan Kneschke }
array(A)561f56e3907SJan Kneschke array(A) ::= LPARAN RPARAN. {
56224680a91SGlenn Strauss   A = array_init(8);
563f56e3907SJan Kneschke }
array(A)564bcdc6a3bSJan Kneschke array(A) ::= LPARAN aelements(B) RPARAN. {
565bcdc6a3bSJan Kneschke   A = B;
566bcdc6a3bSJan Kneschke   B = NULL;
567bcdc6a3bSJan Kneschke }
568bcdc6a3bSJan Kneschke 
aelements(A)569bcdc6a3bSJan Kneschke aelements(A) ::= aelements(C) COMMA aelement(B). {
570431559e5SStefan Bühler   A = NULL;
571431559e5SStefan Bühler   if (ctx->ok) {
572af3df29aSGlenn Strauss     if (buffer_is_unset(&B->key) ||
573af3df29aSGlenn Strauss         NULL == array_get_element_klen(C, BUF_PTR_LEN(&B->key))) {
574bcdc6a3bSJan Kneschke       array_insert_unique(C, B);
5756517c89dSJan Kneschke       B = NULL;
5764f14ff84SJan Kneschke     } else {
5776c3c3601SStefan Bühler       fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
578ad9b7e00SGlenn Strauss               B->key.ptr);
5794f14ff84SJan Kneschke       ctx->ok = 0;
5804f14ff84SJan Kneschke     }
581bcdc6a3bSJan Kneschke 
582bcdc6a3bSJan Kneschke     A = C;
5836517c89dSJan Kneschke     C = NULL;
584bcdc6a3bSJan Kneschke   }
58597526207SStefan Bühler   array_free(C);
58697526207SStefan Bühler   C = NULL;
5878c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
58897526207SStefan Bühler   B = NULL;
589431559e5SStefan Bühler }
590bcdc6a3bSJan Kneschke 
aelements(A)591bcdc6a3bSJan Kneschke aelements(A) ::= aelements(C) COMMA. {
592bcdc6a3bSJan Kneschke   A = C;
5936517c89dSJan Kneschke   C = NULL;
594bcdc6a3bSJan Kneschke }
595bcdc6a3bSJan Kneschke 
aelements(A)596bcdc6a3bSJan Kneschke aelements(A) ::= aelement(B). {
597431559e5SStefan Bühler   A = NULL;
598431559e5SStefan Bühler   if (ctx->ok) {
59924680a91SGlenn Strauss     A = array_init(4);
600bcdc6a3bSJan Kneschke     array_insert_unique(A, B);
6016517c89dSJan Kneschke     B = NULL;
602bcdc6a3bSJan Kneschke   }
6038c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
60497526207SStefan Bühler   B = NULL;
605431559e5SStefan Bühler }
606bcdc6a3bSJan Kneschke 
aelement(A)6076e78c2c8SJan Kneschke aelement(A) ::= expression(B). {
608bcdc6a3bSJan Kneschke   A = B;
609bcdc6a3bSJan Kneschke   B = NULL;
610bcdc6a3bSJan Kneschke }
aelement(A)6115e2a796aSmOo aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
612431559e5SStefan Bühler   A = NULL;
613431559e5SStefan Bühler   if (ctx->ok) {
614ad9b7e00SGlenn Strauss     buffer_copy_buffer(&C->key, B);
615bcdc6a3bSJan Kneschke 
616bcdc6a3bSJan Kneschke     A = C;
617bcdc6a3bSJan Kneschke     C = NULL;
618bcdc6a3bSJan Kneschke   }
6198c7f1dfbSGlenn Strauss   if (C) C->fn->free(C);
62097526207SStefan Bühler   C = NULL;
62197526207SStefan Bühler   buffer_free(B);
62297526207SStefan Bühler   B = NULL;
623431559e5SStefan Bühler }
624bcdc6a3bSJan Kneschke 
6258073d5feSJan Kneschke eols ::= EOL.
6268073d5feSJan Kneschke eols ::= .
6278073d5feSJan Kneschke 
628bf67fb14SmOo globalstart ::= GLOBAL. {
629bf67fb14SmOo   data_config *dc;
63083535bbeSGlenn Strauss   dc = configparser_get_data_config(ctx->srv->config_context, CONST_STR_LEN("global"));
63107dd0bd0SStefan Bühler   force_assert(dc);
632bf67fb14SmOo   configparser_push(ctx, dc, 0);
633bf67fb14SmOo }
634bf67fb14SmOo 
635431559e5SStefan Bühler global ::= globalstart LCURLY metalines RCURLY. {
636bf67fb14SmOo   configparser_pop(ctx);
637bf67fb14SmOo }
638bf67fb14SmOo 
condlines(A)639d56f19c7SJan Kneschke condlines(A) ::= condlines(B) eols ELSE condline(C). {
640431559e5SStefan Bühler   A = NULL;
641431559e5SStefan Bühler   if (ctx->ok) {
6420bd06a96SStefan Bühler     if (B->context_ndx >= C->context_ndx) {
6430bd06a96SStefan Bühler       fprintf(stderr, "unreachable else condition\n");
6440bd06a96SStefan Bühler       ctx->ok = 0;
6450bd06a96SStefan Bühler     }
64679fb7570SGlenn Strauss     if (B->cond == CONFIG_COND_ELSE) {
64779fb7570SGlenn Strauss       fprintf(stderr, "unreachable condition following else catch-all\n");
64879fb7570SGlenn Strauss       ctx->ok = 0;
64979fb7570SGlenn Strauss     }
6508073d5feSJan Kneschke     C->prev = B;
6518073d5feSJan Kneschke     B->next = C;
6528073d5feSJan Kneschke     A = C;
65397526207SStefan Bühler   }
6548073d5feSJan Kneschke   B = NULL;
6558073d5feSJan Kneschke   C = NULL;
6568073d5feSJan Kneschke }
6578073d5feSJan Kneschke 
condlines(A)658ce24523bSGlenn Strauss condlines(A) ::= condlines(B) eols ELSE cond_else(C). {
659ce24523bSGlenn Strauss   A = NULL;
660ce24523bSGlenn Strauss   if (ctx->ok) {
661ce24523bSGlenn Strauss     if (B->context_ndx >= C->context_ndx) {
662ce24523bSGlenn Strauss       fprintf(stderr, "unreachable else condition\n");
663ce24523bSGlenn Strauss       ctx->ok = 0;
664ce24523bSGlenn Strauss     }
665ce24523bSGlenn Strauss     if (B->cond == CONFIG_COND_ELSE) {
666ce24523bSGlenn Strauss       fprintf(stderr, "unreachable condition following else catch-all\n");
667ce24523bSGlenn Strauss       ctx->ok = 0;
668ce24523bSGlenn Strauss     }
669ce24523bSGlenn Strauss   }
670ce24523bSGlenn Strauss   if (ctx->ok) {
671ce24523bSGlenn Strauss     size_t pos;
672ce24523bSGlenn Strauss     data_config *dc;
673af3df29aSGlenn Strauss     dc = (data_config *)array_extract_element_klen(ctx->all_configs, BUF_PTR_LEN(&C->key));
674ce24523bSGlenn Strauss     force_assert(C == dc);
675ad9b7e00SGlenn Strauss     buffer_copy_buffer(&C->key, &B->key);
676cf3e3012SGlenn Strauss     C->comp_key = C->key.ptr + (B->comp_key - B->key.ptr);
677b6418503SGlenn Strauss     C->comp = B->comp;
6785aadcba4SGlenn Strauss     /*buffer_copy_buffer(&C->string, &B->string);*/
679cf3e3012SGlenn Strauss     /* -2 for "==" and minus 3 for spaces and quotes around string (in key) */
680af3df29aSGlenn Strauss     pos = buffer_clen(&C->key) - buffer_clen(&B->string) - 5;
681ce24523bSGlenn Strauss     switch(B->cond) {
682ce24523bSGlenn Strauss     case CONFIG_COND_NE:
683ad9b7e00SGlenn Strauss       C->key.ptr[pos] = '='; /* opposite cond */
684ce24523bSGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("=="));*/
685ce24523bSGlenn Strauss       break;
686ce24523bSGlenn Strauss     case CONFIG_COND_EQ:
687ad9b7e00SGlenn Strauss       C->key.ptr[pos] = '!'; /* opposite cond */
688ce24523bSGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("!="));*/
689ce24523bSGlenn Strauss       break;
690ce24523bSGlenn Strauss     case CONFIG_COND_NOMATCH:
691ad9b7e00SGlenn Strauss       C->key.ptr[pos] = '='; /* opposite cond */
692ce24523bSGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("=~"));*/
693ce24523bSGlenn Strauss       break;
694ce24523bSGlenn Strauss     case CONFIG_COND_MATCH:
695ad9b7e00SGlenn Strauss       C->key.ptr[pos] = '!'; /* opposite cond */
696ce24523bSGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("!~"));*/
697ce24523bSGlenn Strauss       break;
69839c31278SGlenn Strauss     case CONFIG_COND_PREFIX:
69939c31278SGlenn Strauss       C->key.ptr[pos] = '!'; /* opposite cond */
70039c31278SGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("!^"));*/
70139c31278SGlenn Strauss       break;
70239c31278SGlenn Strauss     case CONFIG_COND_SUFFIX:
70339c31278SGlenn Strauss       C->key.ptr[pos] = '!'; /* opposite cond */
70439c31278SGlenn Strauss       /*buffer_copy_string_len(C->op, CONST_STR_LEN("!$"));*/
70539c31278SGlenn Strauss       break;
706ce24523bSGlenn Strauss     default: /* should not happen; CONFIG_COND_ELSE checked further above */
707ce24523bSGlenn Strauss       force_assert(0);
708ce24523bSGlenn Strauss     }
709ce24523bSGlenn Strauss 
710af3df29aSGlenn Strauss     if (NULL == (dc = configparser_get_data_config(ctx->all_configs, BUF_PTR_LEN(&C->key)))) {
711ce24523bSGlenn Strauss       /* re-insert into ctx->all_configs with new C->key */
712ce24523bSGlenn Strauss       array_insert_unique(ctx->all_configs, (data_unset *)C);
713ce24523bSGlenn Strauss       C->prev = B;
714ce24523bSGlenn Strauss       B->next = C;
715ce24523bSGlenn Strauss     } else {
716ce24523bSGlenn Strauss       fprintf(stderr, "unreachable else condition\n");
717ce24523bSGlenn Strauss       ctx->ok = 0;
7188c7f1dfbSGlenn Strauss       C->fn->free((data_unset *)C);
719ce24523bSGlenn Strauss       C = dc;
720ce24523bSGlenn Strauss     }
721ce24523bSGlenn Strauss 
722ce24523bSGlenn Strauss     A = C;
72397526207SStefan Bühler   }
724ce24523bSGlenn Strauss   B = NULL;
725ce24523bSGlenn Strauss   C = NULL;
726ce24523bSGlenn Strauss }
727ce24523bSGlenn Strauss 
condlines(A)7288073d5feSJan Kneschke condlines(A) ::= condline(B). {
7298073d5feSJan Kneschke   A = B;
7308073d5feSJan Kneschke   B = NULL;
7318073d5feSJan Kneschke }
7328073d5feSJan Kneschke 
condline(A)7338073d5feSJan Kneschke condline(A) ::= context LCURLY metalines RCURLY. {
734431559e5SStefan Bühler   A = NULL;
735431559e5SStefan Bühler   if (ctx->ok) {
736b3e80a13SGlenn Strauss     A = configparser_pop(ctx);
737bcdc6a3bSJan Kneschke   }
738431559e5SStefan Bühler }
739bcdc6a3bSJan Kneschke 
cond_else(A)740ce24523bSGlenn Strauss cond_else(A) ::= context_else LCURLY metalines RCURLY. {
741ce24523bSGlenn Strauss   A = NULL;
742ce24523bSGlenn Strauss   if (ctx->ok) {
743b3e80a13SGlenn Strauss     A = configparser_pop(ctx);
744ce24523bSGlenn Strauss   }
745ce24523bSGlenn Strauss }
746ce24523bSGlenn Strauss 
SRVVARNAME(B)7475e2a796aSmOo context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
7486e78c2c8SJan Kneschke 
7496e78c2c8SJan Kneschke   if (ctx->ok && D->type != TYPE_STRING) {
7506e78c2c8SJan Kneschke     fprintf(stderr, "rvalue must be string");
7516e78c2c8SJan Kneschke     ctx->ok = 0;
7526e78c2c8SJan Kneschke   }
753bcdc6a3bSJan Kneschke 
754431559e5SStefan Bühler   if (ctx->ok) {
755cf3e3012SGlenn Strauss     configparser_parse_condition(ctx, B, C, E, &((data_string *)D)->value);
756360aba36SJan Kneschke   }
757360aba36SJan Kneschke 
7586517c89dSJan Kneschke   buffer_free(B);
7596517c89dSJan Kneschke   B = NULL;
7606517c89dSJan Kneschke   buffer_free(C);
7616517c89dSJan Kneschke   C = NULL;
7623c92c959SGlenn Strauss   if (D) D->fn->free(D);
7636e78c2c8SJan Kneschke   D = NULL;
764bcdc6a3bSJan Kneschke }
76579fb7570SGlenn Strauss 
766ce24523bSGlenn Strauss context_else ::= . {
76779fb7570SGlenn Strauss   if (ctx->ok) {
768cf3e3012SGlenn Strauss     configparser_parse_else_condition(ctx);
76979fb7570SGlenn Strauss   }
77079fb7570SGlenn Strauss }
77179fb7570SGlenn Strauss 
cond(A)772bcdc6a3bSJan Kneschke cond(A) ::= EQ. {
773bcdc6a3bSJan Kneschke   A = CONFIG_COND_EQ;
774bcdc6a3bSJan Kneschke }
cond(A)775bcdc6a3bSJan Kneschke cond(A) ::= MATCH. {
776bcdc6a3bSJan Kneschke   A = CONFIG_COND_MATCH;
777bcdc6a3bSJan Kneschke }
cond(A)778bcdc6a3bSJan Kneschke cond(A) ::= NE. {
779bcdc6a3bSJan Kneschke   A = CONFIG_COND_NE;
780bcdc6a3bSJan Kneschke }
cond(A)781bcdc6a3bSJan Kneschke cond(A) ::= NOMATCH. {
782bcdc6a3bSJan Kneschke   A = CONFIG_COND_NOMATCH;
783bcdc6a3bSJan Kneschke }
cond(A)78439c31278SGlenn Strauss cond(A) ::= PREFIX. {
78539c31278SGlenn Strauss   A = CONFIG_COND_PREFIX;
78639c31278SGlenn Strauss }
cond(A)78739c31278SGlenn Strauss cond(A) ::= SUFFIX. {
78839c31278SGlenn Strauss   A = CONFIG_COND_SUFFIX;
78939c31278SGlenn Strauss }
7906e78c2c8SJan Kneschke 
stringop(A)79175c3a839SJan Kneschke stringop(A) ::= expression(B). {
79275c3a839SJan Kneschke   A = NULL;
7936e78c2c8SJan Kneschke   if (ctx->ok) {
7945e2a796aSmOo     if (B->type == TYPE_STRING) {
79551e141c8SGlenn Strauss       buffer_copy_buffer((A = buffer_init()), &((data_string*)B)->value);
7965e2a796aSmOo     } else if (B->type == TYPE_INTEGER) {
7975e2a796aSmOo       A = buffer_init();
7987c7f8c46SGlenn Strauss       buffer_append_int(A, ((data_integer *)B)->value);
7995e2a796aSmOo     } else {
80075c3a839SJan Kneschke       fprintf(stderr, "operand must be string");
8016e78c2c8SJan Kneschke       ctx->ok = 0;
80275c3a839SJan Kneschke     }
80375c3a839SJan Kneschke   }
8048c7f1dfbSGlenn Strauss   if (B) B->fn->free(B);
80575c3a839SJan Kneschke   B = NULL;
80675c3a839SJan Kneschke }
80775c3a839SJan Kneschke 
stringop(A)80875c3a839SJan Kneschke include ::= INCLUDE stringop(A). {
80975c3a839SJan Kneschke   if (ctx->ok) {
81075c3a839SJan Kneschke     if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
8116e78c2c8SJan Kneschke       ctx->ok = 0;
8126e78c2c8SJan Kneschke     }
81397526207SStefan Bühler   }
81475c3a839SJan Kneschke   buffer_free(A);
8156e78c2c8SJan Kneschke   A = NULL;
8166e78c2c8SJan Kneschke }
81775c3a839SJan Kneschke 
stringop(A)81875c3a839SJan Kneschke include_shell ::= INCLUDE_SHELL stringop(A). {
81975c3a839SJan Kneschke   if (ctx->ok) {
82075c3a839SJan Kneschke     if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
82175c3a839SJan Kneschke       ctx->ok = 0;
82275c3a839SJan Kneschke     }
82397526207SStefan Bühler   }
82475c3a839SJan Kneschke   buffer_free(A);
82575c3a839SJan Kneschke   A = NULL;
82675c3a839SJan Kneschke }
827