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