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 temp[0] = '\0';
00265 while (*p && xisdigit(*p))
00266 *t++ = *p++;
00267 *t++ = '\0';
00268 p--;
00269
00270 token = TOK_INTEGER;
00271 v = valueMakeInteger(atoi(temp));
00272
00273 } else if (xisalpha(*p)) {
00274 char temp[EXPRBUFSIZ], *t = temp;
00275
00276 temp[0] = '\0';
00277 while (*p && (xisalnum(*p) || *p == '_'))
00278 *t++ = *p++;
00279 *t++ = '\0';
00280 p--;
00281
00282 token = TOK_IDENTIFIER;
00283 v = valueMakeString( xstrdup(temp) );
00284
00285 } else if (*p == '\"') {
00286 char temp[EXPRBUFSIZ], *t = temp;
00287
00288 temp[0] = '\0';
00289 p++;
00290 while (*p && *p != '\"')
00291 *t++ = *p++;
00292 *t++ = '\0';
00293
00294 token = TOK_STRING;
00295 v = valueMakeString( rpmExpand(temp, NULL) );
00296
00297 } else {
00298 rpmError(RPMERR_BADSPEC, _("parse error in expression\n"));
00299 return -1;
00300 }
00301 }
00302
00303 state->p = p + 1;
00304 state->nextToken = token;
00305 state->tokenValue = v;
00306
00307 DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token));
00308 DEBUG(valueDump("rdToken:", state->tokenValue, stdout));
00309
00310 return 0;
00311 }
00312
00313 static Value doLogical(ParseState state);
00314
00318 static Value doPrimary(ParseState state)
00319 {
00320 Value v;
00321
00322 DEBUG(printf("doPrimary()\n"));
00323
00324 switch (state->nextToken) {
00325 case TOK_OPEN_P:
00326 if (rdToken(state))
00327 return NULL;
00328 v = doLogical(state);
00329 if (state->nextToken != TOK_CLOSE_P) {
00330 rpmError(RPMERR_BADSPEC, _("unmatched (\n"));
00331 return NULL;
00332 }
00333 break;
00334
00335 case TOK_INTEGER:
00336 case TOK_STRING:
00337 v = state->tokenValue;
00338 if (rdToken(state))
00339 return NULL;
00340 break;
00341
00342 case TOK_IDENTIFIER: {
00343 const char *name = state->tokenValue->data.s;
00344
00345 v = valueMakeString( rpmExpand(name, NULL) );
00346 if (rdToken(state))
00347 return NULL;
00348 break;
00349 }
00350
00351 case TOK_MINUS:
00352 if (rdToken(state))
00353 return NULL;
00354
00355 v = doPrimary(state);
00356 if (v == NULL)
00357 return NULL;
00358
00359 if (! valueIsInteger(v)) {
00360 rpmError(RPMERR_BADSPEC, _("- only on numbers\n"));
00361 return NULL;
00362 }
00363
00364 v = valueMakeInteger(- v->data.i);
00365 break;
00366
00367 case TOK_NOT:
00368 if (rdToken(state))
00369 return NULL;
00370
00371 v = doPrimary(state);
00372 if (v == NULL)
00373 return NULL;
00374
00375 if (! valueIsInteger(v)) {
00376 rpmError(RPMERR_BADSPEC, _("! only on numbers\n"));
00377 return NULL;
00378 }
00379
00380 v = valueMakeInteger(! v->data.i);
00381 break;
00382 default:
00383 return NULL;
00384 break;
00385 }
00386
00387 DEBUG(valueDump("doPrimary:", v, stdout));
00388 return v;
00389 }
00390
00394 static Value doMultiplyDivide(ParseState state)
00395 {
00396 Value v1, v2 = NULL;
00397
00398 DEBUG(printf("doMultiplyDivide()\n"));
00399
00400 v1 = doPrimary(state);
00401 if (v1 == NULL)
00402 return NULL;
00403
00404 while (state->nextToken == TOK_MULTIPLY
00405 || state->nextToken == TOK_DIVIDE) {
00406 int op = state->nextToken;
00407
00408 if (rdToken(state))
00409 return NULL;
00410
00411 if (v2) valueFree(v2);
00412
00413 v2 = doPrimary(state);
00414 if (v2 == NULL)
00415 return NULL;
00416
00417 if (! valueSameType(v1, v2)) {
00418 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00419 return NULL;
00420 }
00421
00422 if (valueIsInteger(v1)) {
00423 int i1 = v1->data.i, i2 = v2->data.i;
00424
00425 valueFree(v1);
00426 if (op == TOK_MULTIPLY)
00427 v1 = valueMakeInteger(i1 * i2);
00428 else
00429 v1 = valueMakeInteger(i1 / i2);
00430 } else {
00431 rpmError(RPMERR_BADSPEC, _("* / not suported for strings\n"));
00432 return NULL;
00433 }
00434 }
00435
00436 if (v2) valueFree(v2);
00437 return v1;
00438 }
00439
00443 static Value doAddSubtract(ParseState state)
00444 {
00445 Value v1, v2 = NULL;
00446
00447 DEBUG(printf("doAddSubtract()\n"));
00448
00449 v1 = doMultiplyDivide(state);
00450 if (v1 == NULL)
00451 return NULL;
00452
00453 while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00454 int op = state->nextToken;
00455
00456 if (rdToken(state))
00457 return NULL;
00458
00459 if (v2) valueFree(v2);
00460
00461 v2 = doMultiplyDivide(state);
00462 if (v2 == NULL)
00463 return NULL;
00464
00465 if (! valueSameType(v1, v2)) {
00466 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00467 return NULL;
00468 }
00469
00470 if (valueIsInteger(v1)) {
00471 int i1 = v1->data.i, i2 = v2->data.i;
00472
00473 valueFree(v1);
00474 if (op == TOK_ADD)
00475 v1 = valueMakeInteger(i1 + i2);
00476 else
00477 v1 = valueMakeInteger(i1 - i2);
00478 } else {
00479 char *copy;
00480
00481 if (op == TOK_MINUS) {
00482 rpmError(RPMERR_BADSPEC, _("- not suported for strings\n"));
00483 return NULL;
00484 }
00485
00486 copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00487 (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00488
00489 valueFree(v1);
00490 v1 = valueMakeString(copy);
00491 }
00492 }
00493
00494 if (v2) valueFree(v2);
00495 return v1;
00496 }
00497
00501 static Value doRelational(ParseState state)
00502 {
00503 Value v1, v2 = NULL;
00504
00505 DEBUG(printf("doRelational()\n"));
00506
00507 v1 = doAddSubtract(state);
00508 if (v1 == NULL)
00509 return NULL;
00510
00511 while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00512 int op = state->nextToken;
00513
00514 if (rdToken(state))
00515 return NULL;
00516
00517 if (v2) valueFree(v2);
00518
00519 v2 = doAddSubtract(state);
00520 if (v2 == NULL)
00521 return NULL;
00522
00523 if (! valueSameType(v1, v2)) {
00524 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00525 return NULL;
00526 }
00527
00528 if (valueIsInteger(v1)) {
00529 int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00530 switch (op) {
00531 case TOK_EQ:
00532 r = (i1 == i2);
00533 break;
00534 case TOK_NEQ:
00535 r = (i1 != i2);
00536 break;
00537 case TOK_LT:
00538 r = (i1 < i2);
00539 break;
00540 case TOK_LE:
00541 r = (i1 <= i2);
00542 break;
00543 case TOK_GT:
00544 r = (i1 > i2);
00545 break;
00546 case TOK_GE:
00547 r = (i1 >= i2);
00548 break;
00549 default:
00550 break;
00551 }
00552 valueFree(v1);
00553 v1 = valueMakeInteger(r);
00554 } else {
00555 const char * s1 = v1->data.s;
00556 const char * s2 = v2->data.s;
00557 int r = 0;
00558 switch (op) {
00559 case TOK_EQ:
00560 r = (strcmp(s1,s2) == 0);
00561 break;
00562 case TOK_NEQ:
00563 r = (strcmp(s1,s2) != 0);
00564 break;
00565 case TOK_LT:
00566 r = (strcmp(s1,s2) < 0);
00567 break;
00568 case TOK_LE:
00569 r = (strcmp(s1,s2) <= 0);
00570 break;
00571 case TOK_GT:
00572 r = (strcmp(s1,s2) > 0);
00573 break;
00574 case TOK_GE:
00575 r = (strcmp(s1,s2) >= 0);
00576 break;
00577 default:
00578 break;
00579 }
00580 valueFree(v1);
00581 v1 = valueMakeInteger(r);
00582 }
00583 }
00584
00585 if (v2) valueFree(v2);
00586 return v1;
00587 }
00588
00592 static Value doLogical(ParseState state)
00593 {
00594 Value v1, v2 = NULL;
00595
00596 DEBUG(printf("doLogical()\n"));
00597
00598 v1 = doRelational(state);
00599 if (v1 == NULL)
00600 return NULL;
00601
00602 while (state->nextToken == TOK_LOGICAL_AND
00603 || state->nextToken == TOK_LOGICAL_OR) {
00604 int op = state->nextToken;
00605
00606 if (rdToken(state))
00607 return NULL;
00608
00609 if (v2) valueFree(v2);
00610
00611 v2 = doRelational(state);
00612 if (v2 == NULL)
00613 return NULL;
00614
00615 if (! valueSameType(v1, v2)) {
00616 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00617 return NULL;
00618 }
00619
00620 if (valueIsInteger(v1)) {
00621 int i1 = v1->data.i, i2 = v2->data.i;
00622
00623 valueFree(v1);
00624 if (op == TOK_LOGICAL_AND)
00625 v1 = valueMakeInteger(i1 && i2);
00626 else
00627 v1 = valueMakeInteger(i1 || i2);
00628 } else {
00629 rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings\n"));
00630 return NULL;
00631 }
00632 }
00633
00634 if (v2) valueFree(v2);
00635 return v1;
00636 }
00637
00638 int parseExpressionBoolean(Spec spec, const char *expr)
00639 {
00640 struct _parseState state;
00641 int result = -1;
00642 Value v;
00643
00644 DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00645
00646
00647 state.p = state.str = xstrdup(expr);
00648 state.spec = spec;
00649 state.nextToken = 0;
00650 state.tokenValue = NULL;
00651 (void) rdToken(&state);
00652
00653
00654 v = doLogical(&state);
00655 if (!v) {
00656 state.str = _free(state.str);
00657 return -1;
00658 }
00659
00660
00661 if (state.nextToken != TOK_EOF) {
00662 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00663 state.str = _free(state.str);
00664 return -1;
00665 }
00666
00667 DEBUG(valueDump("parseExprBoolean:", v, stdout));
00668
00669 switch (v->type) {
00670 case VALUE_TYPE_INTEGER:
00671 result = v->data.i != 0;
00672 break;
00673 case VALUE_TYPE_STRING:
00674 result = v->data.s[0] != '\0';
00675 break;
00676 default:
00677 break;
00678 }
00679
00680 state.str = _free(state.str);
00681 valueFree(v);
00682 return result;
00683 }
00684
00685 char * parseExpressionString(Spec spec, const char *expr)
00686 {
00687 struct _parseState state;
00688 char *result = NULL;
00689 Value v;
00690
00691 DEBUG(printf("parseExprString(?, '%s')\n", expr));
00692
00693
00694 state.p = state.str = xstrdup(expr);
00695 state.spec = spec;
00696 state.nextToken = 0;
00697 state.tokenValue = NULL;
00698 (void) rdToken(&state);
00699
00700
00701 v = doLogical(&state);
00702 if (!v) {
00703 state.str = _free(state.str);
00704 return NULL;
00705 }
00706
00707
00708 if (state.nextToken != TOK_EOF) {
00709 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00710 state.str = _free(state.str);
00711 return NULL;
00712 }
00713
00714 DEBUG(valueDump("parseExprString:", v, stdout));
00715
00716 switch (v->type) {
00717 case VALUE_TYPE_INTEGER: {
00718 char buf[128];
00719 sprintf(buf, "%d", v->data.i);
00720 result = xstrdup(buf);
00721 } break;
00722 case VALUE_TYPE_STRING:
00723 result = xstrdup(v->data.s);
00724 break;
00725 default:
00726 break;
00727 }
00728
00729 state.str = _free(state.str);
00730 valueFree(v);
00731 return result;
00732 }