/* * Copyright (C) John Baier 2014 * * This file is part of ebusd. * * ebusd is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ebusd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ebusd. If not, see http://www.gnu.org/licenses/. */ #ifndef LIBEBUS_FILEREADER_H_ #define LIBEBUS_FILEREADER_H_ #include "symbol.h" #include "result.h" #include #include #include #include #include #include using namespace std; /** the separator character used between fields. */ #define FIELD_SEPARATOR ',' /** the separator character used to quote text having the @a FIELD_SEPARATOR in it. */ #define TEXT_SEPARATOR '"' /** * @brief An abstract class that support reading definitions from a file. */ template class FileReader { public: /** * @brief Constructs a new instance. */ FileReader(bool supportsDefaults) : m_supportsDefaults(supportsDefaults) {} /** * @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(const string filename, T arg=NULL) { ifstream ifs; ifs.open(filename.c_str(), ifstream::in); if (ifs.is_open() == false) return RESULT_ERR_NOTFOUND; string line; unsigned int lineNo = 0; vector row; string token; vector< vector > defaults; while (getline(ifs, line) != 0) { lineNo++; // skip empty lines and comments size_t length = line.length(); if (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/')) continue; row.clear(); bool quotedText = false; ostringstream field; char prev = FIELD_SEPARATOR; for (size_t pos = 0; pos < length; pos++) { char ch = line[pos]; switch (ch) { case FIELD_SEPARATOR: if (quotedText == true) field << ch; else { row.push_back(field.str()); field.str(""); } break; case TEXT_SEPARATOR: if (quotedText == true) { quotedText = false; } else if (prev == TEXT_SEPARATOR) { // double dquote quotedText = true; field << ch; } else if (prev == FIELD_SEPARATOR) { quotedText = true; } else field << ch; break; case '\r': break; default: field << ch; break; } prev = ch; } row.push_back(field.str()); result_t result; if (m_supportsDefaults == true) { if (line[0] == '*') { row[0] = row[0].substr(1); defaults.push_back(row); continue; } result = addFromFile(row, arg, &defaults, filename, lineNo); } else result = addFromFile(row, arg, NULL, filename, lineNo); 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. * @param defaults all previously read default rows (initial star char removed), or NULL if not supported. * @return @a RESULT_OK on success, or an error code. */ virtual result_t addFromFile(vector& row, T arg, vector< vector >* defaults, const string& filename, unsigned int lineNo) = 0; private: /** whether this instance supports rows with defaults (starting with a star). */ bool m_supportsDefaults; }; #endif // LIBEBUS_FILEREADER_H_