mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-15 23:55:03 +03:00
Looks for external resources in the same path of the rule
This commit is contained in:
parent
5cc9e94505
commit
e54ef72051
@ -23,7 +23,8 @@ namespace ModSecurity {
|
|||||||
namespace operators {
|
namespace operators {
|
||||||
|
|
||||||
|
|
||||||
bool IpMatchFromFile::init(const char **error) {
|
bool IpMatchFromFile::init(const std::string &file,
|
||||||
|
const char **error) {
|
||||||
std::string e("");
|
std::string e("");
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class IpMatchFromFile : public IpMatch {
|
|||||||
IpMatchFromFile(std::string op, std::string param, bool negation)
|
IpMatchFromFile(std::string op, std::string param, bool negation)
|
||||||
: IpMatch(op, param, negation) { }
|
: IpMatch(op, param, negation) { }
|
||||||
|
|
||||||
bool init(const char **error) override;
|
bool init(const std::string& file, const char **error) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace operators
|
} // namespace operators
|
||||||
|
@ -40,7 +40,10 @@ class Operator {
|
|||||||
std::string param;
|
std::string param;
|
||||||
bool negation;
|
bool negation;
|
||||||
|
|
||||||
virtual bool init(const char **error) { return true; }
|
virtual bool init(const std::string &file, const char **error) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool evaluate(Assay *assay);
|
virtual bool evaluate(Assay *assay);
|
||||||
virtual bool evaluate(Assay *assay, const std::string &str);
|
virtual bool evaluate(Assay *assay, const std::string &str);
|
||||||
static Operator *instantiate(std::string op);
|
static Operator *instantiate(std::string op);
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
|
|
||||||
#include "operators/operator.h"
|
#include "operators/operator.h"
|
||||||
#include "utils/https_client.h"
|
#include "utils/https_client.h"
|
||||||
|
#include "src/utils.h"
|
||||||
|
|
||||||
namespace ModSecurity {
|
namespace ModSecurity {
|
||||||
namespace operators {
|
namespace operators {
|
||||||
|
|
||||||
|
|
||||||
bool PmFromFile::init(const char **error) {
|
bool PmFromFile::init(const std::string &config, const char **error) {
|
||||||
std::istream *iss;
|
std::istream *iss;
|
||||||
|
|
||||||
if (param.compare(0, 8, "https://") == 0) {
|
if (param.compare(0, 8, "https://") == 0) {
|
||||||
@ -36,7 +37,8 @@ bool PmFromFile::init(const char **error) {
|
|||||||
}
|
}
|
||||||
iss = new std::stringstream(client.content);
|
iss = new std::stringstream(client.content);
|
||||||
} else {
|
} else {
|
||||||
iss = new std::ifstream(param, std::ios::in);
|
std::string resource = find_resource(param, config);
|
||||||
|
iss = new std::ifstream(resource, std::ios::in);
|
||||||
|
|
||||||
if (((std::ifstream *)iss)->is_open() == false) {
|
if (((std::ifstream *)iss)->is_open() == false) {
|
||||||
*error = std::string("Failed to open file: " + param).c_str();
|
*error = std::string("Failed to open file: " + param).c_str();
|
||||||
|
@ -31,7 +31,7 @@ class PmFromFile : public Pm {
|
|||||||
PmFromFile(std::string op, std::string param, bool negation)
|
PmFromFile(std::string op, std::string param, bool negation)
|
||||||
: Pm(op, param, negation) { }
|
: Pm(op, param, negation) { }
|
||||||
|
|
||||||
bool init(const char **error) override;
|
bool init(const std::string &file, const char **error) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ bool Rx::evaluate(Assay *assay, const std::string& input) {
|
|||||||
SMatch match;
|
SMatch match;
|
||||||
|
|
||||||
if (regex_search(input, &match, *m_re) && match.size() >= 1) {
|
if (regex_search(input, &match, *m_re) && match.size() >= 1) {
|
||||||
|
std::cout << "wheee" << std::endl;
|
||||||
// this->matched.push_back(match.match);
|
// this->matched.push_back(match.match);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,8 @@ bool ValidateByteRange::getRange(const std::string &rangeRepresentation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ValidateByteRange::init(const char **error) {
|
bool ValidateByteRange::init(const std::string &file,
|
||||||
|
const char **error) {
|
||||||
size_t pos = param.find_first_of(",");
|
size_t pos = param.find_first_of(",");
|
||||||
|
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
|
@ -38,7 +38,7 @@ class ValidateByteRange : public Operator {
|
|||||||
|
|
||||||
bool evaluate(Assay *assay, const std::string &input) override;
|
bool evaluate(Assay *assay, const std::string &input) override;
|
||||||
bool getRange(const std::string &rangeRepresentation, const char **error);
|
bool getRange(const std::string &rangeRepresentation, const char **error);
|
||||||
bool init(const char **error) override;
|
bool init(const std::string& file, const char **error) override;
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> ranges;
|
std::vector<std::string> ranges;
|
||||||
char table[32];
|
char table[32];
|
||||||
|
@ -90,7 +90,9 @@ int Driver::addSecRule(Rule *rule) {
|
|||||||
* by other rule
|
* by other rule
|
||||||
*/
|
*/
|
||||||
if (rule->rule_id == 0) {
|
if (rule->rule_id == 0) {
|
||||||
parserError << "Rules must have an ID." << std::endl;
|
parserError << "Rules must have an ID. File: ";
|
||||||
|
parserError << rule->m_fileName << " at line: ";
|
||||||
|
parserError << std::to_string(rule->m_lineNumber) << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) {
|
for (int i = 0; i < ModSecurity::Phases::NUMBER_OF_PHASES; i++) {
|
||||||
|
@ -351,7 +351,7 @@ op:
|
|||||||
{
|
{
|
||||||
Operator *op = Operator::instantiate($1);
|
Operator *op = Operator::instantiate($1);
|
||||||
const char *error = NULL;
|
const char *error = NULL;
|
||||||
if (op->init(&error) == false) {
|
if (op->init(driver.ref.back(), &error) == false) {
|
||||||
driver.error(@0, error);
|
driver.error(@0, error);
|
||||||
YYERROR;
|
YYERROR;
|
||||||
}
|
}
|
||||||
@ -361,7 +361,7 @@ op:
|
|||||||
{
|
{
|
||||||
Operator *op = Operator::instantiate("\"@rx " + $1 + "\"");
|
Operator *op = Operator::instantiate("\"@rx " + $1 + "\"");
|
||||||
const char *error = NULL;
|
const char *error = NULL;
|
||||||
if (op->init(&error) == false) {
|
if (op->init(driver.ref.back(), &error) == false) {
|
||||||
driver.error(@0, error);
|
driver.error(@0, error);
|
||||||
YYERROR;
|
YYERROR;
|
||||||
}
|
}
|
||||||
@ -375,7 +375,9 @@ expression:
|
|||||||
Rule *rule = new Rule(
|
Rule *rule = new Rule(
|
||||||
/* op */ $3,
|
/* op */ $3,
|
||||||
/* variables */ $2,
|
/* variables */ $2,
|
||||||
/* actions */ $4
|
/* actions */ $4,
|
||||||
|
/* file name */ driver.ref.back(),
|
||||||
|
/* line number */ @0.end.line
|
||||||
);
|
);
|
||||||
|
|
||||||
if (driver.addSecRule(rule) == false) {
|
if (driver.addSecRule(rule) == false) {
|
||||||
@ -387,7 +389,9 @@ expression:
|
|||||||
Rule *rule = new Rule(
|
Rule *rule = new Rule(
|
||||||
/* op */ $3,
|
/* op */ $3,
|
||||||
/* variables */ $2,
|
/* variables */ $2,
|
||||||
/* actions */ NULL
|
/* actions */ NULL,
|
||||||
|
/* file name */ driver.ref.back(),
|
||||||
|
/* line number */ @0.end.line
|
||||||
);
|
);
|
||||||
|
|
||||||
if (driver.addSecRule(rule) == false) {
|
if (driver.addSecRule(rule) == false) {
|
||||||
@ -399,7 +403,9 @@ expression:
|
|||||||
Rule *rule = new Rule(
|
Rule *rule = new Rule(
|
||||||
/* op */ NULL,
|
/* op */ NULL,
|
||||||
/* variables */ NULL,
|
/* variables */ NULL,
|
||||||
/* actions */ $2
|
/* actions */ $2,
|
||||||
|
/* file name */ driver.ref.back(),
|
||||||
|
/* line number */ @0.end.line
|
||||||
);
|
);
|
||||||
driver.addSecAction(rule);
|
driver.addSecAction(rule);
|
||||||
}
|
}
|
||||||
@ -508,7 +514,14 @@ expression:
|
|||||||
/* Debug log: end */
|
/* Debug log: end */
|
||||||
| CONFIG_DIR_GEO_DB
|
| CONFIG_DIR_GEO_DB
|
||||||
{
|
{
|
||||||
GeoLookup::getInstance().setDataBase($1);
|
std::string file = ModSecurity::find_resource($1, driver.ref.back());
|
||||||
|
if (GeoLookup::getInstance().setDataBase(file) == false) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Failed to load the GeoDB from: ";
|
||||||
|
ss << file;
|
||||||
|
driver.error(@0, ss.str());
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Body limits */
|
/* Body limits */
|
||||||
| CONFIG_DIR_REQ_BODY_LIMIT
|
| CONFIG_DIR_REQ_BODY_LIMIT
|
||||||
|
@ -98,7 +98,7 @@ CONFIG_SEC_REMOTE_RULES (?i:SecRemoteRules)
|
|||||||
CONFIG_SEC_REMOTE_RULES_FAIL_ACTION (?i:SecRemoteRulesFailAction)
|
CONFIG_SEC_REMOTE_RULES_FAIL_ACTION (?i:SecRemoteRulesFailAction)
|
||||||
|
|
||||||
|
|
||||||
DICT_ELEMENT [^ \|\t]+
|
DICT_ELEMENT [^ \t]+
|
||||||
|
|
||||||
|
|
||||||
OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@validateHash|@validateSchema|@verifyCC|@verifyCPF|@verifySSN|@gsbLookup|@rsub)|(?:\!{0,1})(?:@within|@containsWord|@contains|@endsWith|@eq|@ge|@gt|@ipMatchF|@ipMatch|@ipMatchFromFile|@le|@lt|@pmf|@pm|@pmFromFile|@rbl|@rx|@streq|@strmatch|@beginsWith))
|
OPERATOR (?i:(?:@inspectFile|@fuzzyHash|@validateByteRange|@validateDTD|@validateHash|@validateSchema|@verifyCC|@verifyCPF|@verifySSN|@gsbLookup|@rsub)|(?:\!{0,1})(?:@within|@containsWord|@contains|@endsWith|@eq|@ge|@gt|@ipMatchF|@ipMatch|@ipMatchFromFile|@le|@lt|@pmf|@pm|@pmFromFile|@rbl|@rx|@streq|@strmatch|@beginsWith))
|
||||||
@ -143,17 +143,20 @@ CONFIG_VALUE_PATH [0-9A-Za-z_/\.\-\*]+
|
|||||||
AUDIT_PARTS [ABCDEFHJKIZ]+
|
AUDIT_PARTS [ABCDEFHJKIZ]+
|
||||||
CONFIG_VALUE_NUMBER [0-9]+
|
CONFIG_VALUE_NUMBER [0-9]+
|
||||||
|
|
||||||
FREE_TEXT ([^\"]|([^\\]\\\"))+
|
FREE_TEXT ([^\"]|(\\\"))+
|
||||||
|
|
||||||
FREE_TEXT_NEW_LINE [^\"|\n]+
|
FREE_TEXT_NEW_LINE [^\"|\n]+
|
||||||
FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+
|
FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+
|
||||||
FREE_TEXT_SPACE [^ \t]+
|
FREE_TEXT_SPACE [^ \t]+
|
||||||
FREE_TEXT_SPACE_COMMA [^, \t]+
|
FREE_TEXT_SPACE_COMMA [^, \t]+
|
||||||
|
FREE_TEXT_SPACE_COMMA_QUOTE [^, \t\"]+
|
||||||
|
|
||||||
VAR_FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+
|
VAR_FREE_TEXT_QUOTE ([^\']|([^\\]\\\'))+
|
||||||
VAR_FREE_TEXT_SPACE_COMMA [^, \t\"]+
|
VAR_FREE_TEXT_SPACE_COMMA [^, \t\"]+
|
||||||
VAR_FREE_TEXT_SPACE [^ \t\"]+
|
VAR_FREE_TEXT_SPACE [^ \t\"]+
|
||||||
|
|
||||||
|
SOMETHING ["]{1}[^@]{1}([^"]|([^\\"]\\\"))*["]{1}
|
||||||
|
|
||||||
CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
||||||
|
|
||||||
%x EXPECTING_OPERATOR COMMENT
|
%x EXPECTING_OPERATOR COMMENT
|
||||||
@ -266,14 +269,14 @@ CONFIG_DIR_UNICODE_MAP_FILE (?i:SecUnicodeMapFile)
|
|||||||
{CONFIG_DIR_SEC_MARKER}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONFIG_DIR_SEC_MARKER(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
{CONFIG_DIR_SEC_MARKER}[ ]{FREE_TEXT_NEW_LINE} { return yy::seclang_parser::make_CONFIG_DIR_SEC_MARKER(strchr(yytext, ' ') + 1, *driver.loc.back()); }
|
||||||
|
|
||||||
<EXPECTING_OPERATOR>{
|
<EXPECTING_OPERATOR>{
|
||||||
["][^@]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); }
|
{SOMETHING} { BEGIN(INITIAL); return yy::seclang_parser::make_FREE_TEXT(yytext, *driver.loc.back()); }
|
||||||
["]{OPERATOR}[ ]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); }
|
["]{OPERATOR}[ ]{FREE_TEXT}["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); }
|
||||||
["]{OPERATORNOARG}[\t ]*["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); }
|
["]{OPERATORNOARG}[\t ]*["] { BEGIN(INITIAL); return yy::seclang_parser::make_OPERATOR(yytext, *driver.loc.back()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
{ACTION} { return yy::seclang_parser::make_ACTION(yytext, *driver.loc.back()); }
|
{ACTION} { return yy::seclang_parser::make_ACTION(yytext, *driver.loc.back()); }
|
||||||
{ACTION_PHASE} { return yy::seclang_parser::make_ACTION_PHASE(yytext, *driver.loc.back()); }
|
{ACTION_PHASE} { return yy::seclang_parser::make_ACTION_PHASE(yytext, *driver.loc.back()); }
|
||||||
{ACTION_SKIP_AFTER}:{FREE_TEXT} { return yy::seclang_parser::make_ACTION_SKIP_AFTER(strchr(yytext, ':') + 1, *driver.loc.back()); }
|
{ACTION_SKIP_AFTER}:{FREE_TEXT_SPACE_COMMA_QUOTE} { return yy::seclang_parser::make_ACTION_SKIP_AFTER(strchr(yytext, ':') + 1, *driver.loc.back()); }
|
||||||
{ACTION_AUDIT_LOG} { return yy::seclang_parser::make_ACTION_AUDIT_LOG(yytext, *driver.loc.back()); }
|
{ACTION_AUDIT_LOG} { return yy::seclang_parser::make_ACTION_AUDIT_LOG(yytext, *driver.loc.back()); }
|
||||||
|
|
||||||
{ACTION_SEVERITY}:{ACTION_SEVERITY_VALUE} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext + 9, *driver.loc.back()); }
|
{ACTION_SEVERITY}:{ACTION_SEVERITY_VALUE} { return yy::seclang_parser::make_ACTION_SEVERITY(yytext + 9, *driver.loc.back()); }
|
||||||
|
13
src/rule.cc
13
src/rule.cc
@ -82,12 +82,15 @@ Rule::Rule(std::string marker)
|
|||||||
m_unconditional(false),
|
m_unconditional(false),
|
||||||
m_secmarker(true),
|
m_secmarker(true),
|
||||||
m_marker(marker),
|
m_marker(marker),
|
||||||
m_referenceCount(0) { }
|
m_referenceCount(0),
|
||||||
|
m_fileName(""),
|
||||||
|
m_lineNumber(0) { }
|
||||||
|
|
||||||
Rule::Rule(Operator *_op,
|
Rule::Rule(Operator *_op,
|
||||||
std::vector<Variable *> *_variables,
|
std::vector<Variable *> *_variables,
|
||||||
std::vector<Action *> *actions)
|
std::vector<Action *> *actions,
|
||||||
: chained(false),
|
std::string fileName,
|
||||||
|
int lineNumber): chained(false),
|
||||||
chainedRule(NULL),
|
chainedRule(NULL),
|
||||||
variables(_variables),
|
variables(_variables),
|
||||||
op(_op),
|
op(_op),
|
||||||
@ -96,7 +99,9 @@ Rule::Rule(Operator *_op,
|
|||||||
m_unconditional(false),
|
m_unconditional(false),
|
||||||
m_secmarker(false),
|
m_secmarker(false),
|
||||||
m_marker(""),
|
m_marker(""),
|
||||||
m_referenceCount(0) {
|
m_referenceCount(0),
|
||||||
|
m_fileName(fileName),
|
||||||
|
m_lineNumber(lineNumber) {
|
||||||
if (actions != NULL) {
|
if (actions != NULL) {
|
||||||
for (Action *a : *actions) {
|
for (Action *a : *actions) {
|
||||||
if (a->action_kind == Action::ConfigurationKind) {
|
if (a->action_kind == Action::ConfigurationKind) {
|
||||||
|
@ -33,7 +33,10 @@ class Rule {
|
|||||||
public:
|
public:
|
||||||
Rule(operators::Operator *_op,
|
Rule(operators::Operator *_op,
|
||||||
std::vector<Variables::Variable *> *_variables,
|
std::vector<Variables::Variable *> *_variables,
|
||||||
std::vector<actions::Action *> *_actions);
|
std::vector<actions::Action *> *_actions,
|
||||||
|
std::string fileName,
|
||||||
|
int lineNumber
|
||||||
|
);
|
||||||
explicit Rule(std::string marker);
|
explicit Rule(std::string marker);
|
||||||
|
|
||||||
~Rule();
|
~Rule();
|
||||||
@ -67,6 +70,8 @@ class Rule {
|
|||||||
|
|
||||||
std::string m_marker;
|
std::string m_marker;
|
||||||
bool m_secmarker;
|
bool m_secmarker;
|
||||||
|
std::string m_fileName;
|
||||||
|
int m_lineNumber;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_unconditional;
|
bool m_unconditional;
|
||||||
|
33
src/utils.cc
33
src/utils.cc
@ -1040,5 +1040,38 @@ std::vector<std::string> expandEnv(const std::string& var, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string get_path(const std::string& file) {
|
||||||
|
size_t found;
|
||||||
|
|
||||||
|
found = file.find_last_of("/\\");
|
||||||
|
if (found > 0) {
|
||||||
|
return file.substr(0, found);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string find_resource(const std::string& resource, const std::string& config) {
|
||||||
|
std::ifstream *iss = NULL;
|
||||||
|
|
||||||
|
// Trying absolute or relative to the current dir.
|
||||||
|
iss = new std::ifstream(resource, std::ios::in);
|
||||||
|
if (iss->is_open()) {
|
||||||
|
iss->close();
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trying the same path of the configuration file.
|
||||||
|
std::string f = get_path(config) + "/" + resource;
|
||||||
|
iss = new std::ifstream(f, std::ios::in);
|
||||||
|
if (iss->is_open()) {
|
||||||
|
iss->close();
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string("");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ModSecurity
|
} // namespace ModSecurity
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ namespace ModSecurity {
|
|||||||
std::string limitTo(int amount, const std::string &str);
|
std::string limitTo(int amount, const std::string &str);
|
||||||
std::string toHexIfNeeded(const std::string &str);
|
std::string toHexIfNeeded(const std::string &str);
|
||||||
std::vector<std::string> expandEnv(const std::string& var, int flags);
|
std::vector<std::string> expandEnv(const std::string& var, int flags);
|
||||||
|
std::string find_resource(const std::string& file,
|
||||||
|
const std::string& param);
|
||||||
} // namespace ModSecurity
|
} // namespace ModSecurity
|
||||||
|
|
||||||
#define SRC_UTILS_H_
|
#define SRC_UTILS_H_
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
include "owasp-modsecurity-crs-orig/modsecurity_crs_10_setup.conf"
|
include "owasp-modsecurity-crs-orig/modsecurity_crs_10_setup.conf"
|
||||||
#include "owasp-modsecurity-crs-orig/rules/*.conf"
|
|
||||||
#include owasp-modsecurity-crs-orig/rules/RESPONSE-51-DATA-LEAKAGES-SQL.conf
|
|
||||||
include owasp-modsecurity-crs-orig/rules/REQUEST-01-COMMON-EXCEPTIONS.conf
|
include owasp-modsecurity-crs-orig/rules/REQUEST-01-COMMON-EXCEPTIONS.conf
|
||||||
include owasp-modsecurity-crs-orig/rules/REQUEST-10-IP-REPUTATION.conf
|
include owasp-modsecurity-crs-orig/rules/REQUEST-10-IP-REPUTATION.conf
|
||||||
include owasp-modsecurity-crs-orig/rules/REQUEST-11-METHOD-ENFORCEMENT.conf
|
include owasp-modsecurity-crs-orig/rules/REQUEST-11-METHOD-ENFORCEMENT.conf
|
||||||
|
@ -51,7 +51,7 @@ void perform_unit_test(UnitTest *t, ModSecurityTestResults<UnitTest>* res) {
|
|||||||
if (t->type == "op") {
|
if (t->type == "op") {
|
||||||
Operator *op = Operator::instantiate("\"@" + t->name + \
|
Operator *op = Operator::instantiate("\"@" + t->name + \
|
||||||
" " + t->param + "\"");
|
" " + t->param + "\"");
|
||||||
op->init(&error);
|
op->init(t->filename, &error);
|
||||||
int ret = op->evaluate(NULL, t->input);
|
int ret = op->evaluate(NULL, t->input);
|
||||||
if (ret != t->ret) {
|
if (ret != t->ret) {
|
||||||
t->obtained = ret;
|
t->obtained = ret;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user