rpm 5.3.7
|
00001 00014 #include "system.h" 00015 00016 #include <rpmio.h> 00017 #include <rpmiotypes.h> 00018 #include <rpmlog.h> 00019 00020 #include <rpmbuild.h> 00021 00022 #include "debug.h" 00023 00024 /* #define DEBUG_PARSER 1 */ 00025 00026 #ifdef DEBUG_PARSER 00027 #include <stdio.h> 00028 #define DEBUG(x) do { x ; } while (0) 00029 #else 00030 #define DEBUG(x) 00031 #endif 00032 00036 typedef struct _value { 00037 enum { VALUE_TYPE_INTEGER, VALUE_TYPE_STRING } type; 00038 union { 00039 const char *s; 00040 int i; 00041 } data; 00042 } *Value; 00043 00046 static Value valueMakeInteger(int i) 00047 /*@*/ 00048 { 00049 Value v; 00050 00051 v = (Value) xmalloc(sizeof(*v)); 00052 v->type = VALUE_TYPE_INTEGER; 00053 v->data.i = i; 00054 return v; 00055 } 00056 00059 static Value valueMakeString(/*@only@*/ const char *s) 00060 /*@*/ 00061 { 00062 Value v; 00063 00064 v = (Value) xmalloc(sizeof(*v)); 00065 v->type = VALUE_TYPE_STRING; 00066 v->data.s = s; 00067 return v; 00068 } 00069 00072 static void valueFree( /*@only@*/ Value v) 00073 /*@modifies v @*/ 00074 { 00075 if (v) { 00076 if (v->type == VALUE_TYPE_STRING) 00077 v->data.s = _free(v->data.s); 00078 v = _free(v); 00079 } 00080 } 00081 00082 #ifdef DEBUG_PARSER 00083 static void valueDump(const char *msg, Value v, FILE *fp) 00084 /*@*/ 00085 { 00086 if (msg) 00087 fprintf(fp, "%s ", msg); 00088 if (v) { 00089 if (v->type == VALUE_TYPE_INTEGER) 00090 fprintf(fp, "INTEGER %d\n", v->data.i); 00091 else 00092 fprintf(fp, "STRING '%s'\n", v->data.s); 00093 } else 00094 fprintf(fp, "NULL\n"); 00095 } 00096 #endif 00097 00098 #define valueIsInteger(v) ((v)->type == VALUE_TYPE_INTEGER) 00099 #define valueIsString(v) ((v)->type == VALUE_TYPE_STRING) 00100 #define valueSameType(v1,v2) ((v1)->type == (v2)->type) 00101 00102 00106 typedef struct _parseState { 00107 /*@owned@*/ 00108 char *str; 00109 /*@dependent@*/ 00110 char *p; 00111 int nextToken; 00112 /*@relnull@*/ 00113 Value tokenValue; 00114 Spec spec; 00115 } *ParseState; 00116 00117 00122 #define TOK_EOF 1 00123 #define TOK_INTEGER 2 00124 #define TOK_STRING 3 00125 #define TOK_IDENTIFIER 4 00126 #define TOK_ADD 5 00127 #define TOK_MINUS 6 00128 #define TOK_MULTIPLY 7 00129 #define TOK_DIVIDE 8 00130 #define TOK_OPEN_P 9 00131 #define TOK_CLOSE_P 10 00132 #define TOK_EQ 11 00133 #define TOK_NEQ 12 00134 #define TOK_LT 13 00135 #define TOK_LE 14 00136 #define TOK_GT 15 00137 #define TOK_GE 16 00138 #define TOK_NOT 17 00139 #define TOK_LOGICAL_AND 18 00140 #define TOK_LOGICAL_OR 19 00141 00143 #define EXPRBUFSIZ BUFSIZ 00144 00145 #if defined(DEBUG_PARSER) 00146 typedef struct exprTokTableEntry { 00147 const char *name; 00148 int val; 00149 } ETTE_t; 00150 00151 ETTE_t exprTokTable[] = { 00152 { "EOF", TOK_EOF }, 00153 { "I", TOK_INTEGER }, 00154 { "S", TOK_STRING }, 00155 { "ID", TOK_IDENTIFIER }, 00156 { "+", TOK_ADD }, 00157 { "-", TOK_MINUS }, 00158 { "*", TOK_MULTIPLY }, 00159 { "/", TOK_DIVIDE }, 00160 { "( ", TOK_OPEN_P }, 00161 { " )", TOK_CLOSE_P }, 00162 { "==", TOK_EQ }, 00163 { "!=", TOK_NEQ }, 00164 { "<", TOK_LT }, 00165 { "<=", TOK_LE }, 00166 { ">", TOK_GT }, 00167 { ">=", TOK_GE }, 00168 { "!", TOK_NOT }, 00169 { "&&", TOK_LOGICAL_AND }, 00170 { "||", TOK_LOGICAL_OR }, 00171 { NULL, 0 } 00172 }; 00173 00174 static const char *prToken(int val) 00175 /*@*/ 00176 { 00177 ETTE_t *et; 00178 00179 for (et = exprTokTable; et->name != NULL; et++) { 00180 if (val == et->val) 00181 return et->name; 00182 } 00183 return "???"; 00184 } 00185 #endif /* DEBUG_PARSER */ 00186 00190 static int rdToken(ParseState state) 00191 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00192 /*@modifies state->nextToken, state->p, state->tokenValue, 00193 rpmGlobalMacroContext, internalState @*/ 00194 { 00195 int token; 00196 Value v = NULL; 00197 char *p = state->p; 00198 00199 /* Skip whitespace before the next token. */ 00200 while (*p && xisspace(*p)) p++; 00201 00202 switch (*p) { 00203 case '\0': 00204 token = TOK_EOF; 00205 p--; 00206 break; 00207 case '+': 00208 token = TOK_ADD; 00209 break; 00210 case '-': 00211 token = TOK_MINUS; 00212 break; 00213 case '*': 00214 token = TOK_MULTIPLY; 00215 break; 00216 case '/': 00217 token = TOK_DIVIDE; 00218 break; 00219 case '(': 00220 token = TOK_OPEN_P; 00221 break; 00222 case ')': 00223 token = TOK_CLOSE_P; 00224 break; 00225 case '=': 00226 if (p[1] == '=') { 00227 token = TOK_EQ; 00228 p++; 00229 } else { 00230 rpmlog(RPMLOG_ERR, _("syntax error while parsing ==\n")); 00231 return -1; 00232 } 00233 break; 00234 case '!': 00235 if (p[1] == '=') { 00236 token = TOK_NEQ; 00237 p++; 00238 } else 00239 token = TOK_NOT; 00240 break; 00241 case '<': 00242 if (p[1] == '=') { 00243 token = TOK_LE; 00244 p++; 00245 } else 00246 token = TOK_LT; 00247 break; 00248 case '>': 00249 if (p[1] == '=') { 00250 token = TOK_GE; 00251 p++; 00252 } else 00253 token = TOK_GT; 00254 break; 00255 case '&': 00256 if (p[1] == '&') { 00257 token = TOK_LOGICAL_AND; 00258 p++; 00259 } else { 00260 rpmlog(RPMLOG_ERR, _("syntax error while parsing &&\n")); 00261 return -1; 00262 } 00263 break; 00264 case '|': 00265 if (p[1] == '|') { 00266 token = TOK_LOGICAL_OR; 00267 p++; 00268 } else { 00269 rpmlog(RPMLOG_ERR, _("syntax error while parsing ||\n")); 00270 return -1; 00271 } 00272 break; 00273 00274 default: 00275 if (xisdigit(*p)) { 00276 char temp[EXPRBUFSIZ], *t = temp; 00277 00278 temp[0] = '\0'; 00279 while (*p && xisdigit(*p)) 00280 *t++ = *p++; 00281 *t++ = '\0'; 00282 p--; 00283 00284 token = TOK_INTEGER; 00285 v = valueMakeInteger(atoi(temp)); 00286 00287 } else if (xisalpha(*p)) { 00288 char temp[EXPRBUFSIZ], *t = temp; 00289 00290 temp[0] = '\0'; 00291 while (*p && (xisalnum(*p) || *p == '_')) 00292 *t++ = *p++; 00293 *t++ = '\0'; 00294 p--; 00295 00296 token = TOK_IDENTIFIER; 00297 v = valueMakeString( xstrdup(temp) ); 00298 00299 } else if (*p == '\"') { 00300 char temp[EXPRBUFSIZ], *t = temp; 00301 00302 temp[0] = '\0'; 00303 p++; 00304 while (*p && *p != '\"') 00305 *t++ = *p++; 00306 *t++ = '\0'; 00307 00308 token = TOK_STRING; 00309 v = valueMakeString( rpmExpand(temp, NULL) ); 00310 00311 } else { 00312 rpmlog(RPMLOG_ERR, _("parse error in expression\n")); 00313 return -1; 00314 } 00315 } 00316 00317 state->p = p + 1; 00318 state->nextToken = token; 00319 state->tokenValue = v; 00320 00321 DEBUG(printf("rdToken: \"%s\" (%d)\n", prToken(token), token)); 00322 DEBUG(valueDump("rdToken:", state->tokenValue, stdout)); 00323 00324 return 0; 00325 } 00326 00327 /*@null@*/ 00328 static Value doLogical(ParseState state) 00329 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00330 /*@modifies state->nextToken, state->p, state->tokenValue, 00331 rpmGlobalMacroContext, internalState @*/; 00332 00336 /*@null@*/ 00337 static Value doPrimary(ParseState state) 00338 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00339 /*@modifies state->nextToken, state->p, state->tokenValue, 00340 rpmGlobalMacroContext, internalState @*/ 00341 { 00342 Value v; 00343 00344 DEBUG(printf("doPrimary()\n")); 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 rpmlog(RPMLOG_ERR, _("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 rpmlog(RPMLOG_ERR, _("- 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 rpmlog(RPMLOG_ERR, _("! 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 00411 DEBUG(valueDump("doPrimary:", v, stdout)); 00412 return v; 00413 } 00414 00418 /*@null@*/ 00419 static Value doMultiplyDivide(ParseState state) 00420 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00421 /*@modifies state->nextToken, state->p, state->tokenValue, 00422 rpmGlobalMacroContext, internalState @*/ 00423 { 00424 Value v1, v2 = NULL; 00425 00426 DEBUG(printf("doMultiplyDivide()\n")); 00427 00428 v1 = doPrimary(state); 00429 if (v1 == NULL) 00430 return NULL; 00431 00432 while (state->nextToken == TOK_MULTIPLY 00433 || state->nextToken == TOK_DIVIDE) 00434 { 00435 int op = state->nextToken; 00436 00437 if (rdToken(state)) 00438 return NULL; 00439 00440 if (v2) valueFree(v2); 00441 00442 v2 = doPrimary(state); 00443 if (v2 == NULL) 00444 return NULL; 00445 00446 if (! valueSameType(v1, v2)) { 00447 rpmlog(RPMLOG_ERR, _("types must match\n")); 00448 return NULL; 00449 } 00450 00451 if (valueIsInteger(v1)) { 00452 int i1 = v1->data.i, i2 = v2->data.i; 00453 00454 valueFree(v1); 00455 if (op == TOK_MULTIPLY) 00456 v1 = valueMakeInteger(i1 * i2); 00457 else 00458 v1 = valueMakeInteger(i1 / i2); 00459 } else { 00460 rpmlog(RPMLOG_ERR, _("* / not suported for strings\n")); 00461 return NULL; 00462 } 00463 } 00464 00465 if (v2) valueFree(v2); 00466 return v1; 00467 } 00468 00472 /*@null@*/ 00473 static Value doAddSubtract(ParseState state) 00474 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00475 /*@modifies state->nextToken, state->p, state->tokenValue, 00476 rpmGlobalMacroContext, internalState @*/ 00477 { 00478 Value v1, v2 = NULL; 00479 00480 DEBUG(printf("doAddSubtract()\n")); 00481 00482 v1 = doMultiplyDivide(state); 00483 if (v1 == NULL) 00484 return NULL; 00485 00486 while (state->nextToken == TOK_ADD || state->nextToken == TOK_MINUS) { 00487 int op = state->nextToken; 00488 00489 if (rdToken(state)) 00490 return NULL; 00491 00492 if (v2) valueFree(v2); 00493 00494 v2 = doMultiplyDivide(state); 00495 if (v2 == NULL) 00496 return NULL; 00497 00498 if (! valueSameType(v1, v2)) { 00499 rpmlog(RPMLOG_ERR, _("types must match\n")); 00500 return NULL; 00501 } 00502 00503 if (valueIsInteger(v1)) { 00504 int i1 = v1->data.i, i2 = v2->data.i; 00505 00506 valueFree(v1); 00507 if (op == TOK_ADD) 00508 v1 = valueMakeInteger(i1 + i2); 00509 else 00510 v1 = valueMakeInteger(i1 - i2); 00511 } else { 00512 char *copy; 00513 00514 if (op == TOK_MINUS) { 00515 rpmlog(RPMLOG_ERR, _("- not suported for strings\n")); 00516 return NULL; 00517 } 00518 00519 copy = xmalloc(strlen(v1->data.s) + strlen(v2->data.s) + 1); 00520 (void) stpcpy( stpcpy(copy, v1->data.s), v2->data.s); 00521 00522 valueFree(v1); 00523 v1 = valueMakeString(copy); 00524 } 00525 } 00526 00527 if (v2) valueFree(v2); 00528 return v1; 00529 } 00530 00534 /*@null@*/ 00535 static Value doRelational(ParseState state) 00536 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00537 /*@modifies state->nextToken, state->p, state->tokenValue, 00538 rpmGlobalMacroContext, internalState @*/ 00539 { 00540 Value v1, v2 = NULL; 00541 00542 DEBUG(printf("doRelational()\n")); 00543 00544 v1 = doAddSubtract(state); 00545 if (v1 == NULL) 00546 return NULL; 00547 00548 while (state->nextToken >= TOK_EQ && state->nextToken <= TOK_GE) { 00549 int op = state->nextToken; 00550 00551 if (rdToken(state)) 00552 return NULL; 00553 00554 if (v2) valueFree(v2); 00555 00556 v2 = doAddSubtract(state); 00557 if (v2 == NULL) 00558 return NULL; 00559 00560 if (! valueSameType(v1, v2)) { 00561 rpmlog(RPMLOG_ERR, _("types must match\n")); 00562 return NULL; 00563 } 00564 00565 if (valueIsInteger(v1)) { 00566 int i1 = v1->data.i, i2 = v2->data.i, r = 0; 00567 switch (op) { 00568 case TOK_EQ: 00569 r = (i1 == i2); 00570 /*@switchbreak@*/ break; 00571 case TOK_NEQ: 00572 r = (i1 != i2); 00573 /*@switchbreak@*/ break; 00574 case TOK_LT: 00575 r = (i1 < i2); 00576 /*@switchbreak@*/ break; 00577 case TOK_LE: 00578 r = (i1 <= i2); 00579 /*@switchbreak@*/ break; 00580 case TOK_GT: 00581 r = (i1 > i2); 00582 /*@switchbreak@*/ break; 00583 case TOK_GE: 00584 r = (i1 >= i2); 00585 /*@switchbreak@*/ break; 00586 default: 00587 /*@switchbreak@*/ break; 00588 } 00589 valueFree(v1); 00590 v1 = valueMakeInteger(r); 00591 } else { 00592 const char * s1 = v1->data.s; 00593 const char * s2 = v2->data.s; 00594 int r = 0; 00595 switch (op) { 00596 case TOK_EQ: 00597 r = (strcmp(s1,s2) == 0); 00598 /*@switchbreak@*/ break; 00599 case TOK_NEQ: 00600 r = (strcmp(s1,s2) != 0); 00601 /*@switchbreak@*/ break; 00602 case TOK_LT: 00603 r = (strcmp(s1,s2) < 0); 00604 /*@switchbreak@*/ break; 00605 case TOK_LE: 00606 r = (strcmp(s1,s2) <= 0); 00607 /*@switchbreak@*/ break; 00608 case TOK_GT: 00609 r = (strcmp(s1,s2) > 0); 00610 /*@switchbreak@*/ break; 00611 case TOK_GE: 00612 r = (strcmp(s1,s2) >= 0); 00613 /*@switchbreak@*/ break; 00614 default: 00615 /*@switchbreak@*/ break; 00616 } 00617 valueFree(v1); 00618 v1 = valueMakeInteger(r); 00619 } 00620 } 00621 00622 if (v2) valueFree(v2); 00623 return v1; 00624 } 00625 00629 static Value doLogical(ParseState state) 00630 /*@globals rpmGlobalMacroContext, h_errno @*/ 00631 /*@modifies state->nextToken, state->p, state->tokenValue, 00632 rpmGlobalMacroContext @*/ 00633 { 00634 Value v1, v2 = NULL; 00635 00636 DEBUG(printf("doLogical()\n")); 00637 00638 v1 = doRelational(state); 00639 if (v1 == NULL) 00640 return NULL; 00641 00642 while (state->nextToken == TOK_LOGICAL_AND 00643 || state->nextToken == TOK_LOGICAL_OR) 00644 { 00645 int op = state->nextToken; 00646 00647 if (rdToken(state)) 00648 return NULL; 00649 00650 if (v2) valueFree(v2); 00651 00652 v2 = doRelational(state); 00653 if (v2 == NULL) 00654 return NULL; 00655 00656 if (! valueSameType(v1, v2)) { 00657 rpmlog(RPMLOG_ERR, _("types must match\n")); 00658 return NULL; 00659 } 00660 00661 if (valueIsInteger(v1)) { 00662 int i1 = v1->data.i, i2 = v2->data.i; 00663 00664 valueFree(v1); 00665 if (op == TOK_LOGICAL_AND) 00666 v1 = valueMakeInteger(i1 && i2); 00667 else 00668 v1 = valueMakeInteger(i1 || i2); 00669 } else { 00670 rpmlog(RPMLOG_ERR, _("&& and || not suported for strings\n")); 00671 return NULL; 00672 } 00673 } 00674 00675 if (v2) valueFree(v2); 00676 return v1; 00677 } 00678 00679 int parseExpressionBoolean(Spec spec, const char *expr) 00680 { 00681 struct _parseState state; 00682 int result = -1; 00683 Value v; 00684 00685 DEBUG(printf("parseExprBoolean(?, '%s')\n", expr)); 00686 00687 /* Initialize the expression parser state. */ 00688 state.p = state.str = xstrdup(expr); 00689 state.spec = spec; 00690 state.nextToken = 0; 00691 state.tokenValue = NULL; 00692 (void) rdToken(&state); 00693 00694 /* Parse the expression. */ 00695 v = doLogical(&state); 00696 if (!v) { 00697 state.str = _free(state.str); 00698 return -1; 00699 } 00700 00701 /* If the next token is not TOK_EOF, we have a syntax error. */ 00702 if (state.nextToken != TOK_EOF) { 00703 rpmlog(RPMLOG_ERR, _("syntax error in expression\n")); 00704 state.str = _free(state.str); 00705 return -1; 00706 } 00707 00708 DEBUG(valueDump("parseExprBoolean:", v, stdout)); 00709 00710 switch (v->type) { 00711 case VALUE_TYPE_INTEGER: 00712 result = v->data.i != 0; 00713 break; 00714 case VALUE_TYPE_STRING: 00715 result = v->data.s[0] != '\0'; 00716 break; 00717 default: 00718 break; 00719 } 00720 00721 state.str = _free(state.str); 00722 valueFree(v); 00723 return result; 00724 } 00725 00726 char * parseExpressionString(Spec spec, const char *expr) 00727 { 00728 struct _parseState state; 00729 char *result = NULL; 00730 Value v; 00731 00732 DEBUG(printf("parseExprString(?, '%s')\n", expr)); 00733 00734 /* Initialize the expression parser state. */ 00735 state.p = state.str = xstrdup(expr); 00736 state.spec = spec; 00737 state.nextToken = 0; 00738 state.tokenValue = NULL; 00739 (void) rdToken(&state); 00740 00741 /* Parse the expression. */ 00742 v = doLogical(&state); 00743 if (!v) { 00744 state.str = _free(state.str); 00745 return NULL; 00746 } 00747 00748 /* If the next token is not TOK_EOF, we have a syntax error. */ 00749 if (state.nextToken != TOK_EOF) { 00750 rpmlog(RPMLOG_ERR, _("syntax error in expression\n")); 00751 state.str = _free(state.str); 00752 return NULL; 00753 } 00754 00755 DEBUG(valueDump("parseExprString:", v, stdout)); 00756 00757 switch (v->type) { 00758 case VALUE_TYPE_INTEGER: { 00759 char buf[128]; 00760 sprintf(buf, "%d", v->data.i); 00761 result = xstrdup(buf); 00762 } break; 00763 case VALUE_TYPE_STRING: 00764 result = xstrdup(v->data.s); 00765 break; 00766 default: 00767 break; 00768 } 00769 00770 state.str = _free(state.str); 00771 valueFree(v); 00772 return result; 00773 }