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