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