static Token CondHandleComparison(char *lhs, bool doFree, bool doEval) { Token t; const char *rhs; const char *op; t = Err; /* Skip whitespace to get to the operator. */ while (isspace(*condExpr)) condExpr++; /* Make sure the operator is a valid one. If it isn't a * known relational operator, pretend we got a * != 0 comparison. */ op = condExpr; switch (*condExpr) { case '!': case '=': case '<': case '>': if (condExpr[1] == '=') condExpr += 2; else condExpr += 1; break; default: op = "!="; rhs = "0"; goto do_compare; } while (isspace(*condExpr)) condExpr++; if (*condExpr == '\0') { Parse_Error(PARSE_WARNING, "Missing right-hand-side of operator"); goto error; } rhs = condExpr; do_compare: if (*rhs == '"') { /* Doing a string comparison. Only allow == and != for * operators. */ char *string; const char *cp; int qt; BUFFER buf; do_string_compare: if ((*op != '!' && *op != '=') || op[1] != '=') { Parse_Error(PARSE_WARNING, "String comparison operator should be either == or !="); goto error; } Buf_Init(&buf, 0); qt = *rhs == '"' ? 1 : 0; for (cp = &rhs[qt]; ((qt && *cp != '"') || (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) { if (*cp == '$') { size_t len; if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len)) { cp += len; continue; } } else if (*cp == '\\' && cp[1] != '\0') /* Backslash escapes things -- skip over next * character, if it exists. */ cp++; Buf_AddChar(&buf, *cp++); } string = Buf_Retrieve(&buf); if (DEBUG(COND)) printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, string, op); /* Null-terminate rhs and perform the comparison. * t is set to the result. */ if (*op == '=') t = strcmp(lhs, string) ? False : True; else t = strcmp(lhs, string) ? True : False; free(string); if (rhs == condExpr) { if (!qt && *cp == ')') condExpr = cp; else if (*cp == '\0') condExpr = cp; else condExpr = cp + 1; } } else { /* rhs is either a float or an integer. Convert both the * lhs and the rhs to a double and compare the two. */ double left, right; char *string; if (!CondCvtArg(lhs, &left)) goto do_string_compare; if (*rhs == '$') { size_t len; bool freeIt; string = Var_Parse(rhs, NULL, doEval,&len,&freeIt); if (string == var_Error) right = 0.0; else { if (!CondCvtArg(string, &right)) { if (freeIt) free(string); goto do_string_compare; } if (freeIt) free(string); if (rhs == condExpr) condExpr += len; } } else { if (!CondCvtArg(rhs, &right)) goto do_string_compare; if (rhs == condExpr) { /* Skip over the right-hand side. */ while (!isspace(*condExpr) && *condExpr != '\0') condExpr++; } } if (DEBUG(COND)) printf("left = %f, right = %f, op = %.2s\n", left, right, op); switch (op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left != right ? True : False; break; case '=': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto error; } t = left == right ? True : False; break; case '<': if (op[1] == '=') t = left <= right ? True : False; else t = left < right ? True : False; break; case '>': if (op[1] == '=') t = left >= right ? True : False; else t = left > right ? True : False; break; } } error: if (doFree) free(lhs); return t; }
/*- *----------------------------------------------------------------------- * CondToken -- * Return the next token from the input. * * Results: * A Token for the next lexical token in the stream. * * Side Effects: * condPushback will be set back to TOK_NONE if it is used. * *----------------------------------------------------------------------- */ static Token compare_expression(Boolean doEval) { Token t; char *lhs; char *rhs; char *op; void *lhsFree; void *rhsFree; Boolean lhsQuoted; Boolean rhsQuoted; double left, right; t = TOK_ERROR; rhs = NULL; lhsFree = rhsFree = FALSE; lhsQuoted = rhsQuoted = FALSE; /* * Parse the variable spec and skip over it, saving its * value in lhs. */ lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict); if (!lhs) goto done; /* * Skip whitespace to get to the operator */ while (isspace((unsigned char) *condExpr)) condExpr++; /* * Make sure the operator is a valid one. If it isn't a * known relational operator, pretend we got a * != 0 comparison. */ op = condExpr; switch (*condExpr) { case '!': case '=': case '<': case '>': if (condExpr[1] == '=') { condExpr += 2; } else { condExpr += 1; } break; default: if (!doEval) { t = TOK_FALSE; goto done; } /* For .ifxxx "..." check for non-empty string. */ if (lhsQuoted) { t = lhs[0] != 0; goto done; } /* For .ifxxx <number> compare against zero */ if (CondCvtArg(lhs, &left)) { t = left != 0.0; goto done; } /* For .if ${...} check for non-empty string (defProc is ifdef). */ if (if_info->form[0] == 0) { t = lhs[0] != 0; goto done; } /* Otherwise action default test ... */ t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot; goto done; } while (isspace((unsigned char)*condExpr)) condExpr++; if (*condExpr == '\0') { Parse_Error(PARSE_WARNING, "Missing right-hand-side of operator"); goto done; } rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE); if (!rhs) goto done; if (rhsQuoted || lhsQuoted) { do_string_compare: if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { Parse_Error(PARSE_WARNING, "String comparison operator should be either == or !="); goto done; } if (DEBUG(COND)) { fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", lhs, rhs, op); } /* * Null-terminate rhs and perform the comparison. * t is set to the result. */ if (*op == '=') { t = strcmp(lhs, rhs) == 0; } else { t = strcmp(lhs, rhs) != 0; } } else { /* * rhs is either a float or an integer. Convert both the * lhs and the rhs to a double and compare the two. */ if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right)) goto do_string_compare; if (DEBUG(COND)) { fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, right, op); } switch(op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto done; } t = (left != right); break; case '=': if (op[1] != '=') { Parse_Error(PARSE_WARNING, "Unknown operator"); goto done; } t = (left == right); break; case '<': if (op[1] == '=') { t = (left <= right); } else { t = (left < right); } break; case '>': if (op[1] == '=') { t = (left >= right); } else { t = (left > right); } break; } } done: free(lhsFree); free(rhsFree); return t; }