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 {
00046 Value v;
00047
00048 v = (Value) xmalloc(sizeof(*v));
00049 v->type = VALUE_TYPE_INTEGER;
00050 v->data.i = i;
00051 return v;
00052 }
00053
00056 static Value valueMakeString( const char *s)
00057
00058 {
00059 Value v;
00060
00061 v = (Value) xmalloc(sizeof(*v));
00062 v->type = VALUE_TYPE_STRING;
00063 v->data.s = s;
00064 return v;
00065 }
00066
00069 static void valueFree( Value v)
00070
00071 {
00072 if (v) {
00073 if (v->type == VALUE_TYPE_STRING)
00074 v->data.s = _free(v->data.s);
00075 v = _free(v);
00076 }
00077 }
00078
00079 #ifdef DEBUG_PARSER
00080 static void valueDump(const char *msg, Value v, FILE *fp)
00081
00082 {
00083 if (msg)
00084 fprintf(fp, "%s ", msg);
00085 if (v) {
00086 if (v->type == VALUE_TYPE_INTEGER)
00087 fprintf(fp, "INTEGER %d\n", v->data.i);
00088 else
00089 fprintf(fp, "STRING '%s'\n", v->data.s);
00090 } else
00091 fprintf(fp, "NULL\n");
00092 }
00093 #endif
00094
00095 #define valueIsInteger(v) ((v)->type == VALUE_TYPE_INTEGER)
00096 #define valueIsString(v) ((v)->type == VALUE_TYPE_STRING)
00097 #define valueSameType(v1,v2) ((v1)->type == (v2)->type)
00098
00099
00103 typedef struct _parseState {
00104
00105 char *str;
00106
00107 char *p;
00108 int nextToken;
00109
00110 Value tokenValue;
00111 Spec spec;
00112 } *ParseState;
00113
00114
00119 #define TOK_EOF 1
00120 #define TOK_INTEGER 2
00121 #define TOK_STRING 3
00122 #define TOK_IDENTIFIER 4
00123 #define TOK_ADD 5
00124 #define TOK_MINUS 6
00125 #define TOK_MULTIPLY 7
00126 #define TOK_DIVIDE 8
00127 #define TOK_OPEN_P 9
00128 #define TOK_CLOSE_P 10
00129 #define TOK_EQ 11
00130 #define TOK_NEQ 12
00131 #define TOK_LT 13
00132 #define TOK_LE 14
00133 #define TOK_GT 15
00134 #define TOK_GE 16
00135 #define TOK_NOT 17
00136 #define TOK_LOGICAL_AND 18
00137 #define TOK_LOGICAL_OR 19
00138
00140 #define EXPRBUFSIZ BUFSIZ
00141
00142 #if defined(DEBUG_PARSER)
00143 typedef struct exprTokTableEntry {
00144 const char *name;
00145 int val;
00146 } ETTE_t;
00147
00148 ETTE_t exprTokTable[] = {
00149 { "EOF", TOK_EOF },
00150 { "I", TOK_INTEGER },
00151 { "S", TOK_STRING },
00152 { "ID", TOK_IDENTIFIER },
00153 { "+", TOK_ADD },
00154 { "-", TOK_MINUS },
00155 { "*", TOK_MULTIPLY },
00156 { "/", TOK_DIVIDE },
00157 { "( ", TOK_OPEN_P },
00158 { " )", TOK_CLOSE_P },
00159 { "==", TOK_EQ },
00160 { "!=", TOK_NEQ },
00161 { "<", TOK_LT },
00162 { "<=", TOK_LE },
00163 { ">", TOK_GT },
00164 { ">=", TOK_GE },
00165 { "!", TOK_NOT },
00166 { "&&", TOK_LOGICAL_AND },
00167 { "||", TOK_LOGICAL_OR },
00168 { NULL, 0 }
00169 };
00170
00171 static const char *prToken(int val)
00172
00173 {
00174 ETTE_t *et;
00175
00176 for (et = exprTokTable; et->name != NULL; et++) {
00177 if (val == et->val)
00178 return et->name;
00179 }
00180 return "???";
00181 }
00182 #endif
00183
00187
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 rpmError(RPMERR_BADSPEC, _("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 rpmError(RPMERR_BADSPEC, _("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 rpmError(RPMERR_BADSPEC, _("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 rpmError(RPMERR_BADSPEC, _("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
00327 static Value doLogical(ParseState state)
00328
00329
00330 ;
00331
00335
00336 static Value doPrimary(ParseState state)
00337
00338
00339
00340 {
00341 Value v;
00342
00343 DEBUG(printf("doPrimary()\n"));
00344
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 rpmError(RPMERR_BADSPEC, _("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 rpmError(RPMERR_BADSPEC, _("- 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 rpmError(RPMERR_BADSPEC, _("! 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
00412 DEBUG(valueDump("doPrimary:", v, stdout));
00413 return v;
00414 }
00415
00419
00420 static Value doMultiplyDivide(ParseState state)
00421
00422
00423
00424 {
00425 Value v1, v2 = NULL;
00426
00427 DEBUG(printf("doMultiplyDivide()\n"));
00428
00429 v1 = doPrimary(state);
00430 if (v1 == NULL)
00431 return NULL;
00432
00433
00434 while (state->nextToken == TOK_MULTIPLY
00435 || state->nextToken == TOK_DIVIDE) {
00436 int op = state->nextToken;
00437
00438 if (rdToken(state))
00439 return NULL;
00440
00441 if (v2) valueFree(v2);
00442
00443 v2 = doPrimary(state);
00444 if (v2 == NULL)
00445 return NULL;
00446
00447 if (! valueSameType(v1, v2)) {
00448 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00449 return NULL;
00450 }
00451
00452 if (valueIsInteger(v1)) {
00453 int i1 = v1->data.i, i2 = v2->data.i;
00454
00455 valueFree(v1);
00456 if (op == TOK_MULTIPLY)
00457 v1 = valueMakeInteger(i1 * i2);
00458 else
00459 v1 = valueMakeInteger(i1 / i2);
00460 } else {
00461 rpmError(RPMERR_BADSPEC, _("* / not suported for strings\n"));
00462 return NULL;
00463 }
00464 }
00465
00466
00467 if (v2) valueFree(v2);
00468 return v1;
00469 }
00470
00474
00475
00476 static Value doAddSubtract(ParseState state)
00477
00478
00479
00480 {
00481 Value v1, v2 = NULL;
00482
00483 DEBUG(printf("doAddSubtract()\n"));
00484
00485 v1 = doMultiplyDivide(state);
00486 if (v1 == NULL)
00487 return NULL;
00488
00489
00490 while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00491 int op = state->nextToken;
00492
00493 if (rdToken(state))
00494 return NULL;
00495
00496 if (v2) valueFree(v2);
00497
00498 v2 = doMultiplyDivide(state);
00499 if (v2 == NULL)
00500 return NULL;
00501
00502 if (! valueSameType(v1, v2)) {
00503 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00504 return NULL;
00505 }
00506
00507 if (valueIsInteger(v1)) {
00508 int i1 = v1->data.i, i2 = v2->data.i;
00509
00510 valueFree(v1);
00511 if (op == TOK_ADD)
00512 v1 = valueMakeInteger(i1 + i2);
00513 else
00514 v1 = valueMakeInteger(i1 - i2);
00515 } else {
00516 char *copy;
00517
00518 if (op == TOK_MINUS) {
00519 rpmError(RPMERR_BADSPEC, _("- not suported for strings\n"));
00520 return NULL;
00521 }
00522
00523 copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00524 (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00525
00526 valueFree(v1);
00527 v1 = valueMakeString(copy);
00528 }
00529 }
00530
00531
00532 if (v2) valueFree(v2);
00533 return v1;
00534 }
00535
00536
00540
00541 static Value doRelational(ParseState state)
00542
00543
00544
00545 {
00546 Value v1, v2 = NULL;
00547
00548 DEBUG(printf("doRelational()\n"));
00549
00550 v1 = doAddSubtract(state);
00551 if (v1 == NULL)
00552 return NULL;
00553
00554
00555 while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00556 int op = state->nextToken;
00557
00558 if (rdToken(state))
00559 return NULL;
00560
00561 if (v2) valueFree(v2);
00562
00563 v2 = doAddSubtract(state);
00564 if (v2 == NULL)
00565 return NULL;
00566
00567 if (! valueSameType(v1, v2)) {
00568 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00569 return NULL;
00570 }
00571
00572 if (valueIsInteger(v1)) {
00573 int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00574 switch (op) {
00575 case TOK_EQ:
00576 r = (i1 == i2);
00577 break;
00578 case TOK_NEQ:
00579 r = (i1 != i2);
00580 break;
00581 case TOK_LT:
00582 r = (i1 < i2);
00583 break;
00584 case TOK_LE:
00585 r = (i1 <= i2);
00586 break;
00587 case TOK_GT:
00588 r = (i1 > i2);
00589 break;
00590 case TOK_GE:
00591 r = (i1 >= i2);
00592 break;
00593 default:
00594 break;
00595 }
00596 valueFree(v1);
00597 v1 = valueMakeInteger(r);
00598 } else {
00599 const char * s1 = v1->data.s;
00600 const char * s2 = v2->data.s;
00601 int r = 0;
00602 switch (op) {
00603 case TOK_EQ:
00604 r = (strcmp(s1,s2) == 0);
00605 break;
00606 case TOK_NEQ:
00607 r = (strcmp(s1,s2) != 0);
00608 break;
00609 case TOK_LT:
00610 r = (strcmp(s1,s2) < 0);
00611 break;
00612 case TOK_LE:
00613 r = (strcmp(s1,s2) <= 0);
00614 break;
00615 case TOK_GT:
00616 r = (strcmp(s1,s2) > 0);
00617 break;
00618 case TOK_GE:
00619 r = (strcmp(s1,s2) >= 0);
00620 break;
00621 default:
00622 break;
00623 }
00624 valueFree(v1);
00625 v1 = valueMakeInteger(r);
00626 }
00627 }
00628
00629
00630 if (v2) valueFree(v2);
00631 return v1;
00632 }
00633
00637 static Value doLogical(ParseState state)
00638
00639
00640
00641 {
00642 Value v1, v2 = NULL;
00643
00644 DEBUG(printf("doLogical()\n"));
00645
00646 v1 = doRelational(state);
00647 if (v1 == NULL)
00648 return NULL;
00649
00650
00651 while (state->nextToken == TOK_LOGICAL_AND
00652 || state->nextToken == TOK_LOGICAL_OR) {
00653 int op = state->nextToken;
00654
00655 if (rdToken(state))
00656 return NULL;
00657
00658 if (v2) valueFree(v2);
00659
00660 v2 = doRelational(state);
00661 if (v2 == NULL)
00662 return NULL;
00663
00664 if (! valueSameType(v1, v2)) {
00665 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00666 return NULL;
00667 }
00668
00669 if (valueIsInteger(v1)) {
00670 int i1 = v1->data.i, i2 = v2->data.i;
00671
00672 valueFree(v1);
00673 if (op == TOK_LOGICAL_AND)
00674 v1 = valueMakeInteger(i1 && i2);
00675 else
00676 v1 = valueMakeInteger(i1 || i2);
00677 } else {
00678 rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings\n"));
00679 return NULL;
00680 }
00681 }
00682
00683
00684 if (v2) valueFree(v2);
00685 return v1;
00686 }
00687
00688 int parseExpressionBoolean(Spec spec, const char *expr)
00689 {
00690 struct _parseState state;
00691 int result = -1;
00692 Value v;
00693
00694 DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00695
00696
00697 state.p = state.str = xstrdup(expr);
00698 state.spec = spec;
00699 state.nextToken = 0;
00700 state.tokenValue = NULL;
00701 (void) rdToken(&state);
00702
00703
00704 v = doLogical(&state);
00705 if (!v) {
00706 state.str = _free(state.str);
00707 return -1;
00708 }
00709
00710
00711 if (state.nextToken != TOK_EOF) {
00712 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00713 state.str = _free(state.str);
00714 return -1;
00715 }
00716
00717 DEBUG(valueDump("parseExprBoolean:", v, stdout));
00718
00719 switch (v->type) {
00720 case VALUE_TYPE_INTEGER:
00721 result = v->data.i != 0;
00722 break;
00723 case VALUE_TYPE_STRING:
00724
00725 result = v->data.s[0] != '\0';
00726
00727 break;
00728 default:
00729 break;
00730 }
00731
00732 state.str = _free(state.str);
00733 valueFree(v);
00734 return result;
00735 }
00736
00737 char * parseExpressionString(Spec spec, const char *expr)
00738 {
00739 struct _parseState state;
00740 char *result = NULL;
00741 Value v;
00742
00743 DEBUG(printf("parseExprString(?, '%s')\n", expr));
00744
00745
00746 state.p = state.str = xstrdup(expr);
00747 state.spec = spec;
00748 state.nextToken = 0;
00749 state.tokenValue = NULL;
00750 (void) rdToken(&state);
00751
00752
00753 v = doLogical(&state);
00754 if (!v) {
00755 state.str = _free(state.str);
00756 return NULL;
00757 }
00758
00759
00760 if (state.nextToken != TOK_EOF) {
00761 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00762 state.str = _free(state.str);
00763 return NULL;
00764 }
00765
00766 DEBUG(valueDump("parseExprString:", v, stdout));
00767
00768
00769 switch (v->type) {
00770 case VALUE_TYPE_INTEGER: {
00771 char buf[128];
00772 sprintf(buf, "%d", v->data.i);
00773 result = xstrdup(buf);
00774 } break;
00775 case VALUE_TYPE_STRING:
00776 result = xstrdup(v->data.s);
00777 break;
00778 default:
00779 break;
00780 }
00781
00782
00783 state.str = _free(state.str);
00784 valueFree(v);
00785 return result;
00786 }