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 break;
00356
00357 case TOK_INTEGER:
00358 case TOK_STRING:
00359 v = state->tokenValue;
00360 if (rdToken(state))
00361 return NULL;
00362 break;
00363
00364 case TOK_IDENTIFIER: {
00365 const char *name = state->tokenValue->data.s;
00366
00367 v = valueMakeString( rpmExpand(name, NULL) );
00368 if (rdToken(state))
00369 return NULL;
00370 break;
00371 }
00372
00373 case TOK_MINUS:
00374 if (rdToken(state))
00375 return NULL;
00376
00377 v = doPrimary(state);
00378 if (v == NULL)
00379 return NULL;
00380
00381 if (! valueIsInteger(v)) {
00382 rpmError(RPMERR_BADSPEC, _("- only on numbers\n"));
00383 return NULL;
00384 }
00385
00386 v = valueMakeInteger(- v->data.i);
00387 break;
00388
00389 case TOK_NOT:
00390 if (rdToken(state))
00391 return NULL;
00392
00393 v = doPrimary(state);
00394 if (v == NULL)
00395 return NULL;
00396
00397 if (! valueIsInteger(v)) {
00398 rpmError(RPMERR_BADSPEC, _("! only on numbers\n"));
00399 return NULL;
00400 }
00401
00402 v = valueMakeInteger(! v->data.i);
00403 break;
00404 default:
00405 return NULL;
00406 break;
00407 }
00408
00409
00410 DEBUG(valueDump("doPrimary:", v, stdout));
00411 return v;
00412 }
00413
00417
00418 static Value doMultiplyDivide(ParseState state)
00419
00420
00421
00422 {
00423 Value v1, v2 = NULL;
00424
00425 DEBUG(printf("doMultiplyDivide()\n"));
00426
00427 v1 = doPrimary(state);
00428 if (v1 == NULL)
00429 return NULL;
00430
00431
00432 while (state->nextToken == TOK_MULTIPLY
00433 || state->nextToken == TOK_DIVIDE) {
00434 int op = state->nextToken;
00435
00436 if (rdToken(state))
00437 return NULL;
00438
00439 if (v2) valueFree(v2);
00440
00441 v2 = doPrimary(state);
00442 if (v2 == NULL)
00443 return NULL;
00444
00445 if (! valueSameType(v1, v2)) {
00446 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00447 return NULL;
00448 }
00449
00450 if (valueIsInteger(v1)) {
00451 int i1 = v1->data.i, i2 = v2->data.i;
00452
00453 valueFree(v1);
00454 if (op == TOK_MULTIPLY)
00455 v1 = valueMakeInteger(i1 * i2);
00456 else
00457 v1 = valueMakeInteger(i1 / i2);
00458 } else {
00459 rpmError(RPMERR_BADSPEC, _("* / not suported for strings\n"));
00460 return NULL;
00461 }
00462 }
00463
00464
00465 if (v2) valueFree(v2);
00466 return v1;
00467 }
00468
00472
00473
00474 static Value doAddSubtract(ParseState state)
00475
00476
00477
00478 {
00479 Value v1, v2 = NULL;
00480
00481 DEBUG(printf("doAddSubtract()\n"));
00482
00483 v1 = doMultiplyDivide(state);
00484 if (v1 == NULL)
00485 return NULL;
00486
00487
00488 while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) {
00489 int op = state->nextToken;
00490
00491 if (rdToken(state))
00492 return NULL;
00493
00494 if (v2) valueFree(v2);
00495
00496 v2 = doMultiplyDivide(state);
00497 if (v2 == NULL)
00498 return NULL;
00499
00500 if (! valueSameType(v1, v2)) {
00501 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00502 return NULL;
00503 }
00504
00505 if (valueIsInteger(v1)) {
00506 int i1 = v1->data.i, i2 = v2->data.i;
00507
00508 valueFree(v1);
00509 if (op == TOK_ADD)
00510 v1 = valueMakeInteger(i1 + i2);
00511 else
00512 v1 = valueMakeInteger(i1 - i2);
00513 } else {
00514 char *copy;
00515
00516 if (op == TOK_MINUS) {
00517 rpmError(RPMERR_BADSPEC, _("- not suported for strings\n"));
00518 return NULL;
00519 }
00520
00521 copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1);
00522 (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s);
00523
00524 valueFree(v1);
00525 v1 = valueMakeString(copy);
00526 }
00527 }
00528
00529
00530 if (v2) valueFree(v2);
00531 return v1;
00532 }
00533
00534
00538
00539 static Value doRelational(ParseState state)
00540
00541
00542
00543 {
00544 Value v1, v2 = NULL;
00545
00546 DEBUG(printf("doRelational()\n"));
00547
00548 v1 = doAddSubtract(state);
00549 if (v1 == NULL)
00550 return NULL;
00551
00552
00553 while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) {
00554 int op = state->nextToken;
00555
00556 if (rdToken(state))
00557 return NULL;
00558
00559 if (v2) valueFree(v2);
00560
00561 v2 = doAddSubtract(state);
00562 if (v2 == NULL)
00563 return NULL;
00564
00565 if (! valueSameType(v1, v2)) {
00566 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00567 return NULL;
00568 }
00569
00570 if (valueIsInteger(v1)) {
00571 int i1 = v1->data.i, i2 = v2->data.i, r = 0;
00572 switch (op) {
00573 case TOK_EQ:
00574 r = (i1 == i2);
00575 break;
00576 case TOK_NEQ:
00577 r = (i1 != i2);
00578 break;
00579 case TOK_LT:
00580 r = (i1 < i2);
00581 break;
00582 case TOK_LE:
00583 r = (i1 <= i2);
00584 break;
00585 case TOK_GT:
00586 r = (i1 > i2);
00587 break;
00588 case TOK_GE:
00589 r = (i1 >= i2);
00590 break;
00591 default:
00592 break;
00593 }
00594 valueFree(v1);
00595 v1 = valueMakeInteger(r);
00596 } else {
00597 const char * s1 = v1->data.s;
00598 const char * s2 = v2->data.s;
00599 int r = 0;
00600 switch (op) {
00601 case TOK_EQ:
00602 r = (strcmp(s1,s2) == 0);
00603 break;
00604 case TOK_NEQ:
00605 r = (strcmp(s1,s2) != 0);
00606 break;
00607 case TOK_LT:
00608 r = (strcmp(s1,s2) < 0);
00609 break;
00610 case TOK_LE:
00611 r = (strcmp(s1,s2) <= 0);
00612 break;
00613 case TOK_GT:
00614 r = (strcmp(s1,s2) > 0);
00615 break;
00616 case TOK_GE:
00617 r = (strcmp(s1,s2) >= 0);
00618 break;
00619 default:
00620 break;
00621 }
00622 valueFree(v1);
00623 v1 = valueMakeInteger(r);
00624 }
00625 }
00626
00627
00628 if (v2) valueFree(v2);
00629 return v1;
00630 }
00631
00635 static Value doLogical(ParseState state)
00636
00637
00638
00639 {
00640 Value v1, v2 = NULL;
00641
00642 DEBUG(printf("doLogical()\n"));
00643
00644 v1 = doRelational(state);
00645 if (v1 == NULL)
00646 return NULL;
00647
00648
00649 while (state->nextToken == TOK_LOGICAL_AND
00650 || state->nextToken == TOK_LOGICAL_OR) {
00651 int op = state->nextToken;
00652
00653 if (rdToken(state))
00654 return NULL;
00655
00656 if (v2) valueFree(v2);
00657
00658 v2 = doRelational(state);
00659 if (v2 == NULL)
00660 return NULL;
00661
00662 if (! valueSameType(v1, v2)) {
00663 rpmError(RPMERR_BADSPEC, _("types must match\n"));
00664 return NULL;
00665 }
00666
00667 if (valueIsInteger(v1)) {
00668 int i1 = v1->data.i, i2 = v2->data.i;
00669
00670 valueFree(v1);
00671 if (op == TOK_LOGICAL_AND)
00672 v1 = valueMakeInteger(i1 && i2);
00673 else
00674 v1 = valueMakeInteger(i1 || i2);
00675 } else {
00676 rpmError(RPMERR_BADSPEC, _("&& and || not suported for strings\n"));
00677 return NULL;
00678 }
00679 }
00680
00681
00682 if (v2) valueFree(v2);
00683 return v1;
00684 }
00685
00686 int parseExpressionBoolean(Spec spec, const char *expr)
00687 {
00688 struct _parseState state;
00689 int result = -1;
00690 Value v;
00691
00692 DEBUG(printf("parseExprBoolean(?, '%s')\n", expr));
00693
00694
00695 state.p = state.str = xstrdup(expr);
00696 state.spec = spec;
00697 state.nextToken = 0;
00698 state.tokenValue = NULL;
00699 (void) rdToken(&state);
00700
00701
00702 v = doLogical(&state);
00703 if (!v) {
00704 state.str = _free(state.str);
00705 return -1;
00706 }
00707
00708
00709 if (state.nextToken != TOK_EOF) {
00710 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00711 state.str = _free(state.str);
00712 return -1;
00713 }
00714
00715 DEBUG(valueDump("parseExprBoolean:", v, stdout));
00716
00717 switch (v->type) {
00718 case VALUE_TYPE_INTEGER:
00719 result = v->data.i != 0;
00720 break;
00721 case VALUE_TYPE_STRING:
00722
00723 result = v->data.s[0] != '\0';
00724
00725 break;
00726 default:
00727 break;
00728 }
00729
00730 state.str = _free(state.str);
00731 valueFree(v);
00732 return result;
00733 }
00734
00735 char * parseExpressionString(Spec spec, const char *expr)
00736 {
00737 struct _parseState state;
00738 char *result = NULL;
00739 Value v;
00740
00741 DEBUG(printf("parseExprString(?, '%s')\n", expr));
00742
00743
00744 state.p = state.str = xstrdup(expr);
00745 state.spec = spec;
00746 state.nextToken = 0;
00747 state.tokenValue = NULL;
00748 (void) rdToken(&state);
00749
00750
00751 v = doLogical(&state);
00752 if (!v) {
00753 state.str = _free(state.str);
00754 return NULL;
00755 }
00756
00757
00758 if (state.nextToken != TOK_EOF) {
00759 rpmError(RPMERR_BADSPEC, _("syntax error in expression\n"));
00760 state.str = _free(state.str);
00761 return NULL;
00762 }
00763
00764 DEBUG(valueDump("parseExprString:", v, stdout));
00765
00766
00767 switch (v->type) {
00768 case VALUE_TYPE_INTEGER: {
00769 char buf[128];
00770 sprintf(buf, "%d", v->data.i);
00771 result = xstrdup(buf);
00772 } break;
00773 case VALUE_TYPE_STRING:
00774 result = xstrdup(v->data.s);
00775 break;
00776 default:
00777 break;
00778 }
00779
00780
00781 state.str = _free(state.str);
00782 valueFree(v);
00783 return result;
00784 }