00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <ctype.h>
00036 #include <stdarg.h>
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040
00041 #include <glib.h>
00042
00043 #include "tuple_compiler.h"
00044
00045 #define MAX_STR (256)
00046 #define MIN_ALLOC_NODES (8)
00047 #define MIN_ALLOC_BUF (64)
00048 #define TUPLEZ_MAX_VARS (4)
00049
00050 #define tuple_error(ctx, ...) fprintf (stderr, "Tuple compiler: " __VA_ARGS__)
00051
00052 enum {
00053 OP_RAW = 0,
00054 OP_FIELD,
00055 OP_EXISTS,
00056 OP_EQUALS,
00057 OP_NOT_EQUALS,
00058 OP_GT,
00059 OP_GTEQ,
00060 OP_LT,
00061 OP_LTEQ,
00062 OP_IS_EMPTY
00063 };
00064
00065 enum {
00066 TUPLE_VAR_FIELD = 0,
00067 TUPLE_VAR_CONST
00068 };
00069
00070 struct _TupleEvalNode {
00071 int opcode;
00072 int var[TUPLEZ_MAX_VARS];
00073 char *text;
00074 struct _TupleEvalNode *children, *next, *prev;
00075 };
00076
00077 typedef struct {
00078 char *name;
00079 int type;
00080 int defvali;
00081 TupleValueType ctype;
00082
00083 int fieldidx;
00084 bool_t fieldread, fieldvalid;
00085 char * fieldstr;
00086 } TupleEvalVar;
00087
00088 struct _TupleEvalContext {
00089 int nvariables;
00090 TupleEvalVar **variables;
00091 };
00092
00093
00094 static void tuple_evalctx_free_var(TupleEvalVar *var)
00095 {
00096 g_free(var->name);
00097 str_unref (var->fieldstr);
00098 g_free(var);
00099 }
00100
00101
00102
00103
00104 TupleEvalContext * tuple_evalctx_new(void)
00105 {
00106 return g_new0(TupleEvalContext, 1);
00107 }
00108
00109
00110
00111
00112 void tuple_evalctx_reset(TupleEvalContext *ctx)
00113 {
00114 int i;
00115
00116 for (i = 0; i < ctx->nvariables; i++)
00117 if (ctx->variables[i]) {
00118 ctx->variables[i]->fieldread = FALSE;
00119 ctx->variables[i]->fieldvalid = FALSE;
00120 str_unref (ctx->variables[i]->fieldstr);
00121 ctx->variables[i]->fieldstr = NULL;
00122 }
00123 }
00124
00125
00126
00127
00128 void tuple_evalctx_free(TupleEvalContext *ctx)
00129 {
00130 int i;
00131
00132 if (!ctx) return;
00133
00134
00135 for (i = 0; i < ctx->nvariables; i++)
00136 if (ctx->variables[i])
00137 tuple_evalctx_free_var(ctx->variables[i]);
00138
00139 g_free(ctx->variables);
00140 g_free(ctx);
00141 }
00142
00143
00144 static int tuple_evalctx_add_var (TupleEvalContext * ctx, const char * name,
00145 const int type, const TupleValueType ctype)
00146 {
00147 int i;
00148 TupleEvalVar *tmp = g_new0(TupleEvalVar, 1);
00149
00150 tmp->name = g_strdup(name);
00151 tmp->type = type;
00152 tmp->fieldidx = -1;
00153 tmp->ctype = ctype;
00154
00155
00156 switch (type) {
00157 case TUPLE_VAR_FIELD:
00158 tmp->fieldidx = tuple_field_by_name (name);
00159 tmp->ctype = tuple_field_get_type (tmp->fieldidx);
00160 break;
00161
00162 case TUPLE_VAR_CONST:
00163 if (ctype == TUPLE_INT)
00164 tmp->defvali = atoi(name);
00165 break;
00166 }
00167
00168
00169 for (i = 0; i < ctx->nvariables; i++)
00170 if (!ctx->variables[i]) {
00171 ctx->variables[i] = tmp;
00172 return i;
00173 }
00174
00175 i = ctx->nvariables;
00176 ctx->variables = g_renew(TupleEvalVar *, ctx->variables, ctx->nvariables + MIN_ALLOC_NODES);
00177 memset(&(ctx->variables[ctx->nvariables]), 0, MIN_ALLOC_NODES * sizeof(TupleEvalVar *));
00178 ctx->nvariables += MIN_ALLOC_NODES;
00179 ctx->variables[i] = tmp;
00180
00181 return i;
00182 }
00183
00184
00185 static void tuple_evalnode_insert(TupleEvalNode **nodes, TupleEvalNode *node)
00186 {
00187 if (*nodes) {
00188 node->prev = (*nodes)->prev;
00189 (*nodes)->prev->next = node;
00190 (*nodes)->prev = node;
00191 node->next = NULL;
00192 } else {
00193 *nodes = node;
00194 node->prev = node;
00195 node->next = NULL;
00196 }
00197 }
00198
00199
00200 static TupleEvalNode *tuple_evalnode_new(void)
00201 {
00202 return g_new0(TupleEvalNode, 1);
00203 }
00204
00205
00206 void tuple_evalnode_free(TupleEvalNode *expr)
00207 {
00208 TupleEvalNode *curr = expr, *next;
00209
00210 while (curr) {
00211 next = curr->next;
00212
00213 g_free(curr->text);
00214
00215 if (curr->children)
00216 tuple_evalnode_free(curr->children);
00217
00218 g_free(curr);
00219
00220 curr = next;
00221 }
00222 }
00223
00224
00225 static TupleEvalNode *tuple_compiler_pass1(int *level, TupleEvalContext *ctx, char **expression);
00226
00227
00228 static bool_t tc_get_item(TupleEvalContext *ctx,
00229 char **str, char *buf, gssize max,
00230 char endch, bool_t *literal, char *errstr, char *item)
00231 {
00232 gssize i = 0;
00233 char *s = *str, tmpendch;
00234
00235 if (*s == '"') {
00236 if (*literal == FALSE) {
00237 tuple_error(ctx, "Literal string value not allowed in '%s'.\n", item);
00238 return FALSE;
00239 }
00240 s++;
00241 *literal = TRUE;
00242 tmpendch = '"';
00243 } else {
00244 *literal = FALSE;
00245 tmpendch = endch;
00246 }
00247
00248 if (*literal == FALSE) {
00249 while (*s != '\0' && *s != tmpendch && (isalnum(*s) || *s == '-') && i < (max - 1)) {
00250 buf[i++] = *(s++);
00251 }
00252
00253 if (*s != tmpendch && *s != '}' && !isalnum(*s) && *s != '-') {
00254 tuple_error(ctx, "Invalid field '%s' in '%s'.\n", *str, item);
00255 return FALSE;
00256 } else if (*s != tmpendch) {
00257 tuple_error(ctx, "Expected '%c' in '%s'.\n", tmpendch, item);
00258 return FALSE;
00259 }
00260 } else {
00261 while (*s != '\0' && *s != tmpendch && i < (max - 1)) {
00262 if (*s == '\\') s++;
00263 buf[i++] = *(s++);
00264 }
00265 }
00266 buf[i] = '\0';
00267
00268 if (*literal) {
00269 if (*s == tmpendch)
00270 s++;
00271 else {
00272 tuple_error(ctx, "Expected literal string end ('%c') in '%s'.\n", tmpendch, item);
00273 return FALSE;
00274 }
00275 }
00276
00277 if (*s != endch) {
00278 tuple_error(ctx, "Expected '%c' after %s in '%s'\n", endch, errstr, item);
00279 return FALSE;
00280 } else {
00281 *str = s;
00282 return TRUE;
00283 }
00284 }
00285
00286
00287 static int tc_get_variable(TupleEvalContext *ctx, char *name, int type)
00288 {
00289 int i;
00290 TupleValueType ctype = TUPLE_UNKNOWN;
00291
00292 if (name == '\0') return -1;
00293
00294 if (isdigit(name[0])) {
00295 ctype = TUPLE_INT;
00296 type = TUPLE_VAR_CONST;
00297 } else
00298 ctype = TUPLE_STRING;
00299
00300 if (type != TUPLE_VAR_CONST) {
00301 for (i = 0; i < ctx->nvariables; i++)
00302 if (ctx->variables[i] && !strcmp(ctx->variables[i]->name, name))
00303 return i;
00304 }
00305
00306 return tuple_evalctx_add_var(ctx, name, type, ctype);
00307 }
00308
00309
00310 static bool_t tc_parse_construct(TupleEvalContext *ctx, TupleEvalNode **res, char *item, char **c, int *level, int opcode)
00311 {
00312 char tmps1[MAX_STR], tmps2[MAX_STR];
00313 bool_t literal1 = TRUE, literal2 = TRUE;
00314
00315 (*c)++;
00316 if (tc_get_item(ctx, c, tmps1, MAX_STR, ',', &literal1, "tag1", item)) {
00317 (*c)++;
00318 if (tc_get_item(ctx, c, tmps2, MAX_STR, ':', &literal2, "tag2", item)) {
00319 TupleEvalNode *tmp = tuple_evalnode_new();
00320 (*c)++;
00321
00322 tmp->opcode = opcode;
00323 if ((tmp->var[0] = tc_get_variable(ctx, tmps1, literal1 ? TUPLE_VAR_CONST : TUPLE_VAR_FIELD)) < 0) {
00324 tuple_evalnode_free(tmp);
00325 tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, item);
00326 return FALSE;
00327 }
00328 if ((tmp->var[1] = tc_get_variable(ctx, tmps2, literal2 ? TUPLE_VAR_CONST : TUPLE_VAR_FIELD)) < 0) {
00329 tuple_evalnode_free(tmp);
00330 tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps2, item);
00331 return FALSE;
00332 }
00333 tmp->children = tuple_compiler_pass1(level, ctx, c);
00334 tuple_evalnode_insert(res, tmp);
00335 } else
00336 return FALSE;
00337 } else
00338 return FALSE;
00339
00340 return TRUE;
00341 }
00342
00343
00344
00345
00346
00347
00348 static TupleEvalNode *tuple_compiler_pass1(int *level, TupleEvalContext *ctx, char **expression)
00349 {
00350 TupleEvalNode *res = NULL, *tmp = NULL;
00351 char *c = *expression, *item, tmps1[MAX_STR];
00352 bool_t literal, end = FALSE;
00353
00354 (*level)++;
00355
00356 while (*c != '\0' && !end) {
00357 tmp = NULL;
00358 if (*c == '}') {
00359 c++;
00360 (*level)--;
00361 end = TRUE;
00362 } else if (*c == '$') {
00363
00364 item = c++;
00365 if (*c == '{') {
00366 int opcode;
00367 char *expr = ++c;
00368
00369 switch (*c) {
00370 case '?': c++;
00371
00372 literal = FALSE;
00373 if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
00374 c++;
00375 tmp = tuple_evalnode_new();
00376 tmp->opcode = OP_EXISTS;
00377 if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
00378 tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
00379 goto ret_error;
00380 }
00381 tmp->children = tuple_compiler_pass1(level, ctx, &c);
00382 tuple_evalnode_insert(&res, tmp);
00383 } else
00384 goto ret_error;
00385 break;
00386
00387 case '=': c++;
00388 if (*c != '=') {
00389
00390 literal = FALSE;
00391 if (tc_get_item(ctx, &c, tmps1, MAX_STR, ',', &literal, "variable", item)) {
00392 c++;
00393 if (*c == '"') {
00394
00395 c++;
00396 } else if (isdigit(*c)) {
00397
00398 }
00399
00400 tuple_error(ctx, "Definitions are not yet supported!\n");
00401 goto ret_error;
00402 } else
00403 goto ret_error;
00404 } else {
00405
00406 if (!tc_parse_construct(ctx, &res, item, &c, level, OP_EQUALS))
00407 goto ret_error;
00408 }
00409 break;
00410
00411 case '!': c++;
00412 if (*c != '=') goto ext_expression;
00413 if (!tc_parse_construct(ctx, &res, item, &c, level, OP_NOT_EQUALS))
00414 goto ret_error;
00415 break;
00416
00417 case '<': c++;
00418 if (*c == '=') {
00419 opcode = OP_LTEQ;
00420 c++;
00421 } else
00422 opcode = OP_LT;
00423
00424 if (!tc_parse_construct(ctx, &res, item, &c, level, opcode))
00425 goto ret_error;
00426 break;
00427
00428 case '>': c++;
00429 if (*c == '=') {
00430 opcode = OP_GTEQ;
00431 c++;
00432 } else
00433 opcode = OP_GT;
00434
00435 if (!tc_parse_construct(ctx, &res, item, &c, level, opcode))
00436 goto ret_error;
00437 break;
00438
00439 case '(': c++;
00440 if (!strncmp(c, "empty)?", 7)) {
00441 c += 7;
00442 literal = FALSE;
00443 if (tc_get_item(ctx, &c, tmps1, MAX_STR, ':', &literal, "tag", item)) {
00444 c++;
00445 tmp = tuple_evalnode_new();
00446 tmp->opcode = OP_IS_EMPTY;
00447 if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
00448 tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
00449 goto ret_error;
00450 }
00451 tmp->children = tuple_compiler_pass1(level, ctx, &c);
00452 tuple_evalnode_insert(&res, tmp);
00453 } else
00454 goto ret_error;
00455 } else
00456 goto ext_expression;
00457 break;
00458
00459 default:
00460 ext_expression:
00461
00462 c = expr;
00463 literal = FALSE;
00464 if (tc_get_item(ctx, &c, tmps1, MAX_STR, '}', &literal, "field", item)) {
00465
00466
00467
00468 tmp = tuple_evalnode_new();
00469 tmp->opcode = OP_FIELD;
00470 if ((tmp->var[0] = tc_get_variable(ctx, tmps1, TUPLE_VAR_FIELD)) < 0) {
00471 tuple_error(ctx, "Invalid variable '%s' in '%s'.\n", tmps1, expr);
00472 goto ret_error;
00473 }
00474 tuple_evalnode_insert(&res, tmp);
00475 c++;
00476
00477 } else
00478 goto ret_error;
00479 }
00480 } else {
00481 tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
00482 goto ret_error;
00483 }
00484
00485 } else if (*c == '%') {
00486
00487 item = c++;
00488 if (*c == '{') {
00489 gssize i = 0;
00490 c++;
00491
00492 while (*c != '\0' && (isalnum(*c) || *c == '-') && *c != '}' && *c != ':' && i < (MAX_STR - 1))
00493 tmps1[i++] = *(c++);
00494 tmps1[i] = '\0';
00495
00496 if (*c == ':') {
00497 c++;
00498 } else if (*c == '}') {
00499 c++;
00500 } else if (*c == '\0') {
00501 tuple_error(ctx, "Expected '}' or function arguments in '%s'\n", item);
00502 goto ret_error;
00503 }
00504 } else {
00505 tuple_error(ctx, "Expected '{', got '%c' in '%s'.\n", *c, c);
00506 goto ret_error;
00507 }
00508 } else {
00509
00510 gssize i = 0;
00511 while (*c != '\0' && *c != '$' && *c != '%' && *c != '}' && i < (MAX_STR - 1)) {
00512 if (*c == '\\') c++;
00513 tmps1[i++] = *(c++);
00514 }
00515 tmps1[i] = '\0';
00516
00517 tmp = tuple_evalnode_new();
00518 tmp->opcode = OP_RAW;
00519 tmp->text = g_strdup(tmps1);
00520 tuple_evalnode_insert(&res, tmp);
00521 }
00522 }
00523
00524 if (*level <= 0) {
00525 tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements in '%s'!\n", c);
00526 goto ret_error;
00527 }
00528
00529 *expression = c;
00530 return res;
00531
00532 ret_error:
00533 tuple_evalnode_free(tmp);
00534 tuple_evalnode_free(res);
00535 return NULL;
00536 }
00537
00538
00539 TupleEvalNode *tuple_formatter_compile(TupleEvalContext *ctx, char *expr)
00540 {
00541 int level = 0;
00542 char *tmpexpr = expr;
00543 TupleEvalNode *res1;
00544
00545 res1 = tuple_compiler_pass1(&level, ctx, &tmpexpr);
00546
00547 if (level != 1) {
00548 tuple_error(ctx, "Syntax error! Uneven/unmatched nesting of elements! (%d)\n", level);
00549 tuple_evalnode_free(res1);
00550 return NULL;
00551 }
00552
00553 return res1;
00554 }
00555
00556
00557
00558 static bool_t tf_get_fieldval (TupleEvalVar * var, const Tuple * tuple)
00559 {
00560 if (var->type != TUPLE_VAR_FIELD || var->fieldidx < 0)
00561 return FALSE;
00562
00563 if (var->fieldread)
00564 return var->fieldvalid;
00565
00566 if (tuple_get_value_type (tuple, var->fieldidx, NULL) != var->ctype) {
00567 var->fieldread = TRUE;
00568 var->fieldvalid = FALSE;
00569 return FALSE;
00570 }
00571
00572 if (var->ctype == TUPLE_INT)
00573 var->defvali = tuple_get_int (tuple, var->fieldidx, NULL);
00574 else if (var->ctype == TUPLE_STRING)
00575 var->fieldstr = tuple_get_str (tuple, var->fieldidx, NULL);
00576
00577 var->fieldread = TRUE;
00578 var->fieldvalid = TRUE;
00579 return TRUE;
00580 }
00581
00582
00583
00584
00585
00586 static TupleValueType tf_get_var (char * * tmps, int * tmpi, TupleEvalVar *
00587 var, const Tuple * tuple)
00588 {
00589 TupleValueType type = TUPLE_UNKNOWN;
00590 *tmps = NULL;
00591 *tmpi = 0;
00592
00593 switch (var->type) {
00594 case TUPLE_VAR_CONST:
00595 switch (var->ctype) {
00596 case TUPLE_STRING: *tmps = var->name; break;
00597 case TUPLE_INT: *tmpi = var->defvali; break;
00598 default: break;
00599 }
00600 type = var->ctype;
00601 break;
00602
00603 case TUPLE_VAR_FIELD:
00604 if (tf_get_fieldval (var, tuple)) {
00605 type = var->ctype;
00606 if (type == TUPLE_INT)
00607 * tmpi = var->defvali;
00608 else if (type == TUPLE_STRING)
00609 * tmps = var->fieldstr;
00610 }
00611 break;
00612 }
00613
00614 return type;
00615 }
00616
00617
00618
00619
00620
00621 static bool_t tuple_formatter_eval_do (TupleEvalContext * ctx, TupleEvalNode *
00622 expr, const Tuple * tuple, GString * out)
00623 {
00624 TupleEvalNode *curr = expr;
00625 TupleEvalVar *var0, *var1;
00626 TupleValueType type0, type1;
00627 int tmpi0, tmpi1;
00628 char tmps[MAX_STR], *tmps0, *tmps1, *tmps2;
00629 bool_t result;
00630 int resulti;
00631
00632 if (!expr) return FALSE;
00633
00634 while (curr) {
00635 const char *str = NULL;
00636
00637 switch (curr->opcode) {
00638 case OP_RAW:
00639 str = curr->text;
00640 break;
00641
00642 case OP_FIELD:
00643 var0 = ctx->variables[curr->var[0]];
00644
00645 switch (var0->type) {
00646 case TUPLE_VAR_FIELD:
00647 if (tf_get_fieldval (var0, tuple)) {
00648 switch (var0->ctype) {
00649 case TUPLE_STRING:
00650 str = var0->fieldstr;
00651 break;
00652
00653 case TUPLE_INT:
00654 g_snprintf (tmps, sizeof (tmps), "%d", var0->defvali);
00655 str = tmps;
00656 break;
00657
00658 default:
00659 str = NULL;
00660 }
00661 }
00662 break;
00663 }
00664 break;
00665
00666 case OP_EQUALS:
00667 case OP_NOT_EQUALS:
00668 case OP_LT: case OP_LTEQ:
00669 case OP_GT: case OP_GTEQ:
00670 var0 = ctx->variables[curr->var[0]];
00671 var1 = ctx->variables[curr->var[1]];
00672
00673 type0 = tf_get_var(&tmps0, &tmpi0, var0, tuple);
00674 type1 = tf_get_var(&tmps1, &tmpi1, var1, tuple);
00675 result = FALSE;
00676
00677 if (type0 != TUPLE_UNKNOWN && type1 != TUPLE_UNKNOWN) {
00678 if (type0 == type1) {
00679 if (type0 == TUPLE_STRING)
00680 resulti = strcmp(tmps0, tmps1);
00681 else
00682 resulti = tmpi0 - tmpi1;
00683 } else {
00684 if (type0 == TUPLE_INT)
00685 resulti = tmpi0 - atoi(tmps1);
00686 else
00687 resulti = atoi(tmps0) - tmpi1;
00688 }
00689
00690 switch (curr->opcode) {
00691 case OP_EQUALS: result = (resulti == 0); break;
00692 case OP_NOT_EQUALS: result = (resulti != 0); break;
00693 case OP_LT: result = (resulti < 0); break;
00694 case OP_LTEQ: result = (resulti <= 0); break;
00695 case OP_GT: result = (resulti > 0); break;
00696 case OP_GTEQ: result = (resulti >= 0); break;
00697 default: result = FALSE;
00698 }
00699 }
00700
00701 if (result && ! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
00702 return FALSE;
00703 break;
00704
00705 case OP_EXISTS:
00706 if (tf_get_fieldval (ctx->variables[curr->var[0]], tuple)) {
00707 if (! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
00708 return FALSE;
00709 }
00710 break;
00711
00712 case OP_IS_EMPTY:
00713 var0 = ctx->variables[curr->var[0]];
00714
00715 if (tf_get_fieldval (var0, tuple)) {
00716 switch (var0->ctype) {
00717 case TUPLE_INT:
00718 result = (var0->defvali == 0);
00719 break;
00720
00721 case TUPLE_STRING:
00722 result = TRUE;
00723 tmps2 = var0->fieldstr;
00724
00725 while (result && tmps2 && *tmps2 != '\0') {
00726 gunichar uc = g_utf8_get_char(tmps2);
00727 if (g_unichar_isspace(uc))
00728 tmps2 = g_utf8_next_char(tmps2);
00729 else
00730 result = FALSE;
00731 }
00732 break;
00733
00734 default:
00735 result = TRUE;
00736 }
00737 } else
00738 result = TRUE;
00739
00740 if (result && ! tuple_formatter_eval_do (ctx, curr->children, tuple, out))
00741 return FALSE;
00742 break;
00743
00744 default:
00745 tuple_error(ctx, "Unimplemented opcode %d!\n", curr->opcode);
00746 return FALSE;
00747 break;
00748 }
00749
00750 if (str)
00751 g_string_append (out, str);
00752
00753 curr = curr->next;
00754 }
00755
00756 return TRUE;
00757 }
00758
00759 void tuple_formatter_eval (TupleEvalContext * ctx, TupleEvalNode * expr,
00760 const Tuple * tuple, GString * out)
00761 {
00762 g_string_truncate (out, 0);
00763 tuple_formatter_eval_do (ctx, expr, tuple, out);
00764 }