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