introduced instructions, added "include" and "load" instructions for including/loading configuration data depending on conditions, added support for on-the-fly creation of conditions, added support for string based conditions
This commit is contained in:
+295
-75
@@ -401,14 +401,12 @@ bool Message::checkIdPrefix(vector<unsigned char>& id)
|
||||
{
|
||||
if (id.size() > m_id.size())
|
||||
return false;
|
||||
bool match = true;
|
||||
for (size_t pos = 0; pos < id.size(); pos++) {
|
||||
if (id[pos] != m_id[pos]) {
|
||||
match = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Message::checkId(SymbolString& master, unsigned char* index)
|
||||
@@ -429,13 +427,9 @@ bool Message::checkId(SymbolString& master, unsigned char* index)
|
||||
bool Message::checkId(Message& other)
|
||||
{
|
||||
unsigned char idLen = getIdLength();
|
||||
if (idLen != other.getIdLength() || getCount() > 1) // not supported for chained messages
|
||||
if (idLen != other.getIdLength() || getCount() > 1) // only equal for non-chained messages
|
||||
return false;
|
||||
for (unsigned char pos = 0; pos < idLen; pos++) {
|
||||
if (m_id[2+pos] != other.m_id[2+pos])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return other.checkIdPrefix(m_id);
|
||||
}
|
||||
|
||||
unsigned long long Message::getDerivedKey(const unsigned char dstAddress)
|
||||
@@ -801,6 +795,14 @@ bool ChainedMessage::checkId(SymbolString& master, unsigned char* index)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChainedMessage::checkId(Message& other)
|
||||
{
|
||||
unsigned char idLen = getIdLength();
|
||||
if (idLen != other.getIdLength() || other.getCount() == 1) // only equal for chained messages
|
||||
return false;
|
||||
return other.checkIdPrefix(m_id);
|
||||
}
|
||||
|
||||
result_t ChainedMessage::prepareMasterPart(SymbolString& master, istringstream& input, char separator, unsigned char index)
|
||||
{
|
||||
size_t cnt = getCount();
|
||||
@@ -967,43 +969,40 @@ Message* getFirstAvailable(vector<Message*> &messages, Message& sameIdExtAs) {
|
||||
Message* message = *msgIt;
|
||||
if (!message->checkId(sameIdExtAs))
|
||||
continue;
|
||||
|
||||
if (message->isAvailable())
|
||||
return *msgIt;
|
||||
return message;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue)
|
||||
/**
|
||||
* Split up a list of string values separated by @a VALUE_SEPARATOR.
|
||||
* @param valueList the input string to split.
|
||||
* @param values the output value list to append to.
|
||||
*/
|
||||
result_t splitValues(string valueList, vector<string>& values)
|
||||
{
|
||||
// name,circuit,messagename,[comment],[fieldname],[ZZ],values (name already skipped by caller)
|
||||
string circuit = it==end ? "" : *(it++); // circuit
|
||||
string name = it==end ? "" : *(it++); // messagename
|
||||
if (it<end)
|
||||
it++; // comment
|
||||
string field = it==end ? "" : *(it++); // fieldname
|
||||
string zz = it==end ? "" : *(it++); // ZZ
|
||||
unsigned char dstAddress = SYN;
|
||||
result_t result = RESULT_OK;
|
||||
if (zz.length()==0)
|
||||
zz = defaultDest;
|
||||
if (zz.length()>0) {
|
||||
dstAddress = (unsigned char)parseInt(zz.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK)
|
||||
return result;
|
||||
if (dstAddress!=SYN && !isValidAddress(dstAddress, false))
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
}
|
||||
if (name.length()==0) {
|
||||
if (!isValidAddress(dstAddress, false) || isMaster(dstAddress))
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
} else if (circuit.length()==0) {
|
||||
circuit = defaultCircuit;
|
||||
}
|
||||
istringstream stream(it==end ? "" : *(it++));
|
||||
istringstream stream(valueList);
|
||||
string str;
|
||||
vector<unsigned int> valueRanges;
|
||||
while (getline(stream, str, VALUE_SEPARATOR) != 0) {
|
||||
if (str.length()>0 && str[0]=='\'' && str[str.length()-1]=='\'') {
|
||||
str = str.substr(1, str.length()-2);
|
||||
}
|
||||
values.push_back(str);
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split up a list of numeric value ranges separated by @a VALUE_SEPARATOR.
|
||||
* @param valueList the input string to split.
|
||||
* @param valueRanges the output list of value ranges to append to (pairs of inclusive from-to values).
|
||||
*/
|
||||
result_t splitValues(string valueList, vector<unsigned int>& valueRanges)
|
||||
{
|
||||
istringstream stream(valueList);
|
||||
string str;
|
||||
result_t result;
|
||||
while (getline(stream, str, VALUE_SEPARATOR) != 0) {
|
||||
FileReader::trim(str);
|
||||
if (str.length()==0)
|
||||
@@ -1040,12 +1039,81 @@ result_t Condition::create(const string condName, vector<string>::iterator& it,
|
||||
valueRanges.push_back(val); // single value
|
||||
}
|
||||
}
|
||||
if (field.length()>0 && valueRanges.empty())
|
||||
return RESULT_ERR_INVALID_NUM;
|
||||
returnValue = new SimpleCondition(condName, circuit, name, dstAddress, field, valueRanges);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t Condition::create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue)
|
||||
{
|
||||
// name,circuit,messagename,[comment],[fieldname],[ZZ],values (name already skipped by caller)
|
||||
string circuit = it==end ? "" : *(it++); // circuit
|
||||
string name = it==end ? "" : *(it++); // messagename
|
||||
if (it<end)
|
||||
it++; // comment
|
||||
string field = it==end ? "" : *(it++); // fieldname
|
||||
string zz = it==end ? "" : *(it++); // ZZ
|
||||
unsigned char dstAddress = SYN;
|
||||
result_t result = RESULT_OK;
|
||||
if (zz.length()==0)
|
||||
zz = defaultDest;
|
||||
if (zz.length()>0) {
|
||||
dstAddress = (unsigned char)parseInt(zz.c_str(), 16, 0, 0xff, result);
|
||||
if (result != RESULT_OK)
|
||||
return result;
|
||||
if (dstAddress!=SYN && !isValidAddress(dstAddress, false))
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
}
|
||||
if (name.length()==0) {
|
||||
if (!isValidAddress(dstAddress, false) || isMaster(dstAddress))
|
||||
return RESULT_ERR_INVALID_ADDR;
|
||||
} else if (circuit.length()==0) {
|
||||
circuit = defaultCircuit;
|
||||
}
|
||||
string valueList = it==end ? "" : *(it++);
|
||||
if (valueList.length()==0) {
|
||||
returnValue = new SimpleCondition(condName, circuit, name, dstAddress, field);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (valueList[0]=='\'') {
|
||||
// strings
|
||||
vector<string> values;
|
||||
result = splitValues(valueList, values);
|
||||
if (result!=RESULT_OK)
|
||||
return result;
|
||||
returnValue = new SimpleStringCondition(condName, circuit, name, dstAddress, field, values);
|
||||
return RESULT_OK;
|
||||
}
|
||||
// numbers
|
||||
vector<unsigned int> valueRanges;
|
||||
result = splitValues(valueList, valueRanges);
|
||||
if (result!=RESULT_OK)
|
||||
return result;
|
||||
|
||||
returnValue = new SimpleNumericCondition(condName, circuit, name, dstAddress, field, valueRanges);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
SimpleCondition* SimpleCondition::derive(string valueList)
|
||||
{
|
||||
if (valueList.empty())
|
||||
return NULL;
|
||||
result_t result;
|
||||
if (valueList[0]=='\'') {
|
||||
// strings
|
||||
vector<string> values;
|
||||
result = splitValues(valueList, values);
|
||||
if (result!=RESULT_OK)
|
||||
return NULL;
|
||||
return new SimpleStringCondition(m_condName+valueList, m_circuit, m_name, m_dstAddress, m_field, values);
|
||||
}
|
||||
// numbers
|
||||
if (!isNumeric())
|
||||
return NULL;
|
||||
vector<unsigned int> valueRanges;
|
||||
result = splitValues(valueList, valueRanges);
|
||||
if (result!=RESULT_OK)
|
||||
return NULL;
|
||||
return new SimpleNumericCondition(m_condName+valueList, m_circuit, m_name, m_dstAddress, m_field, valueRanges);
|
||||
}
|
||||
|
||||
void SimpleCondition::dump(ostream& output)
|
||||
{
|
||||
@@ -1095,15 +1163,15 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess
|
||||
} else {
|
||||
message = getFirstAvailable(*derived, *message);
|
||||
if (message==NULL) {
|
||||
errorMessage << ": conditional derived message";
|
||||
errorMessage << ": conditional derived message not found";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_valueRanges.empty()) {
|
||||
if (!message->hasField(m_field.length()>0 ? m_field.c_str() : NULL, true)) {
|
||||
errorMessage << ": numeric field " << m_field << " not found";
|
||||
if (m_hasValues) {
|
||||
if (!message->hasField(m_field.length()>0 ? m_field.c_str() : NULL, isNumeric())) {
|
||||
errorMessage << (isNumeric() ? ": numeric field " : ": string field ") << m_field << " not found";
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
@@ -1119,18 +1187,9 @@ bool SimpleCondition::isTrue()
|
||||
if (!m_message)
|
||||
return false;
|
||||
if (m_message->getLastChangeTime()>m_lastCheckTime) {
|
||||
bool isTrue = m_valueRanges.empty(); // for message seen check
|
||||
bool isTrue = !m_hasValues; // for message seen check
|
||||
if (!isTrue) {
|
||||
unsigned int value = 0;
|
||||
result_t result = m_message->decodeLastDataNumField(value, m_field.length()==0 ? NULL : m_field.c_str());
|
||||
if (result==RESULT_OK) {
|
||||
for (size_t i=0; i+1<m_valueRanges.size(); i+=2) {
|
||||
if (m_valueRanges[i]<=value && value<=m_valueRanges[i+1]) {
|
||||
isTrue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
isTrue = checkValue(m_message, m_field);
|
||||
}
|
||||
m_isTrue = isTrue;
|
||||
m_lastCheckTime = m_message->getLastChangeTime();
|
||||
@@ -1139,6 +1198,35 @@ bool SimpleCondition::isTrue()
|
||||
}
|
||||
|
||||
|
||||
bool SimpleNumericCondition::checkValue(Message* message, string field) {
|
||||
unsigned int value = 0;
|
||||
result_t result = message->decodeLastDataNumField(value, field.length()==0 ? NULL : field.c_str());
|
||||
if (result==RESULT_OK) {
|
||||
for (size_t i=0; i+1<m_valueRanges.size(); i+=2) {
|
||||
if (m_valueRanges[i]<=value && value<=m_valueRanges[i+1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SimpleStringCondition::checkValue(Message* message, string field) {
|
||||
ostringstream output;
|
||||
result_t result = message->decodeLastData(output, 0, false, field.length()==0 ? NULL : field.c_str());
|
||||
if (result==RESULT_OK) {
|
||||
string value = output.str();
|
||||
for (size_t i=0; i<m_values.size(); i++) {
|
||||
if (m_values[i]==value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CombinedCondition::dump(ostream& output)
|
||||
{
|
||||
for (vector<Condition*>::iterator it = m_conditions.begin(); it!=m_conditions.end(); it++) {
|
||||
@@ -1171,6 +1259,34 @@ bool CombinedCondition::isTrue()
|
||||
}
|
||||
|
||||
|
||||
result_t Instruction::create(const string contextPath, Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue)
|
||||
{
|
||||
// type[,argument]* (type already skipped by caller)
|
||||
bool singleton = false;
|
||||
if ((singleton=(type=="load")) || type=="include") {
|
||||
if (it==end || (*it).empty()) {
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
size_t pos = contextPath.find_last_of('/');
|
||||
string path;
|
||||
if (pos==string::npos) {
|
||||
path = contextPath;
|
||||
} else {
|
||||
path = contextPath.substr(0, pos+1);
|
||||
}
|
||||
returnValue = new LoadInstruction(condition, singleton, path+(*it));
|
||||
return RESULT_OK;
|
||||
}
|
||||
// unknown instruction
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
||||
result_t LoadInstruction::execute(MessageMap* messages) {
|
||||
return messages->readFromFile(m_filename);
|
||||
}
|
||||
|
||||
|
||||
result_t MessageMap::add(Message* message, bool storeByName)
|
||||
{
|
||||
unsigned long long key = message->getKey();
|
||||
@@ -1286,19 +1402,43 @@ result_t MessageMap::readConditions(string& types, const string& filename, Condi
|
||||
types = types.substr(pos+1);
|
||||
} else {
|
||||
bool store = false;
|
||||
condition = NULL;
|
||||
while ((pos=types.find(']'))!=string::npos) {
|
||||
// simple condition
|
||||
string key = filename+":"+types.substr(1, pos-1);
|
||||
map<string, Condition*>::iterator it = m_conditions.find(key);
|
||||
Condition* add = NULL;
|
||||
if (it==m_conditions.end()) {
|
||||
m_lastError = "condition "+types.substr(1, pos-1)+" not defined";
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
// check for on-the-fly condition
|
||||
size_t pos = key.find_first_of("=<>", filename.length()+1);
|
||||
if (pos!=string::npos) {
|
||||
it = m_conditions.find(key.substr(0, pos));
|
||||
if (it!=m_conditions.end()) {
|
||||
// derive from another condition
|
||||
if (key[pos]=='=')
|
||||
pos++;
|
||||
add = it->second->derive(key.substr(pos));
|
||||
if (add==NULL) {
|
||||
m_lastError = "derive condition with values "+key.substr(pos)+" failed";
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
m_conditions[key] = add; // store derived condition
|
||||
}
|
||||
}
|
||||
if (add==NULL) {
|
||||
// shared condition not available
|
||||
m_lastError = "condition "+types.substr(1, pos-1)+" not defined";
|
||||
return RESULT_ERR_NOTFOUND;
|
||||
}
|
||||
} else {
|
||||
add = it->second;
|
||||
}
|
||||
if (condition) {
|
||||
condition = condition->combineAnd(it->second);
|
||||
condition = condition->combineAnd(add);
|
||||
store = true;
|
||||
} else
|
||||
condition = it->second;
|
||||
} else {
|
||||
condition = add;
|
||||
}
|
||||
types = types.substr(pos+1);
|
||||
if (types.length()==0 || types[0]!='[')
|
||||
break;
|
||||
@@ -1321,7 +1461,25 @@ result_t MessageMap::addFromFile(vector<string>::iterator& begin, const vector<s
|
||||
result_t result = readConditions(types, filename, condition);
|
||||
if (result!=RESULT_OK)
|
||||
return result;
|
||||
|
||||
if (types.length()>0 && types[0]=='!') {
|
||||
// instruction
|
||||
types = types.substr(1);
|
||||
Instruction* instruction = NULL;
|
||||
result_t result = Instruction::create(filename, condition, types, ++begin, end, instruction);
|
||||
if (instruction==NULL || result!=RESULT_OK) {
|
||||
m_lastError = "invalid instruction";
|
||||
return result;
|
||||
}
|
||||
map<string, vector<Instruction*> >::iterator it = m_instructions.find(filename);
|
||||
if (it == m_instructions.end()) {
|
||||
vector<Instruction*> instructions;
|
||||
instructions.push_back(instruction);
|
||||
m_instructions[filename] = instructions;
|
||||
} else {
|
||||
it->second.push_back(instruction);
|
||||
}
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (types.length() == 0)
|
||||
types.append("r");
|
||||
else if (types.find(']')!=string::npos)
|
||||
@@ -1375,19 +1533,71 @@ result_t MessageMap::resolveConditions(bool verbose) {
|
||||
result_t overallResult = RESULT_OK;
|
||||
for (map<string, Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
|
||||
Condition* condition = it->second;
|
||||
ostringstream error;
|
||||
result_t result = condition->resolve(this, error);
|
||||
result_t result = resolveCondition(condition);
|
||||
if (result!=RESULT_OK) {
|
||||
string errorMessage = error.str();
|
||||
if (errorMessage.length()>0) {
|
||||
if (m_lastError.length()>0)
|
||||
m_lastError += ", ";
|
||||
m_lastError += errorMessage;
|
||||
overallResult = result;
|
||||
}
|
||||
}
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
result_t MessageMap::resolveCondition(Condition* condition) {
|
||||
ostringstream error;
|
||||
result_t result = condition->resolve(this, error);
|
||||
if (result!=RESULT_OK) {
|
||||
string errorMessage = error.str();
|
||||
if (errorMessage.length()>0) {
|
||||
if (m_lastError.length()>0)
|
||||
m_lastError += ", ";
|
||||
m_lastError += errorMessage;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
result_t MessageMap::executeInstructions(bool verbose) {
|
||||
result_t overallResult = RESULT_OK;
|
||||
for (map<string, vector<Instruction*> >::iterator it = m_instructions.begin(); it != m_instructions.end(); it++) {
|
||||
vector<Instruction*> instructions = it->second;
|
||||
bool removeSingletons = false;
|
||||
for (vector<Instruction*>::iterator lit = instructions.begin(); lit != instructions.end(); lit++) {
|
||||
Instruction* instruction = *lit;
|
||||
if (removeSingletons && instruction->isSingleton()) {
|
||||
continue;
|
||||
}
|
||||
if (verbose)
|
||||
overallResult = result;
|
||||
else {
|
||||
return result;
|
||||
Condition* condition = instruction->getCondition();
|
||||
bool execute = condition==NULL;
|
||||
if (!execute) {
|
||||
result_t result = resolveCondition(condition);
|
||||
if (result!=RESULT_OK) {
|
||||
overallResult = result;
|
||||
} else if (condition->isTrue()) {
|
||||
execute = true;
|
||||
}
|
||||
}
|
||||
if (execute) {
|
||||
if (instruction->isSingleton())
|
||||
removeSingletons = true;
|
||||
result_t result = instruction->execute(this);
|
||||
if (result!=RESULT_OK) {
|
||||
overallResult = result;
|
||||
}
|
||||
delete instruction;
|
||||
instructions.erase(lit--);
|
||||
}
|
||||
}
|
||||
if (removeSingletons) {
|
||||
for (vector<Instruction*>::iterator lit = instructions.begin(); lit != instructions.end(); lit++) {
|
||||
Instruction* instruction = *lit;
|
||||
if (!instruction->isSingleton()) {
|
||||
continue;
|
||||
}
|
||||
delete instruction;
|
||||
instructions.erase(lit);
|
||||
lit--;
|
||||
}
|
||||
if (instructions.empty()) {
|
||||
m_instructions.erase(it--);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1609,6 +1819,15 @@ void MessageMap::clear()
|
||||
for (map<string, Condition*>::iterator it = m_conditions.begin(); it != m_conditions.end(); it++) {
|
||||
delete it->second;
|
||||
}
|
||||
// free instruction instances
|
||||
for (map<string, vector<Instruction*> >::iterator it = m_instructions.begin(); it != m_instructions.end(); it++) {
|
||||
vector<Instruction*> instructions = it->second;
|
||||
for (vector<Instruction*>::iterator lit = instructions.begin(); lit != instructions.end(); lit++) {
|
||||
Instruction* instruction = *lit;
|
||||
delete instruction;
|
||||
}
|
||||
instructions.clear();
|
||||
}
|
||||
// clear messages by name
|
||||
m_messageCount = 0;
|
||||
m_conditionalMessageCount = 0;
|
||||
@@ -1617,6 +1836,7 @@ void MessageMap::clear()
|
||||
// clear messages by key
|
||||
m_messagesByKey.clear();
|
||||
m_conditions.clear();
|
||||
m_instructions.clear();
|
||||
m_maxIdLength = 0;
|
||||
}
|
||||
|
||||
|
||||
+228
-13
@@ -237,7 +237,7 @@ public:
|
||||
* @param other the other @a Message to check against.
|
||||
* @return true if the ID matches, false otherwise.
|
||||
*/
|
||||
bool checkId(Message& other);
|
||||
virtual bool checkId(Message& other);
|
||||
|
||||
/**
|
||||
* Return the key for storing in @a MessageMap.
|
||||
@@ -565,6 +565,9 @@ public:
|
||||
// @copydoc
|
||||
virtual bool checkId(SymbolString& master, unsigned char* index=NULL);
|
||||
|
||||
// @copydoc
|
||||
virtual bool checkId(Message& other);
|
||||
|
||||
// @copydoc
|
||||
virtual unsigned char getCount() { return (unsigned char)m_ids.size(); }
|
||||
|
||||
@@ -680,6 +683,13 @@ public:
|
||||
*/
|
||||
static result_t create(const string condName, vector<string>::iterator& it, const vector<string>::iterator end, string defaultDest, string defaultCircuit, SimpleCondition*& returnValue);
|
||||
|
||||
/**
|
||||
* Derive a new @a SimpleCondition from this condition.
|
||||
* @param valueList the @a string with the new list of values.
|
||||
* @return the derived @a SimpleCondition instance, or NULL if the value list is invalid.
|
||||
*/
|
||||
virtual SimpleCondition* derive(string valueList) { return NULL; };
|
||||
|
||||
/**
|
||||
* Write the condition definition to the @a ostream.
|
||||
* @param output the @a ostream to append to.
|
||||
@@ -719,7 +729,7 @@ protected:
|
||||
|
||||
|
||||
/**
|
||||
* A simple condition based on the value of one @a Message.
|
||||
* A simple @a Condition based on the value of one @a Message.
|
||||
*/
|
||||
class SimpleCondition : public Condition
|
||||
{
|
||||
@@ -732,18 +742,20 @@ public:
|
||||
* @param name the message name, or empty for scan message.
|
||||
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message).
|
||||
* @param field the field name.
|
||||
* @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check.
|
||||
* @param hasValues whether a value has to be checked against.
|
||||
*/
|
||||
SimpleCondition(const string condName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
|
||||
SimpleCondition(const string condName, const string circuit, const string name, const unsigned char dstAddress, const string field, const bool hasValues=false)
|
||||
: Condition(),
|
||||
m_condName(condName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field),
|
||||
m_valueRanges(valueRanges), m_message(NULL) { }
|
||||
m_condName(condName), m_circuit(circuit), m_name(name), m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SimpleCondition() {}
|
||||
|
||||
// @copydoc
|
||||
virtual SimpleCondition* derive(string valueList);
|
||||
|
||||
// @copydoc
|
||||
virtual void dump(ostream& output);
|
||||
|
||||
@@ -758,12 +770,25 @@ public:
|
||||
*/
|
||||
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage);
|
||||
|
||||
/**
|
||||
* Check and return whether this condition is fulfilled.
|
||||
* @return whether this condition is fulfilled.
|
||||
*/
|
||||
// @copydoc
|
||||
virtual bool isTrue();
|
||||
|
||||
/**
|
||||
* Return whether the condition is based on a numeric value.
|
||||
* @return whether the condition is based on a numeric value.
|
||||
*/
|
||||
virtual bool isNumeric() { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Check the values against the field in the @a Message.
|
||||
* @param message the @a Message to check against.
|
||||
* @param field the field name to check against, or empty for first field.
|
||||
* @return whether the field matches one of the valid values.
|
||||
*/
|
||||
virtual bool checkValue(Message* message, const string field) { return true; }
|
||||
|
||||
private:
|
||||
|
||||
/** the condition name. */
|
||||
@@ -781,8 +806,8 @@ private:
|
||||
/** the field name, or empty for first field. */
|
||||
const string m_field;
|
||||
|
||||
/** the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */
|
||||
const vector<unsigned int> m_valueRanges;
|
||||
/** whether a value has to be checked against. */
|
||||
const bool m_hasValues;
|
||||
|
||||
/** the resolved @a Message instance, or NULL. */
|
||||
Message* m_message;
|
||||
@@ -791,7 +816,86 @@ private:
|
||||
|
||||
|
||||
/**
|
||||
* A condition combining two or more @a SimpleCondition instances with a logical and.
|
||||
* A simple @a Condition based on the numeric value of one @a Message.
|
||||
*/
|
||||
class SimpleNumericCondition : public SimpleCondition
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
* @param circuit the circuit name.
|
||||
* @param name the message name, or empty for scan message.
|
||||
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message).
|
||||
* @param field the field name.
|
||||
* @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check.
|
||||
*/
|
||||
SimpleNumericCondition(const string condName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<unsigned int> valueRanges)
|
||||
: SimpleCondition(condName, circuit, name, dstAddress, field, true),
|
||||
m_valueRanges(valueRanges) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SimpleNumericCondition() {}
|
||||
|
||||
protected:
|
||||
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
private:
|
||||
|
||||
/** the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */
|
||||
const vector<unsigned int> m_valueRanges;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A simple @a Condition based on the string value of one @a Message.
|
||||
*/
|
||||
class SimpleStringCondition : public SimpleCondition
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condName the name of the condition.
|
||||
* @param circuit the circuit name.
|
||||
* @param name the message name, or empty for scan message.
|
||||
* @param dstAddress the override destination address, or @a SYN (only for @a Message without specific destination as well as scan message).
|
||||
* @param field the field name.
|
||||
* @param values the valid values.
|
||||
*/
|
||||
SimpleStringCondition(const string condName, const string circuit, const string name, const unsigned char dstAddress, const string field, const vector<string> values)
|
||||
: SimpleCondition(condName, circuit, name, dstAddress, field, true),
|
||||
m_values(values) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~SimpleStringCondition() {}
|
||||
|
||||
// @copydoc
|
||||
virtual bool isNumeric() { return false; }
|
||||
|
||||
protected:
|
||||
|
||||
// @copydoc
|
||||
virtual bool checkValue(Message* message, const string field);
|
||||
|
||||
private:
|
||||
|
||||
/** the valid values. */
|
||||
const vector<string> m_values;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A @a Condition combining two or more @a SimpleCondition instances with a logical and.
|
||||
*/
|
||||
class CombinedCondition : public Condition
|
||||
{
|
||||
@@ -828,6 +932,100 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An abstract instruction based on the value of one or more @a Message instances.
|
||||
*/
|
||||
class Instruction
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
*/
|
||||
Instruction(Condition* condition, const bool singleton)
|
||||
: m_condition(condition), m_singleton(singleton) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Instruction() { }
|
||||
|
||||
/**
|
||||
* Factory method for creating a new instance.
|
||||
* @param contextPath the path and/or filename context being loaded.
|
||||
* @param condition the @a Condition for the instruction, or NULL.
|
||||
* @param type the type of the instruction.
|
||||
* @param it the iterator to traverse for the definition parts.
|
||||
* @param end the iterator pointing to the end of the definition parts.
|
||||
* @param returnValue the variable in which to store the created instance.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
static result_t create(const string contextPath, Condition* condition, const string type, vector<string>::iterator& it, const vector<string>::iterator end, Instruction*& returnValue);
|
||||
|
||||
/**
|
||||
* Return the @a Condition this instruction requires.
|
||||
* @return the @a Condition this instruction requires, or null.
|
||||
*/
|
||||
Condition* getCondition() { return m_condition; }
|
||||
|
||||
/**
|
||||
* Return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* @return whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
*/
|
||||
bool isSingleton() { return m_singleton; }
|
||||
|
||||
/**
|
||||
* Execute the instruction.
|
||||
* @param messages the @a MessageMap.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
virtual result_t execute(MessageMap* messages) = 0;
|
||||
|
||||
private:
|
||||
|
||||
/** the @a Condition this instruction requires, or null. */
|
||||
Condition* m_condition;
|
||||
|
||||
/** whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file. */
|
||||
bool m_singleton;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An @a Instruction allowing to load another file.
|
||||
*/
|
||||
class LoadInstruction : public Instruction
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a new instance.
|
||||
* @param condition the @a Condition this instruction requires, or null.
|
||||
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be executed for the same source file.
|
||||
* @param filename the name of the file to load.
|
||||
*/
|
||||
LoadInstruction(Condition* condition, const bool singleton, const string filename)
|
||||
: Instruction(condition, singleton), m_filename(filename) { }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~LoadInstruction() { }
|
||||
|
||||
// @copydoc
|
||||
virtual result_t execute(MessageMap* messages);
|
||||
|
||||
private:
|
||||
|
||||
/** the name of the file to load. */
|
||||
const string m_filename;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Holds a map of all known @a Message instances.
|
||||
*/
|
||||
@@ -895,6 +1093,20 @@ public:
|
||||
*/
|
||||
result_t resolveConditions(bool verbose=false);
|
||||
|
||||
/**
|
||||
* Resolve a @a Condition.
|
||||
* @param condition the @a Condition to resolve.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
result_t resolveCondition(Condition* condition);
|
||||
|
||||
/**
|
||||
* Run all executable @a Instruction instances.
|
||||
* @param verbose whether to verbosely add all problems to the error message.
|
||||
* @return @a RESULT_OK on success, or an error code.
|
||||
*/
|
||||
result_t executeInstructions(bool verbose);
|
||||
|
||||
/**
|
||||
* Get the stored @a Message instances for the key.
|
||||
* @param key the key of the @a Message.
|
||||
@@ -1037,6 +1249,9 @@ private:
|
||||
/** the @a Condition instances by filename and condition name. */
|
||||
map<string, Condition*> m_conditions;
|
||||
|
||||
/** the list of @a Instruction instances by filename. */
|
||||
map<string, vector<Instruction*> > m_instructions;
|
||||
|
||||
};
|
||||
|
||||
#endif // LIBEBUS_MESSAGE_H_
|
||||
|
||||
Reference in New Issue
Block a user