File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / configparser.y
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:20:06 2014 UTC (10 years ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, HEAD
lighttpd 1.4.35

    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:     force_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:       force_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:   force_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:   force_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:   force_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:     force_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>