From 922217602bdd8f5b53ce10e4b0b44609bca11fb6 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 23 Nov 2014 20:25:48 +0100 Subject: [PATCH] added FileReader --- src/lib/ebus/data.cpp | 19 +++++++- src/lib/ebus/data.h | 72 +++++++++++++++++++++++++++++- src/lib/ebus/message.cpp | 17 ++++++- src/lib/ebus/message.h | 5 ++- src/lib/ebus/test/test_message.cpp | 59 +++++------------------- 5 files changed, 120 insertions(+), 52 deletions(-) diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index 7c1ee862..f619a757 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -69,7 +69,6 @@ static const dataType_t dataTypes[] = { /** the week day names. */ static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; -#define FIELD_SEPARATOR ';' #define VALUE_SEPARATOR ',' #define LENGTH_SEPARATOR ':' #define NULL_VALUE "-" @@ -1048,7 +1047,7 @@ result_t DataFieldTemplates::add(DataField* field, bool replace) map::iterator it = m_fieldsByName.find(name); if (it != m_fieldsByName.end()) { if (replace == false) - return RESULT_ERR_INVALID_ARG; // duplicate key + return RESULT_ERR_DUPLICATE; // duplicate key delete it->second; it->second = field; @@ -1061,6 +1060,21 @@ result_t DataFieldTemplates::add(DataField* field, bool replace) return RESULT_OK; } +result_t DataFieldTemplates::addFromFile(vector& row, void* arg) +{ + DataField* field = NULL; + vector::iterator it = row.begin(); + result_t result = DataField::create(it, row.end(), this, field); + if (result != RESULT_OK) + return result; + + result = add(field); + if (result != RESULT_OK) + delete field; + + return result; +} + DataField* DataFieldTemplates::get(const string name) { map::const_iterator ref = m_fieldsByName.find(name); @@ -1069,3 +1083,4 @@ DataField* DataFieldTemplates::get(const string name) return ref->second; } + diff --git a/src/lib/ebus/data.h b/src/lib/ebus/data.h index 874bbe61..8117a9da 100644 --- a/src/lib/ebus/data.h +++ b/src/lib/ebus/data.h @@ -23,11 +23,16 @@ #include "symbol.h" #include "result.h" #include +#include +#include +#include #include #include using namespace std; +#define FIELD_SEPARATOR ';' + /** the message part in which a data field is stored. */ enum PartType { pt_any, // stored in any data (master or slave) @@ -554,10 +559,73 @@ private: }; +/** + * @brief An abstract class that support reading definitions from a file. + */ +template +class FileReader +{ +public: + + /** + * @brief Constructs a new instance. + */ + FileReader() {} + /** + * @brief Destructor. + */ + virtual ~FileReader() {} + /** + * @brief Reads the definitions from a file. + * @param filename the name (and path) of the file to read. + * @return @a RESULT_OK on success, or an error code. + */ + virtual result_t readFromFile(string filename, T arg=NULL) + { + ifstream ifs; + ifs.open(filename.c_str(), ifstream::in); + if (ifs.is_open() == false) + return RESULT_ERR_FILENOTFOUND; + + string line; + unsigned int lineNo = 0; + vector row; + string token; + while (getline(ifs, line) != 0) { + lineNo++; + // skip empty lines and comments + if (line.length() == 0 || line.substr(0, 1) == "#" || line.substr(0, 2) == "//") + continue; + istringstream isstr(line); + row.clear(); + while (getline(isstr, token, FIELD_SEPARATOR) != 0) + row.push_back(token); + + result_t result = addFromFile(row, arg); + if (result != RESULT_OK) { + cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; + ifs.close(); + return result; + } + } + + ifs.close(); + return RESULT_OK; + } + /** + * @brief Adds a definition that was read from a file. + * @param row the definition row read from the file. + * @return @a RESULT_OK on success, or an error code. + */ + virtual result_t addFromFile(vector& row, T arg) = 0; + +}; + + /** * @brief A map of template @a DataField instances. */ -class DataFieldTemplates +class DataFieldTemplates : public FileReader { public: @@ -581,6 +649,8 @@ public: * Note: the caller may not free the added instance on success. */ result_t add(DataField* message, bool replace=false); + // @copydoc + virtual result_t addFromFile(vector& row, void* arg); /** * @brief Gets the template @a DataField instance with the specified name. * @return the template @a DataField instance, or NULL. diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 60412223..ecdfc467 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -210,7 +210,7 @@ result_t MessageMap::add(Message* message) unsigned long long pkey = message->getKey(); map::iterator keyIt = m_passiveMessagesByKey.find(pkey); if (keyIt != m_passiveMessagesByKey.end()) - return RESULT_ERR_INVALID_ARG; // duplicate key + return RESULT_ERR_DUPLICATE; // duplicate key unsigned char idLength = message->getId().size() - 2; if (idLength > m_maxIdLength) @@ -223,6 +223,21 @@ result_t MessageMap::add(Message* message) return RESULT_OK; } +result_t MessageMap::addFromFile(vector& row, DataFieldTemplates* arg) +{ + Message* message = NULL; + vector::iterator it = row.begin(); + result_t result = Message::create(it, row.end(), arg, message); + if (result != RESULT_OK) + return result; + + result = add(message); + if (result != RESULT_OK) + delete message; + + return result; +} + Message* MessageMap::find(const string clazz, const string name, const bool isActive, const bool isSet) { string key = clazz; diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 195b8664..a373c668 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -176,7 +176,7 @@ private: /** * @brief Holds a map of all known @a Message instances. */ -class MessageMap +class MessageMap : public FileReader { public: @@ -195,6 +195,8 @@ public: * Note: the caller may not free the added instance on success. */ result_t add(Message* message); + // @copydoc + virtual result_t addFromFile(vector& row, DataFieldTemplates* arg); /** * @brief Finds the @a Message instance for the specified class and name. * @param master the master @a SymbolString for identifying the @a Message. @@ -214,6 +216,7 @@ public: */ void clear(); + private: /** the maximum ID length used by any of the known @a Message instances. */ diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 3b7b2410..389d845f 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -66,51 +66,6 @@ void printErrorPos(vector::iterator it, const vector::iterator e cout << setw(cnt) << " " << setw(0) << "^" << endl; } -bool readTemplates(string filename, DataFieldTemplates* templates) -{ - ifstream ifs; - ifs.open(filename.c_str(), ifstream::in); - if (ifs.is_open() == false) { - cerr << "error reading \"" << filename << endl; - return false; - } - - string line; - unsigned int lineNo = 0; - vector row; - string token; - while (getline(ifs, line) != 0) { - lineNo++; - istringstream isstr(line); - row.clear(); - while (getline(isstr, token, ';') != 0) - row.push_back(token); - - // skip empty and commented rows - if (row.empty() == true || row[0][0] == '#') - continue; - - DataField* field = NULL; - vector::iterator it = row.begin(); - result_t result = DataField::create(it, row.end(), templates, field); - if (result != RESULT_OK) { - cerr << "error reading \"" << filename << "\" line " << static_cast(lineNo) << ": " << getResultCode(result) << endl; - printErrorPos(row.begin(), row.end(), it); - } else if (it != row.end()) - cout << "extra data in \"" << filename << "\" line " << static_cast(lineNo) << endl; - else { - result = templates->add(field, true); - if (result != RESULT_OK) { - cerr << "error adding template \"" << field->getName() << "\": " << getResultCode(result) << endl; - delete field; - } - } - } - - ifs.close(); - return true; -} - int main() { // message= [type];class;name;[comment];[QQ];ZZ;PBSB;fields... @@ -124,11 +79,21 @@ int main() {"c;ehp;ActualEnvironmentPower;Energiebezug;;08;B50929BA00;;s;IGN:2;;;;;s;power", "8", "1008b5090329ba00", "03ba0008", "p"}, }; DataFieldTemplates* templates = new DataFieldTemplates(); - readTemplates("_types.csv", templates); + result_t result = templates->readFromFile("_types.csv"); + if (result == RESULT_OK) + cout << "read templates OK" << endl; + else + cout << "read templates error: " << getResultCode(result) << endl; + + MessageMap* messages = new MessageMap(); + result = messages->readFromFile("ehp00.csv", templates); + if (result == RESULT_OK) + cout << "read messages OK" << endl; + else + cout << "read messages error: " << getResultCode(result) << endl; Message *message = NULL; Message* deleteMessage = NULL; - MessageMap* messages = new MessageMap(); for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; istringstream isstr(check[0]);