Annotation of embedaddon/lighttpd/src/configparser.y, revision 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>