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