rpm
4.5
|
00001 00014 #include "system.h" 00015 00016 #include <rpmbuild.h> 00017 #include <rpmlib.h> 00018 00019 #include "debug.h" 00020 00021 /* #define DEBUG_PARSER 1 */ 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(/*@only@*/ 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( /*@only@*/ Value v) 00070 /*@modifies v @*/ 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 /*@owned@*/ 00105 char *str; 00106 /*@dependent@*/ 00107 char *p; 00108 int nextToken; 00109 /*@relnull@*/ 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 /* DEBUG_PARSER */ 00183 00187 /*@-boundswrite@*/ 00188 static int rdToken(ParseState state) 00189 /*@globals rpmGlobalMacroContext, h_errno @*/ 00190 /*@modifies state->nextToken, state->p, state->tokenValue, 00191 rpmGlobalMacroContext @*/ 00192 { 00193 int token; 00194 Value v = NULL; 00195 char *p = state->p; 00196 00197 /* Skip whitespace before the next token. */ 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 /*@=boundswrite@*/ 00325 00326 /*@null@*/ 00327 static Value doLogical(ParseState state) 00328 /*@globals rpmGlobalMacroContext, h_errno @*/ 00329 /*@modifies state->nextToken, state->p, state->tokenValue, 00330 rpmGlobalMacroContext @*/; 00331 00335 /*@null@*/ 00336 static Value doPrimary(ParseState state) 00337 /*@globals rpmGlobalMacroContext, h_errno @*/ 00338 /*@modifies state->nextToken, state->p, state->tokenValue, 00339 rpmGlobalMacroContext @*/ 00340 { 00341 Value v; 00342 00343 DEBUG(printf("doPrimary()\n")); 00344 00345 /*@-branchstate@*/ 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 /*@notreached@*/ break; 00409 } 00410 /*@=branchstate@*/ 00411 00412 DEBUG(valueDump("doPrimary:", v, stdout)); 00413 return v; 00414 } 00415 00419 /*@null@*/ 00420 static Value doMultiplyDivide(ParseState state) 00421 /*@globals rpmGlobalMacroContext, h_errno @*/ 00422 /*@modifies state->nextToken, state->p, state->tokenValue, 00423 rpmGlobalMacroContext @*/ 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 /*@-branchstate@*/ 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 /*@=branchstate@*/ 00466 00467 if (v2) valueFree(v2); 00468 return v1; 00469 } 00470 00474 /*@-boundswrite@*/ 00475 /*@null@*/ 00476 static Value doAddSubtract(ParseState state) 00477 /*@globals rpmGlobalMacroContext, h_errno @*/ 00478 /*@modifies state->nextToken, state->p, state->tokenValue, 00479 rpmGlobalMacroContext @*/ 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 /*@-branchstate@*/ 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 /*@=branchstate@*/ 00531 00532 if (v2) valueFree(v2); 00533 return v1; 00534 } 00535 /*@=boundswrite@*/ 00536 00540 /*@null@*/ 00541 static Value doRelational(ParseState state) 00542 /*@globals rpmGlobalMacroContext, h_errno @*/ 00543 /*@modifies state->nextToken, state->p, state->tokenValue, 00544 rpmGlobalMacroContext @*/ 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 /*@-branchstate@*/ 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 /*@switchbreak@*/ break; 00578 case TOK_NEQ: 00579 r = (i1 != i2); 00580 /*@switchbreak@*/ break; 00581 case TOK_LT: 00582 r = (i1 < i2); 00583 /*@switchbreak@*/ break; 00584 case TOK_LE: 00585 r = (i1 <= i2); 00586 /*@switchbreak@*/ break; 00587 case TOK_GT: 00588 r = (i1 > i2); 00589 /*@switchbreak@*/ break; 00590 case TOK_GE: 00591 r = (i1 >= i2); 00592 /*@switchbreak@*/ break; 00593 default: 00594 /*@switchbreak@*/ 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 /*@switchbreak@*/ break; 00606 case TOK_NEQ: 00607 r = (strcmp(s1,s2) != 0); 00608 /*@switchbreak@*/ break; 00609 case TOK_LT: 00610 r = (strcmp(s1,s2) < 0); 00611 /*@switchbreak@*/ break; 00612 case TOK_LE: 00613 r = (strcmp(s1,s2) <= 0); 00614 /*@switchbreak@*/ break; 00615 case TOK_GT: 00616 r = (strcmp(s1,s2) > 0); 00617 /*@switchbreak@*/ break; 00618 case TOK_GE: 00619 r = (strcmp(s1,s2) >= 0); 00620 /*@switchbreak@*/ break; 00621 default: 00622 /*@switchbreak@*/ break; 00623 } 00624 valueFree(v1); 00625 v1 = valueMakeInteger(r); 00626 } 00627 } 00628 /*@=branchstate@*/ 00629 00630 if (v2) valueFree(v2); 00631 return v1; 00632 } 00633 00637 static Value doLogical(ParseState state) 00638 /*@globals rpmGlobalMacroContext, h_errno @*/ 00639 /*@modifies state->nextToken, state->p, state->tokenValue, 00640 rpmGlobalMacroContext @*/ 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 /*@-branchstate@*/ 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 /*@=branchstate@*/ 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 /* Initialize the expression parser state. */ 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 /* Parse the expression. */ 00704 v = doLogical(&state); 00705 if (!v) { 00706 state.str = _free(state.str); 00707 return -1; 00708 } 00709 00710 /* If the next token is not TOK_EOF, we have a syntax error. */ 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 /*@-boundsread@*/ 00725 result = v->data.s[0] != '\0'; 00726 /*@=boundsread@*/ 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 /* Initialize the expression parser state. */ 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 /* Parse the expression. */ 00753 v = doLogical(&state); 00754 if (!v) { 00755 state.str = _free(state.str); 00756 return NULL; 00757 } 00758 00759 /* If the next token is not TOK_EOF, we have a syntax error. */ 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 /*@-branchstate@*/ 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 /*@=branchstate@*/ 00782 00783 state.str = _free(state.str); 00784 valueFree(v); 00785 return result; 00786 }