00001
00014 #include "system.h"
00015
00016 #include <rpmio.h>
00017 #include <rpmbuild.h>
00018 #include <rpmlib.h>
00019
00020 #include "debug.h"
00021
00022
00023
00024 #ifdef DEBUG_PARSER
00025 #include <stdio.h>
00026 #define DEBUG(x) do { x ; } while (0)
00027 #else
00028 #define DEBUG(x)
00029 #endif
00030
00034 typedef struct _value {
00035 enum { VALUE_TYPE_INTEGER, VALUE_TYPE_STRING } type;
00036 union {
00037 const char *s;
00038 int i;
00039 } data;
00040 } *Value;
00041
00044 static Value valueMakeInteger(int i)
00045
00046 {
00047 Value v;
00048
00049 v = (Value) xmalloc(sizeof(*v));
00050 v->type = VALUE_TYPE_INTEGER;
00051 v->data.i = i;
00052 return v;
00053 }
00054
00057 static Value valueMakeString( const char *s)
00058
00059 {
00060 Value v;
00061
00062 v = (Value) xmalloc(sizeof(*v));
00063 v->type = VALUE_TYPE_STRING;
00064 v->data.s = s;
00065 return v;
00066 }
00067
00070 static void valueFree( Value v)
00071
00072 {
00073 if (v) {
00074 if (v->type == VALUE_TYPE_STRING)
00075 v->data.s = _free(v->data.s);
00076 v = _free(v);
00077 }
00078 }
00079
00080 #ifdef DEBUG_PARSER
00081 static void valueDump(const char *msg, Value v, FILE *fp)
00082
00083 {
00084 if (msg)
00085 fprintf(fp, "%s ", msg);
00086 if (v) {
00087 if (v->type == VALUE_TYPE_INTEGER)
00088 fprintf(fp, "INTEGER %d\n", v->data.i);
00089 else
00090 fprintf(fp, "STRING '%s'\n", v->data.s);
00091 } else
00092 fprintf(fp, "NULL\n");
00093 }
00094 #endif
00095
00096 #define valueIsInteger(v) ((v)->type == VALUE_TYPE_INTEGER)
00097 #define valueIsString(v) ((v)->type == VALUE_TYPE_STRING)
00098 #define valueSameType(v1,v2) ((v1)->type == (v2)->type)
00099
00100
00104 typedef struct _parseState {
00105
00106 char *str;
00107
00108 char *p;
00109 int nextToken;
00110
00111 Value tokenValue;
00112 Spec spec;
00113 } *ParseState;
00114
00115
00120 #define TOK_EOF 1
00121 #define TOK_INTEGER 2
00122 #define TOK_STRING 3
00123 #define TOK_IDENTIFIER 4
00124 #define TOK_ADD 5
00125 #define TOK_MINUS 6
00126 #define TOK_MULTIPLY 7
00127 #define TOK_DIVIDE 8
00128 #define TOK_OPEN_P 9
00129 #define TOK_CLOSE_P 10
00130 #define TOK_EQ 11
00131 #define TOK_NEQ 12
00132 #define TOK_LT 13
00133 #define TOK_LE 14
00134 #define TOK_GT 15
00135 #define TOK_GE 16
00136 #define TOK_NOT 17
00137 #define TOK_LOGICAL_AND 18
00138 #define TOK_LOGICAL_OR 19
00139
00141 #define EXPRBUFSIZ BUFSIZ
00142
00143 #if defined(DEBUG_PARSER)
00144 typedef struct exprTokTableEntry {
00145 const char *name;
00146 int val;
00147 } ETTE_t;
00148
00149 ETTE_t exprTokTable[] = {
00150 { "EOF", TOK_EOF },
00151 { "I", TOK_INTEGER },
00152 { "S", TOK_STRING },
00153 { "ID", TOK_IDENTIFIER },
00154 { "+", TOK_ADD },
00155 { "-", TOK_MINUS },
00156 { "*", TOK_MULTIPLY },
00157 { "/", TOK_DIVIDE },
00158 { "( ", TOK_OPEN_P },
00159 { " )", TOK_CLOSE_P },
00160 { "==", TOK_EQ },
00161 { "!=", TOK_NEQ },
00162 { "<", TOK_LT },
00163 { "<=", TOK_LE },
00164 { ">", TOK_GT },
00165 { ">=", TOK_GE },
00166 { "!", TOK_NOT },
00167 { "&&", TOK_LOGICAL_AND },
00168 { "||", TOK_LOGICAL_OR },
00169 { NULL, 0 }
00170 };
00171
00172 static const char *prToken(int val)
00173
00174 {
00175 ETTE_t *et;
00176
00177 for (et = exprTokTable; et->name != NULL; et++) {
00178 if (val == et->val)
00179 return et->name;
00180 }
00181 return "???";
00182 }
00183 #endif
00184
00188 static int rdToken(ParseState state)
00189
00190
00191
00192 {
00193 int token;
00194 Value v = NULL;
00195 char *p = state->p;
00196
00197
00198 while (*p && xisspace(*p)) p++;
00199
00200 switch (*p) {
00201 case '\0':
00202 token = TOK_EOF;
00203 p--;
00204 break;
00205 case '+':
00206 token = TOK_ADD;
00207 break;
00208 case '-':
00209 token = TOK_MINUS;
00210 break;
00211 case '*':
00212 token = TOK_MULTIPLY;
00213 break;
00214 case '/':
00215 token = TOK_DIVIDE;
00216 break;
00217 case '(':
00218 token = TOK_OPEN_P;
00219 break;
00220 case ')':
00221 token = TOK_CLOSE_P;
00222 break;
00223 case '=':
00224 if (p[1] == '=') {
00225 token = TOK_EQ;
00226 p++;
00227 } else {
00228 rpmlog(RPMLOG_ERR, _("syntax error while parsing ==\n"));
00229 return -1;
00230 }
00231 break;
00232 case '!':
00233 if (p[1] == '=') {
00234 token = TOK_NEQ;
00235 p++;
00236 } else
00237 token = TOK_NOT;
00238 break;
00239 case '<':
00240 if (p[1] == '=') {
00241 token = TOK_LE;
00242 p++;
00243 } else
00244 token = TOK_LT;
00245 break;
00246 case '>':
00247 if (p[1] == '=') {
00248 token = TOK_GE;
00249 p++;
00250 } else
00251 token = TOK_GT;
00252 break;
00253 case '&':
00254 if (p[1] == '&') {
00255 token = TOK_LOGICAL_AND;
00256 p++;
00257 } else {
00258 rpmlog(RPMLOG_ERR, _("syntax error while parsing &&\n"));
00259 return -1;
00260 }
00261 break;
00262 case '|':
00263 if (p[1] == '|') {
00264 token = TOK_LOGICAL_OR;
00265 p++;
00266 } else {
00267 rpmlog(RPMLOG_ERR, _("syntax error while parsing ||\n"));
00268 return -1;
00269 }
00270 break;
00271
00272 default:
00273 if (xisdigit(*p)) {
00274 char temp[EXPRBUFSIZ], *t = temp;
00275
00276 temp[0] = '\0';
00277 while (*p && xisdigit(*p))
00278 *t++ = *p++;
00279 *t++ = '\0';
00280 p--;
00281
00282 token = TOK_INTEGER;
00283 v = valueMakeInteger(atoi(temp));
00284
00285 } else if (xisalpha(*p)) {
00286 char temp[EXPRBUFSIZ], *t = temp;
00287
00288 temp[0] = '\0';
00289 while (*p && (xisalnum(*p) || *p == '_'))
00290 *t++ = *p++;
00291 *t++ = '\0';
00292 p--;
00293
00294 token = TOK_IDENTIFIER;
00295 v = valueMakeString( xstrdup(temp) );
00296
00297 } else if (*p == '\"') {
00298 char temp[EXPRBUFSIZ], *t = temp;
00299
00300 temp[0] = '\0';
00301 p++;
00302 while (*p && *p != '\"')
00303 *t++ = *p++;
00304 *t++ = '\0';
00305
00306 token = TOK_STRING;
00307 v = valueMakeString( rpmExpand(temp, NULL) );
00308
00309 } else {
00310 rpmlog(RPMLOG_ERR, _("parse error in expression\n"));
00311 return -1;
00312 }
00313 }
00314
00315 state->p = p + 1;
00316 state->nextToken = token;
00317 state->tokenValue = v;
00318
00319 DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token));
00320 DEBUG(valueDump("rdToken:", state->tokenValue, stdout));
00321
00322 return 0;
00323 }
00324
00325
00326 static Value doLogical(ParseState state)
00327
00328
00329 ;
00330
00334
00335 static Value doPrimary(ParseState state)
00336
00337
00338
00339 {
00340 Value v;
00341
00342 DEBUG(printf("doPrimary()\n"));
00343
00344 switch (state->nextToken) {
00345 case TOK_OPEN_P:
00346 if (rdToken(state))
00347 return NULL;
00348 v = doLogical(state);
00349 if (state->nextToken != TOK_CLOSE_P) {
00350 rpmlog(RPMLOG_ERR, _("unmatched (\n"));
00351 return NULL;
00352 }
00353 if (rdToken(state))
00354 return NULL;
00355 break;
00356
00357 case TOK_INTEGER:
00358 case TOK_STRING:
00359 v = state->tokenValue;
00360 if (rdToken(state))
00361 return NULL;
00362 break;
00363
00364 case TOK_IDENTIFIER: {
00365 const char *name = state->tokenValue->data.s;
00366
00367 v = valueMakeString( rpmExpand(name, NULL) );
00368 if (rdToken(state))
00369 return NULL;
00370 break;
00371 }
00372
00373 case TOK_MINUS:
00374 if (rdToken(state))
00375 return NULL;
00376
00377 v = doPrimary(state);
00378 if (v == NULL)
00379 return NULL;
00380
00381 if (! valueIsInteger(v)) {
00382 rpmlog(RPMLOG_ERR, _("- only on numbers\n"));
00383 return NULL;
00384 }
00385
00386 v = valueMakeInteger(- v->data.i);
00387 break;
00388
00389 case TOK_NOT:
00390 if (rdToken(state))
00391 return NULL;
00392
00393 v = doPrimary(state);
00394 if (v == NULL)
00395 return NULL;
00396
00397 if (! valueIsInteger(v)) {
00398 rpmlog(RPMLOG_ERR, _("! only on numbers\n"));
00399 return NULL;
00400 }
00401
00402 v = valueMakeInteger(! v->data.i);
00403 break;
00404 default:
00405 return NULL;
00406 break;
00407 }
00408
00409 DEBUG(valueDump("doPrimary:", v, stdout));
00410 return v;
00411 }
00412
00416
00417 static Value doMultiplyDivide(ParseState state)
00418
00419
00420
00421 {
00422 Value v1, v2 = NULL;
00423
00424 DEBUG(printf("doMultiplyDivide()\n"));
00425
00426 v1 = doPrimary(state);
00427 if (v1 == NULL)
00428 return NULL;
00429
00430 while (state->nextToken == TOK_MULTIPLY
00431 || state->nextToken == TOK_DIVIDE) {
00432 int op = state->nextToken;
00433
00434 if (rdToken(state))
00435 return NULL;
00436
00437 if (v2) valueFree(v2);
00438
00439 v2 = doPrimary(state);
00440 if (v2 == NULL)
00441 return NULL;
00442
00443 if (! valueSameType(v1, v2)) {
00444 rpmlog(RPMLOG_ERR, _("types must match\n"));
00445 return NULL;
00446 }
00447
00448 if (valueIsInteger(v1)) {
00449 int i1 = v1->data.i, i2 = v2->data.i;
00450
00451 valueFree(v1);
00452 if (op == TOK_MULTIPLY)
00453 v1 = valueMakeInteger(i1 * i2);
00454 else
00455 v1 = valueMakeInteger(i1 / i2);
00456 } else {
00457 rpmlog(RPMLOG_ERR, _("* / not suported for strings\n"));
00458 return NULL;
00459 }
00460 }
00461
00462 if (v2) valueFree(v2);
00463 return v1;
00464 }
00465
00469
00470 static Value doAddSubtract(ParseState state)
00471
00472
00473
00474 {
00475 Value v1, v2 = NULL;
00476
00477 DEBUG(printf("doAddSubtract()\n"));
00478
00479 v1 = doMultiplyDivide(state);
00480 if (v1 == NULL)
00481 return NULL;
00482
00483 while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00484 int op = state->nextToken;
00485
00486 if (rdToken(state))
00487 return NULL;
00488
00489 if (v2) valueFree(v2);
00490
00491 v2 = doMultiplyDivide(state);
00492 if (v2 == NULL)
00493 return NULL;
00494
00495 if (! valueSameType(v1, v2)) {
00496 rpmlog(RPMLOG_ERR, _("types must match\n"));
00497 return NULL;
00498 }
00499
00500 if (valueIsInteger(v1)) {
00501 int i1 = v1->data.i, i2 = v2->data.i;
00502
00503 valueFree(v1);
00504 if (op == TOK_ADD)
00505 v1 = valueMakeInteger(i1 + i2);
00506 else
00507 v1 = valueMakeInteger(i1 - i2);
00508 } else {
00509 char *copy;
00510
00511 if (op == TOK_MINUS) {
00512 rpmlog(RPMLOG_ERR, _("- not suported for strings\n"));
00513 return NULL;
00514 }
00515
00516 copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00517 (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00518
00519 valueFree(v1);
00520 v1 = valueMakeString(copy);
00521 }
00522 }
00523
00524 if (v2) valueFree(v2);
00525 return v1;
00526 }
00527
00531
00532 static Value doRelational(ParseState state)
00533
00534
00535
00536 {
00537 Value v1, v2 = NULL;
00538
00539 DEBUG(printf("doRelational()\n"));
00540
00541 v1 = doAddSubtract(state);
00542 if (v1 == NULL)
00543 return NULL;
00544
00545 while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00546 int op = state->nextToken;
00547
00548 if (rdToken(state))
00549 return NULL;
00550
00551 if (v2) valueFree(v2);
00552
00553 v2 = doAddSubtract(state);
00554 if (v2 == NULL)
00555 return NULL;
00556
00557 if (! valueSameType(v1, v2)) {
00558 rpmlog(RPMLOG_ERR, _("types must match\n"));
00559 return NULL;
00560 }
00561
00562 if (valueIsInteger(v1)) {
00563 int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00564 switch (op) {
00565 case TOK_EQ:
00566 r = (i1 == i2);
00567 break;
00568 case TOK_NEQ:
00569 r = (i1 != i2);
00570 break;
00571 case TOK_LT:
00572 r = (i1 < i2);
00573 break;
00574 case TOK_LE:
00575 r = (i1 <= i2);
00576 break;
00577 case TOK_GT:
00578 r = (i1 > i2);
00579 break;
00580 case TOK_GE:
00581 r = (i1 >= i2);
00582 break;
00583 default:
00584 break;
00585 }
00586 valueFree(v1);
00587 v1 = valueMakeInteger(r);
00588 } else {
00589 const char * s1 = v1->data.s;
00590 const char * s2 = v2->data.s;
00591 int r = 0;
00592 switch (op) {
00593 case TOK_EQ:
00594 r = (strcmp(s1,s2) == 0);
00595 break;
00596 case TOK_NEQ:
00597 r = (strcmp(s1,s2) != 0);
00598 break;
00599 case TOK_LT:
00600 r = (strcmp(s1,s2) < 0);
00601 break;
00602 case TOK_LE:
00603 r = (strcmp(s1,s2) <= 0);
00604 break;
00605 case TOK_GT:
00606 r = (strcmp(s1,s2) > 0);
00607 break;
00608 case TOK_GE:
00609 r = (strcmp(s1,s2) >= 0);
00610 break;
00611 default:
00612 break;
00613 }
00614 valueFree(v1);
00615 v1 = valueMakeInteger(r);
00616 }
00617 }
00618
00619 if (v2) valueFree(v2);
00620 return v1;
00621 }
00622
00626 static Value doLogical(ParseState state)
00627
00628
00629
00630 {
00631 Value v1, v2 = NULL;
00632
00633 DEBUG(printf("doLogical()\n"));
00634
00635 v1 = doRelational(state);
00636 if (v1 == NULL)
00637 return NULL;
00638
00639 while (state->nextToken == TOK_LOGICAL_AND
00640 || state->nextToken == TOK_LOGICAL_OR) {
00641 int op = state->nextToken;
00642
00643 if (rdToken(state))
00644 return NULL;
00645
00646 if (v2) valueFree(v2);
00647
00648 v2 = doRelational(state);
00649 if (v2 == NULL)
00650 return NULL;
00651
00652 if (! valueSameType(v1, v2)) {
00653 rpmlog(RPMLOG_ERR, _("types must match\n"));
00654 return NULL;
00655 }
00656
00657 if (valueIsInteger(v1)) {
00658 int i1 = v1->data.i, i2 = v2->data.i;
00659
00660 valueFree(v1);
00661 if (op == TOK_LOGICAL_AND)
00662 v1 = valueMakeInteger(i1 && i2);
00663 else
00664 v1 = valueMakeInteger(i1 || i2);
00665 } else {
00666 rpmlog(RPMLOG_ERR, _("&& and || not suported for strings\n"));
00667 return NULL;
00668 }
00669 }
00670
00671 if (v2) valueFree(v2);
00672 return v1;
00673 }
00674
00675 int parseExpressionBoolean(Spec spec, const char *expr)
00676 {
00677 struct _parseState state;
00678 int result = -1;
00679 Value v;
00680
00681 DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00682
00683
00684 state.p = state.str = xstrdup(expr);
00685 state.spec = spec;
00686 state.nextToken = 0;
00687 state.tokenValue = NULL;
00688 (void) rdToken(&state);
00689
00690
00691 v = doLogical(&state);
00692 if (!v) {
00693 state.str = _free(state.str);
00694 return -1;
00695 }
00696
00697
00698 if (state.nextToken != TOK_EOF) {
00699 rpmlog(RPMLOG_ERR, _("syntax error in expression\n"));
00700 state.str = _free(state.str);
00701 return -1;
00702 }
00703
00704 DEBUG(valueDump("parseExprBoolean:", v, stdout));
00705
00706 switch (v->type) {
00707 case VALUE_TYPE_INTEGER:
00708 result = v->data.i != 0;
00709 break;
00710 case VALUE_TYPE_STRING:
00711 result = v->data.s[0] != '\0';
00712 break;
00713 default:
00714 break;
00715 }
00716
00717 state.str = _free(state.str);
00718 valueFree(v);
00719 return result;
00720 }
00721
00722 char * parseExpressionString(Spec spec, const char *expr)
00723 {
00724 struct _parseState state;
00725 char *result = NULL;
00726 Value v;
00727
00728 DEBUG(printf("parseExprString(?, '%s')\n", expr));
00729
00730
00731 state.p = state.str = xstrdup(expr);
00732 state.spec = spec;
00733 state.nextToken = 0;
00734 state.tokenValue = NULL;
00735 (void) rdToken(&state);
00736
00737
00738 v = doLogical(&state);
00739 if (!v) {
00740 state.str = _free(state.str);
00741 return NULL;
00742 }
00743
00744
00745 if (state.nextToken != TOK_EOF) {
00746 rpmlog(RPMLOG_ERR, _("syntax error in expression\n"));
00747 state.str = _free(state.str);
00748 return NULL;
00749 }
00750
00751 DEBUG(valueDump("parseExprString:", v, stdout));
00752
00753 switch (v->type) {
00754 case VALUE_TYPE_INTEGER: {
00755 char buf[128];
00756 sprintf(buf, "%d", v->data.i);
00757 result = xstrdup(buf);
00758 } break;
00759 case VALUE_TYPE_STRING:
00760 result = xstrdup(v->data.s);
00761 break;
00762 default:
00763 break;
00764 }
00765
00766 state.str = _free(state.str);
00767 valueFree(v);
00768 return result;
00769 }