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