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