Annotation of embedaddon/lighttpd/src/configparser.y, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>