added support for retrieving configuration files from config service URL and changed that to be the default, always store loaded files by relative path, changed FileReader to allow reading from stream as well

This commit is contained in:
john30
2018-04-04 10:08:46 +02:00
parent a77b740720
commit a36174c02f
10 changed files with 238 additions and 148 deletions
Regular → Executable
-1
View File
@@ -13,7 +13,6 @@ set(PACKAGE_BUGREPORT "ebusd@ebusd.eu")
set(PACKAGE_URL "https://github.com/john30/ebusd") set(PACKAGE_URL "https://github.com/john30/ebusd")
set(PACKAGE_PIDFILE "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/run/${PACKAGE}.pid") set(PACKAGE_PIDFILE "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/run/${PACKAGE}.pid")
set(PACKAGE_LOGFILE "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/${PACKAGE}.log") set(PACKAGE_LOGFILE "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/log/${PACKAGE}.log")
set(PACKAGE_CONFIGPATH "${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PACKAGE}")
execute_process(COMMAND echo -n ${VERSION} execute_process(COMMAND echo -n ${VERSION}
COMMAND sed "-e" "s/^\\([0-9]*\\.[0-9]*\\).*/\\1/" "-e" "s/\\.\\([0-9]\\)\$/0\\1/" "-e" "s/\\.//" COMMAND sed "-e" "s/^\\([0-9]*\\.[0-9]*\\).*/\\1/" "-e" "s/\\.\\([0-9]\\)\$/0\\1/" "-e" "s/\\.//"
OUTPUT_VARIABLE SCAN_VERSION) OUTPUT_VARIABLE SCAN_VERSION)
Regular → Executable
-3
View File
@@ -25,9 +25,6 @@
/* The address where bug reports for this package should be sent. */ /* The address where bug reports for this package should be sent. */
#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}" #cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}"
/* The default path of the configuration files. */
#define PACKAGE_CONFIGPATH SYSCONFDIR "/" PACKAGE
/* The path and name of the log file. */ /* The path and name of the log file. */
#define PACKAGE_LOGFILE LOCALSTATEDIR "/log/" PACKAGE ".log" #define PACKAGE_LOGFILE LOCALSTATEDIR "/log/" PACKAGE ".log"
Regular → Executable
-1
View File
@@ -119,7 +119,6 @@ AM_COND_IF([CONTRIB], [AC_CONFIG_FILES([
AC_DEFINE_UNQUOTED(PACKAGE_PIDFILE, LOCALSTATEDIR "/run/" PACKAGE ".pid", [The path and name of the PID file.]) AC_DEFINE_UNQUOTED(PACKAGE_PIDFILE, LOCALSTATEDIR "/run/" PACKAGE ".pid", [The path and name of the PID file.])
AC_DEFINE_UNQUOTED(PACKAGE_LOGFILE, LOCALSTATEDIR "/log/" PACKAGE ".log", [The path and name of the log file.]) AC_DEFINE_UNQUOTED(PACKAGE_LOGFILE, LOCALSTATEDIR "/log/" PACKAGE ".log", [The path and name of the log file.])
AC_DEFINE_UNQUOTED(PACKAGE_CONFIGPATH, SYSCONFDIR "/" PACKAGE, [The default path of the configuration files.])
AC_DEFINE(SCAN_VERSION, "[m4_esyscmd_s([sed -e 's#^\([0-9]*\.[0-9]*\).*#\1#' -e 's#\.\([0-9]\)$#0\1#' -e 's#\.##' VERSION])]", [The version of the package formatted for the scan result.]) AC_DEFINE(SCAN_VERSION, "[m4_esyscmd_s([sed -e 's#^\([0-9]*\.[0-9]*\).*#\1#' -e 's#\.\([0-9]\)$#0\1#' -e 's#\.##' VERSION])]", [The version of the package formatted for the scan result.])
AC_DEFINE(REVISION, "[m4_esyscmd_s([git describe --always 2>/dev/null || (date +p%Y%m%d)])]", [The revision of the package.]) AC_DEFINE(REVISION, "[m4_esyscmd_s([git describe --always 2>/dev/null || (date +p%Y%m%d)])]", [The revision of the package.])
+153 -69
View File
@@ -32,6 +32,7 @@
#include <vector> #include <vector>
#include "ebusd/mainloop.h" #include "ebusd/mainloop.h"
#include "lib/utils/log.h" #include "lib/utils/log.h"
#include "lib/utils/httpclient.h"
/** the version string of the program. */ /** the version string of the program. */
@@ -64,11 +65,7 @@ using std::cout;
#endif #endif
/** the default path of the configuration files. */ /** the default path of the configuration files. */
#ifdef PACKAGE_CONFIGPATH #define CONFIG_PATH "http://ebusd.eu/config/"
#define CONFIG_PATH PACKAGE_CONFIGPATH
#else
#define CONFIG_PATH "/etc/ebusd"
#endif
/** the opened PID file, or NULL. */ /** the opened PID file, or NULL. */
static FILE* pidFile = NULL; static FILE* pidFile = NULL;
@@ -133,6 +130,15 @@ static MessageMap* s_messageMap = NULL;
/** the @a MainLoop instance, or NULL. */ /** the @a MainLoop instance, or NULL. */
static MainLoop* s_mainLoop = NULL; static MainLoop* s_mainLoop = NULL;
/** the path prefix (including trailing "/") for retrieving configuration files from local file system (empty for HTTP). */
static string s_configLocalPrefix;
/** the URI prefix (including trailing "/") for retrieving configuration files from HTTP (empty for local files). */
static string s_configUriPrefix;
/** the @a HttpClient for retrieving configuration files from HTTP. */
static HttpClient s_configHttpClient;
/** the documentation of the program. */ /** the documentation of the program. */
static const char argpdoc[] = static const char argpdoc[] =
"A daemon for communication with eBUS heating systems."; "A daemon for communication with eBUS heating systems.";
@@ -239,7 +245,7 @@ static const struct argp_option argpoptions[] = {
static DataFieldTemplates s_globalTemplates; static DataFieldTemplates s_globalTemplates;
/** /**
* the loaded @a DataFieldTemplates by path (may also carry * the loaded @a DataFieldTemplates by relative path (may also carry
* @a globalTemplates as replacement for missing file). * @a globalTemplates as replacement for missing file).
*/ */
static map<string, DataFieldTemplates*> s_templatesByPath; static map<string, DataFieldTemplates*> s_templatesByPath;
@@ -717,37 +723,62 @@ void signalHandler(int sig) {
/** /**
* Collect configuration files matching the prefix and extension from the specified path. * Collect configuration files matching the prefix and extension from the specified path.
* @param path the path from which to collect the files. * @param relPath the relative path from which to collect the files (without trailing "/").
* @param prefix the filename prefix the files have to match, or empty. * @param prefix the filename prefix the files have to match, or empty.
* @param extension the filename extension the files have to match. * @param extension the filename extension the files have to match.
* @param files the @a vector to which to add the matching files. * @param files the @a vector to which to add the matching files.
* @param query the query string suffix for HTTP retrieval starting with "&", or empty.
* @param dirs the @a vector to which to add found directories (without any name check), or NULL to ignore. * @param dirs the @a vector to which to add found directories (without any name check), or NULL to ignore.
* @param hasTemplates the bool to set when the templates file was found in the path, or NULL to ignore. * @param hasTemplates the bool to set when the templates file was found in the path, or NULL to ignore.
* @return the result code. * @return the result code.
*/ */
static result_t collectConfigFiles(const string path, const string prefix, const string extension, static result_t collectConfigFiles(const string& relPath, const string& prefix, const string& extension,
vector<string>* files, vector<string>* dirs = NULL, bool* hasTemplates = NULL) { vector<string>* files, const bool ignoreAddressPrefix = false, const string& query = "", vector<string>* dirs = NULL,
bool* hasTemplates = NULL) {
const string relPathWithSlash = relPath.empty() ? "" : relPath + "/";
if (!s_configUriPrefix.empty()) {
string names;
if (!s_configHttpClient.get(s_configUriPrefix + relPathWithSlash + "?t=" + (extension.substr(1)) + query, "", names)) {
return RESULT_ERR_NOTFOUND;
}
istringstream stream(names);
string name;
while (getline(stream, name)) {
if (name.empty()) {
continue;
}
if (name == "_templates"+extension) {
if (hasTemplates) {
*hasTemplates = true;
}
continue;
}
if (prefix.length() == 0 ? (!ignoreAddressPrefix || name.length() < 3 || name.find_first_of('.') != 2)
: (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
files->push_back(relPathWithSlash + name);
}
}
return RESULT_OK;
}
const string path = s_configLocalPrefix + relPathWithSlash;
DIR* dir = opendir(path.c_str()); DIR* dir = opendir(path.c_str());
if (dir == NULL) { if (dir == NULL) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
dirent* d; dirent* d;
while ((d = readdir(dir)) != NULL) { while ((d = readdir(dir)) != NULL) {
string name = d->d_name; string name = d->d_name;
if (name == "." || name == "..") { if (name == "." || name == "..") {
continue; continue;
} }
const string p = path + "/" + name; const string p = path + name;
struct stat stat_buf; struct stat stat_buf;
if (stat(p.c_str(), &stat_buf) != 0) { if (stat(p.c_str(), &stat_buf) != 0) {
continue; continue;
} }
if (S_ISDIR(stat_buf.st_mode)) { if (S_ISDIR(stat_buf.st_mode)) {
if (dirs != NULL) { if (dirs != NULL) {
dirs->push_back(p); dirs->push_back(relPathWithSlash + name);
} }
} else if (S_ISREG(stat_buf.st_mode) && name.length() >= extension.length() } else if (S_ISREG(stat_buf.st_mode) && name.length() >= extension.length()
&& name.substr(name.length()-extension.length()) == extension) { && name.substr(name.length()-extension.length()) == extension) {
@@ -755,9 +786,11 @@ static result_t collectConfigFiles(const string path, const string prefix, const
if (hasTemplates) { if (hasTemplates) {
*hasTemplates = true; *hasTemplates = true;
} }
} else if (prefix.length() == 0 continue;
|| (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) { }
files->push_back(p); if (prefix.length() == 0 ? (!ignoreAddressPrefix || name.length() < 3 || name.find_first_of('.') != 2)
: (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
files->push_back(relPathWithSlash + name);
} }
} }
} }
@@ -781,63 +814,65 @@ DataFieldTemplates* getTemplates(const string& filename) {
/** /**
* Read the @a DataFieldTemplates for the specified path if necessary. * Read the @a DataFieldTemplates for the specified path if necessary.
* @param path the path from which to read the files. * @param relPath the relative path from which to read the files (without trailing "/").
* @param extension the filename extension of the files to read. * @param extension the filename extension of the files to read.
* @param available whether the templates file is available in the path. * @param available whether the templates file is available in the path.
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @return false when the templates for the path were already loaded before, true when the templates for the path were added (independent from @a available). * @return false when the templates for the path were already loaded before, true when the templates for the path were added (independent from @a available).
* @return the @a DataFieldTemplates. * @return the @a DataFieldTemplates.
*/ */
static bool readTemplates(const string path, const string extension, bool available, bool verbose = false) { static bool readTemplates(const string relPath, const string extension, bool available, bool verbose = false) {
const auto it = s_templatesByPath.find(path); const auto it = s_templatesByPath.find(relPath);
if (it != s_templatesByPath.end()) { if (it != s_templatesByPath.end()) {
return false; return false;
} }
DataFieldTemplates* templates; DataFieldTemplates* templates;
if (path == opt.configPath || !available) { if (relPath.empty() || !available) {
templates = &s_globalTemplates; templates = &s_globalTemplates;
} else { } else {
templates = new DataFieldTemplates(s_globalTemplates); templates = new DataFieldTemplates(s_globalTemplates);
} }
s_templatesByPath[path] = templates; s_templatesByPath[relPath] = templates;
if (!available) { if (!available) {
// global templates are stored as replacement in order to determine whether the directory was already loaded // global templates are stored as replacement in order to determine whether the directory was already loaded
return true; return true;
} }
string errorDescription; string errorDescription;
logInfo(lf_main, "reading templates %s", path.c_str()); string logPath = relPath.empty() ? "/" : relPath;
result_t result = templates->readFromFile(path+"/_templates"+extension, verbose, NULL, &errorDescription, logInfo(lf_main, "reading templates %s", logPath.c_str());
NULL, NULL, NULL); string file = (relPath.empty() ? "" : relPath + "/") + "_templates" + extension;
result_t result = loadDefinitionsFromConfigPath(templates, file, verbose, NULL, &errorDescription);
if (result == RESULT_OK) { if (result == RESULT_OK) {
logInfo(lf_main, "read templates in %s", path.c_str()); logInfo(lf_main, "read templates in %s", logPath.c_str());
return true; return true;
} }
logError(lf_main, "error reading templates in %s: %s, last error: %s", path.c_str(), getResultCode(result), logError(lf_main, "error reading templates in %s: %s, last error: %s", logPath.c_str(), getResultCode(result),
errorDescription.c_str()); errorDescription.c_str());
return false; return false;
} }
/** /**
* Read the configuration files from the specified path. * Read the configuration files from the specified path.
* @param path the path from which to read the files. * @param relPath the relative path from which to read the files (without trailing "/").
* @param extension the filename extension of the files to read. * @param extension the filename extension of the files to read.
* @param messages the @a MessageMap to load the messages into. * @param messages the @a MessageMap to load the messages into.
* @param recursive whether to load all files recursively. * @param recursive whether to load all files recursively.
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @param errorDescription a string in which to store the error description in case of error.
* @return the result code. * @return the result code.
*/ */
static result_t readConfigFiles(const string& path, const string& extension, const bool recursive, static result_t readConfigFiles(const string& relPath, const string& extension, const bool recursive,
const bool verbose, string* errorDescription, MessageMap* messages) { const bool verbose, string* errorDescription, MessageMap* messages) {
vector<string> files, dirs; vector<string> files, dirs;
bool hasTemplates = false; bool hasTemplates = false;
result_t result = collectConfigFiles(path, "", extension, &files, &dirs, &hasTemplates); result_t result = collectConfigFiles(relPath, "", extension, &files, false, "", &dirs, &hasTemplates);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
readTemplates(path, extension, hasTemplates, verbose); readTemplates(relPath, extension, hasTemplates, verbose);
for (const auto& name : files) { for (const auto& name : files) {
logInfo(lf_main, "reading file %s", name.c_str()); logInfo(lf_main, "reading file %s", name.c_str());
result = messages->readFromFile(name, verbose, NULL, errorDescription, NULL, NULL, NULL); result_t result = loadDefinitionsFromConfigPath(messages, name, verbose, NULL, errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -891,6 +926,28 @@ void executeInstructions(MessageMap* messages, bool verbose) {
messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive()); messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive());
} }
result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose,
map<string, string>* defaults, string* errorDescription) {
istream* stream = NULL;
time_t mtime;
if (s_configUriPrefix.empty()) {
stream = FileReader::openFile(s_configLocalPrefix + filename, errorDescription, &mtime);
} else {
string content;
if (s_configHttpClient.get(s_configUriPrefix + filename, "", content, &mtime)) {
stream = new istringstream(content);
}
}
result_t result;
if (stream) {
result = reader->readFromStream(stream, filename, mtime, verbose, defaults, errorDescription);
delete(stream);
} else {
result = RESULT_ERR_NOTFOUND;
}
return result;
}
result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) { result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) {
logInfo(lf_main, "loading configuration files from %s", opt.configPath); logInfo(lf_main, "loading configuration files from %s", opt.configPath);
messages->lock(); messages->lock();
@@ -905,7 +962,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
s_templatesByPath.clear(); s_templatesByPath.clear();
string errorDescription; string errorDescription;
result_t result = readConfigFiles(string(opt.configPath), ".csv", result_t result = readConfigFiles("", ".csv",
(!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages); (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages);
if (result == RESULT_OK) { if (result == RESULT_OK) {
logInfo(lf_main, "read config files"); logInfo(lf_main, "read config files");
@@ -928,22 +985,22 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
return RESULT_EMPTY; return RESULT_EMPTY;
} }
DataFieldSet* identFields = DataFieldSet::getIdentFields(); DataFieldSet* identFields = DataFieldSet::getIdentFields();
string path, prefix, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx string manufStr, addrStr, ident; // path: cfgpath/MANUFACTURER, prefix: ZZ., ident: C[C[C[C[C]]]], SW: xxxx, HW: xxxx
unsigned int sw = 0, hw = 0; unsigned int sw = 0, hw = 0;
ostringstream out; ostringstream out;
size_t offset = 0; size_t offset = 0;
size_t field = 0; size_t field = 0;
bool fromLocal = s_configUriPrefix.empty();
result_t result = (*identFields)[field]->read(data, offset, false, NULL, -1, 0, -1, &out); // manufacturer name result_t result = (*identFields)[field]->read(data, offset, false, NULL, -1, 0, -1, &out); // manufacturer name
if (result == RESULT_ERR_NOTFOUND) { if (result == RESULT_ERR_NOTFOUND && fromLocal) {
result = (*identFields)[field]->read(data, offset, false, NULL, -1, OF_NUMERIC, -1, &out); // manufacturer name result = (*identFields)[field]->read(data, offset, false, NULL, -1, OF_NUMERIC, -1, &out); // manufacturer name
} }
if (result == RESULT_OK) { if (result == RESULT_OK) {
path = out.str(); manufStr = out.str();
transform(path.begin(), path.end(), path.begin(), ::tolower); transform(manufStr.begin(), manufStr.end(), manufStr.begin(), ::tolower);
path = string(opt.configPath) + "/" + path;
out.str(""); out.str("");
out << setw(2) << hex << setfill('0') << nouppercase << static_cast<unsigned>(address) << "."; out << setw(2) << hex << setfill('0') << nouppercase << static_cast<unsigned>(address);
prefix = out.str(); addrStr = out.str();
out.str(""); out.str("");
out.clear(); out.clear();
offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN);
@@ -952,6 +1009,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
if (result == RESULT_OK) { if (result == RESULT_OK) {
ident = out.str(); ident = out.str();
out.str(""); out.str("");
out.clear();
offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN);
result = (*identFields)[field]->read(data, offset, NULL, -1, &sw); // software version number result = (*identFields)[field]->read(data, offset, NULL, -1, &sw); // software version number
if (result == RESULT_ERR_OUT_OF_RANGE) { if (result == RESULT_ERR_OUT_OF_RANGE) {
@@ -972,22 +1030,10 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
identFields->getName(field).c_str(), getResultCode(result)); identFields->getName(field).c_str(), getResultCode(result));
return result; return result;
} }
vector<string> files;
bool hasTemplates = false; bool hasTemplates = false;
// find files matching MANUFACTURER/ZZ.*csv in cfgpath string best;
result = collectConfigFiles(path, prefix, ".csv", &files, NULL, &hasTemplates); map<string, string> bestDefaults;
if (result != RESULT_OK) { vector<string> files;
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(),
getResultCode(result));
return result;
}
if (files.empty()) {
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, path.c_str(),
prefix.c_str());
return RESULT_ERR_NOTFOUND;
}
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), path.c_str(),
prefix.c_str(), getResultCode(result));
auto it = ident.begin(); auto it = ident.begin();
while (it != ident.end()) { while (it != ident.end()) {
if (*it != '_' && !::isalnum(*it)) { if (*it != '_' && !::isalnum(*it)) {
@@ -997,15 +1043,34 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
it++; it++;
} }
} }
// find files matching MANUFACTURER/ZZ.*csv in cfgpath
string query;
if (!fromLocal) {
out << "&a=" << addrStr << "&i=" << ident << "&h=" << dec << static_cast<unsigned>(hw) << "&s=" << dec << static_cast<unsigned>(sw);;
query = out.str();
out.str("");
out.clear();
}
result = collectConfigFiles(manufStr, addrStr + ".", ".csv", &files, false, query, NULL, &hasTemplates);
if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, manufStr.c_str(),
getResultCode(result));
return result;
}
if (files.empty()) {
logError(lf_main, "unable to load scan config %2.2x: no file from %s with prefix %s found", address, manufStr.c_str(),
addrStr.c_str());
return RESULT_ERR_NOTFOUND;
}
logDebug(lf_main, "found %d matching scan config files from %s with prefix %s: %s", files.size(), manufStr.c_str(),
addrStr.c_str(), getResultCode(result));
// complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.circuit][.suffix][.*][.SWxxxx][.HWxxxx][.*].csv // complete name: cfgpath/MANUFACTURER/ZZ[.C[C[C[C[C]]]]][.circuit][.suffix][.*][.SWxxxx][.HWxxxx][.*].csv
size_t bestMatch = 0; size_t bestMatch = 0;
string best;
map<string, string> bestDefaults;
for (const auto& name : files) { for (const auto& name : files) {
symbol_t checkDest; symbol_t checkDest;
unsigned int checkSw, checkHw; unsigned int checkSw, checkHw;
map<string, string> defaults; map<string, string> defaults;
const string filename = name.substr(path.length()+1); const string filename = name.substr(manufStr.length()+1);
if (!messages->extractDefaultsFromFilename(filename, &defaults, &checkDest, &checkSw, &checkHw)) { if (!messages->extractDefaultsFromFilename(filename, &defaults, &checkDest, &checkSw, &checkHw)) {
continue; continue;
} }
@@ -1042,23 +1107,23 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
if (best.empty()) { if (best.empty()) {
logError(lf_main, logError(lf_main,
"unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d", "unable to load scan config %2.2x: no file from %s with prefix %s matches ID \"%s\", SW%4.4d, HW%4.4d",
address, path.c_str(), prefix.c_str(), ident.c_str(), sw, hw); address, manufStr.c_str(), addrStr.c_str(), ident.c_str(), sw, hw);
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
// found the right file. load the templates if necessary, then load the file itself // found the right file. load the templates if necessary, then load the file itself
bool readCommon = readTemplates(path, ".csv", hasTemplates, opt.checkConfig); bool readCommon = readTemplates(manufStr, ".csv", hasTemplates, opt.checkConfig);
if (readCommon) { if (readCommon) {
result = collectConfigFiles(path, "", ".csv", &files); result = collectConfigFiles(manufStr, "", ".csv", &files, true, "&a=-");
if (result == RESULT_OK && !files.empty()) { if (result == RESULT_OK && !files.empty()) {
for (const auto& name : files) { for (const auto& name : files) {
string baseName = name.substr(path.length()+1, name.length()-path.length()-strlen(".csv")); // *. string baseName = name.substr(manufStr.length()+1, name.length()-manufStr.length()-strlen(".csv")); // *.
if (baseName == "_templates.") { // skip templates if (baseName == "_templates.") { // skip templates
continue; continue;
} }
if (baseName.length() < 3 || baseName.find_first_of('.') != 2) { // different from the scheme "ZZ." if (baseName.length() < 3 || baseName.find_first_of('.') != 2) { // different from the scheme "ZZ."
string errorDescription; string errorDescription;
result = messages->readFromFile(name, verbose, NULL, &errorDescription, NULL, NULL, NULL); result = loadDefinitionsFromConfigPath(messages, name, verbose, NULL, &errorDescription);
if (result == RESULT_OK) { if (result == RESULT_OK) {
logNotice(lf_main, "read common config file %s", name.c_str()); logNotice(lf_main, "read common config file %s", name.c_str());
} else { } else {
@@ -1069,16 +1134,16 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
} }
} }
} }
string errorDescription;
bestDefaults["name"] = ident; bestDefaults["name"] = ident;
result = messages->readFromFile(best, verbose, &bestDefaults, &errorDescription, NULL, NULL, NULL); string errorDescription;
result = loadDefinitionsFromConfigPath(messages, best, verbose, &bestDefaults, &errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s, %s", best.c_str(), logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s, %s", best.c_str(),
ident.c_str(), sw, hw, getResultCode(result), errorDescription.c_str()); ident.c_str(), sw, hw, getResultCode(result), errorDescription.c_str());
return result; return result;
} }
logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d", best.c_str(), ident.c_str(), sw, hw); logNotice(lf_main, "read scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d", best.c_str(), ident.c_str(), sw, hw);
*relativeFile = best.substr(strlen(opt.configPath)+1); *relativeFile = best;
return RESULT_OK; return RESULT_OK;
} }
@@ -1135,6 +1200,26 @@ int main(int argc, char* argv[]) {
return EINVAL; return EINVAL;
} }
string configPath = string(opt.configPath);
if (configPath.find("://") == string::npos) {
s_configLocalPrefix = configPath[configPath.length()-1] == '/' ? configPath : configPath + "/";
} else {
if (!opt.scanConfig) {
logError(lf_main, "invalid configpath without scanconfig");
return EINVAL;
}
uint16_t configPort = 80;
string proto, configHost;
if (!HttpClient::parseUrl(configPath, proto, configHost, configPort, s_configUriPrefix)) {
logError(lf_main, "invalid configPath URL");
return EINVAL;
}
if (!s_configHttpClient.connect(configHost, configPort, PACKAGE_NAME "/" PACKAGE_VERSION)) {
logError(lf_main, "invalid configPath URL");
return EINVAL;
}
s_configHttpClient.disconnect();
}
if (!opt.readOnly && opt.scanConfig && opt.initialScan == 0) { if (!opt.readOnly && opt.scanConfig && opt.initialScan == 0) {
opt.initialScan = BROADCAST; opt.initialScan = BROADCAST;
} }
@@ -1143,7 +1228,7 @@ int main(int argc, char* argv[]) {
setFacilitiesLogLevel(opt.logAreas, opt.logLevel); setFacilitiesLogLevel(opt.logAreas, opt.logLevel);
} }
s_messageMap = new MessageMap(string(opt.configPath)+"/", opt.checkConfig); s_messageMap = new MessageMap(opt.checkConfig);
if (opt.checkConfig) { if (opt.checkConfig) {
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check..."); logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
@@ -1178,7 +1263,6 @@ int main(int argc, char* argv[]) {
return 0; return 0;
} }
// open the device // open the device
Device *device = Device::create(opt.device, !opt.noDeviceCheck, opt.readOnly, opt.initialSend); Device *device = Device::create(opt.device, !opt.noDeviceCheck, opt.readOnly, opt.initialSend);
if (device == NULL) { if (device == NULL) {
+12
View File
@@ -120,6 +120,18 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose
*/ */
void executeInstructions(MessageMap* messages, bool verbose = false); void executeInstructions(MessageMap* messages, bool verbose = false);
/**
* Helper method for loading definitions from a relative file from the config path/URL.
* @param reader the @a FileReader instance to load with the definitions.
* @param filename the relative name of the file being read.
* @param verbose whether to verbosely log problems.
* @param defaults the default values by name (potentially overwritten by file name), or NULL to not use defaults.
* @param errorDescription a string in which to store the error description in case of error.
* @return @a RESULT_OK on success, or an error code.
*/
result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose,
map<string, string>* defaults, string* errorDescription);
} // namespace ebusd } // namespace ebusd
#endif // EBUSD_MAIN_H_ #endif // EBUSD_MAIN_H_
+8 -1
View File
@@ -128,7 +128,14 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag
m_logRawLastSymbol = SYN; m_logRawLastSymbol = SYN;
if (opt.aclFile[0]) { if (opt.aclFile[0]) {
string errorDescription; string errorDescription;
result = m_userList.readFromFile(opt.aclFile, false, NULL, &errorDescription, NULL, NULL, NULL); time_t mtime;
istream* stream = FileReader::openFile(opt.aclFile, &errorDescription, &mtime);
if (stream) {
result = m_userList.readFromStream(stream, opt.aclFile, mtime, false, NULL, &errorDescription);
delete(stream);
} else {
result = RESULT_ERR_NOTFOUND;
}
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error reading ACL file \"%s\": %s", opt.aclFile, getResultCode(result)); logError(lf_main, "error reading ACL file \"%s\": %s", opt.aclFile, getResultCode(result));
} }
+23 -19
View File
@@ -36,43 +36,47 @@ using std::setw;
using std::dec; using std::dec;
result_t FileReader::readFromFile(const string& filename, bool verbose, map<string, string>* defaults, istream* FileReader::openFile(const string& filename, string* errorDescription, time_t* time) {
string* errorDescription, size_t* hash, size_t* size, time_t* time) {
struct stat st; struct stat st;
if (stat(filename.c_str(), &st) != 0) { if (stat(filename.c_str(), &st) != 0) {
*errorDescription = filename; *errorDescription = filename;
return RESULT_ERR_NOTFOUND; return NULL;
} }
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
*errorDescription = filename+" is a directory"; *errorDescription = filename+" is a directory";
return RESULT_ERR_NOTFOUND; return NULL;
} }
ifstream stream; ifstream* stream = new ifstream();
stream.open(filename.c_str(), ifstream::in); stream->open(filename.c_str(), ifstream::in);
if (!stream.is_open()) { if (!stream->is_open()) {
*errorDescription = filename; *errorDescription = filename;
return RESULT_ERR_NOTFOUND; delete(stream);
return NULL;
} }
if (time) {
*time = st.st_mtime;
}
return stream;
}
result_t FileReader::readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
map<string, string>* defaults, string* errorDescription, size_t* hash, size_t* size) {
if (hash) { if (hash) {
*hash = 0; *hash = 0;
} }
if (size) { if (size) {
*size = 0; *size = 0;
} }
if (time) {
*time = st.st_mtime;
}
unsigned int lineNo = 0; unsigned int lineNo = 0;
vector<string> row; vector<string> row;
result_t result = RESULT_OK; result_t result = RESULT_OK;
while (stream.peek() != EOF && result == RESULT_OK) { while (stream->peek() != EOF && result == RESULT_OK) {
result = readLineFromStream(filename, verbose, &stream, &lineNo, &row, errorDescription, hash, size); result = readLineFromStream(stream, filename, verbose, &lineNo, &row, errorDescription, hash, size);
} }
stream.close();
return result; return result;
} }
result_t FileReader::readLineFromStream(const string& filename, bool verbose, istream* stream, result_t FileReader::readLineFromStream(istream* stream, const string& filename, bool verbose,
unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size) { unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size) {
result_t result; result_t result;
if (!splitFields(stream, row, lineNo, hash, size)) { if (!splitFields(stream, row, lineNo, hash, size)) {
@@ -237,8 +241,8 @@ const string MappedFileReader::normalizeLanguage(const string& lang) {
return normLang; return normLang;
} }
result_t MappedFileReader::readFromFile(const string& filename, bool verbose, map<string, string>* defaults, result_t MappedFileReader::readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
string* errorDescription, size_t* hash, size_t* size, time_t* time) { map<string, string>* defaults, string* errorDescription, size_t* hash, size_t* size) {
m_mutex.lock(); m_mutex.lock();
m_columnNames.clear(); m_columnNames.clear();
m_lastDefaults.clear(); m_lastDefaults.clear();
@@ -248,8 +252,8 @@ result_t MappedFileReader::readFromFile(const string& filename, bool verbose, ma
} }
size_t lastSep = filename.find_last_of('/'); size_t lastSep = filename.find_last_of('/');
string defaultsPart = lastSep == string::npos ? filename : filename.substr(lastSep+1); string defaultsPart = lastSep == string::npos ? filename : filename.substr(lastSep+1);
extractDefaultsFromFilename(defaultsPart, &m_lastDefaults[""], NULL, NULL, NULL); extractDefaultsFromFilename(defaultsPart, &m_lastDefaults[""]);
result_t result = FileReader::readFromFile(filename, verbose, defaults, errorDescription, hash, size, time); result_t result = FileReader::readFromStream(stream, filename, mtime, verbose, defaults, errorDescription, hash, size);
m_mutex.unlock(); m_mutex.unlock();
return result; return result;
} }
+22 -12
View File
@@ -76,24 +76,34 @@ class FileReader {
virtual ~FileReader() {} virtual ~FileReader() {}
/** /**
* Read the definitions from a file. * Open a file as stream for reading.
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param errorDescription a string in which to store the error description in case of error.
* @param time optional pointer to a @a time_t value for storing the modification time of the file, or NULL.
* @return the opened @a istream on success, or NULL on error.
*/
static istream* openFile(const string& filename, string* errorDescription, time_t* time = NULL);
/**
* Read the definitions from a stream.
* @param stream the @a istream to read from.
* @param filename the relative name of the file being read.
* @param mtime a @a time_t value with the modification time of the file.
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @param defaults the default values by name (potentially overwritten by file name), or NULL to not use defaults. * @param defaults the default values by name (potentially overwritten by file name), or NULL to not use defaults.
* @param errorDescription a string in which to store the error description in case of error. * @param errorDescription a string in which to store the error description in case of error.
* @param hash optional pointer to a @a size_t value for storing the hash of the file, or NULL. * @param hash optional pointer to a @a size_t value for storing the hash of the file, or NULL.
* @param size optional pointer to a @a size_t value for storing the normalized size of the file, or NULL. * @param size optional pointer to a @a size_t value for storing the normalized size of the file, or NULL.
* @param time optional pointer to a @a time_t value for storing the modification time of the file, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults, virtual result_t readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
string* errorDescription, size_t* hash, size_t* size, time_t* time); map<string, string>* defaults, string* errorDescription, size_t* hash = NULL, size_t* size = NULL);
/** /**
* Read a single line definition from the stream. * Read a single line definition from the stream.
* @param stream the @a istream to read from.
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @param stream the @a istream to read from.
* @param lineNo the last line number (incremented with each line read). * @param lineNo the last line number (incremented with each line read).
* @param row the definition row to clear and update with the read data (for performance reasons only). * @param row the definition row to clear and update with the read data (for performance reasons only).
* @param errorDescription a string in which to store the error description in case of error. * @param errorDescription a string in which to store the error description in case of error.
@@ -101,7 +111,7 @@ class FileReader {
* @param size optional pointer to a @a size_t value for updating with the normalized length of the line, or NULL. * @param size optional pointer to a @a size_t value for updating with the normalized length of the line, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readLineFromStream(const string& filename, bool verbose, istream* stream, virtual result_t readLineFromStream(istream* stream, const string& filename, bool verbose,
unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size); unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size);
/** /**
@@ -194,20 +204,20 @@ class MappedFileReader : public FileReader {
static const string normalizeLanguage(const string& lang); static const string normalizeLanguage(const string& lang);
// @copydoc // @copydoc
result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults, result_t readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
string* errorDescription, size_t* hash, size_t* size, time_t* time) override; map<string, string>* defaults, string* errorDescription, size_t* hash = NULL, size_t* size = NULL) override;
/** /**
* Extract default values from the file name. * Extract default values from the file name.
* @param filename the name of the file (without path) * @param filename the name of the file (without path)
* @param defaults the default values by name to add to. * @param defaults the default values by name to add to.
* @param destAddress a pointer to a variable in which to store the numeric destination address, or NULL. * @param destAddress optional pointer to a variable in which to store the numeric destination address, or NULL.
* @param software a pointer to a in which to store the numeric software version, or NULL. * @param software optional pointer to a in which to store the numeric software version, or NULL.
* @param hardware a pointer to a in which to store the numeric hardware version, or NULL. * @param hardware optional pointer to a in which to store the numeric hardware version, or NULL.
* @return true if the minimum parts were extracted, false otherwise. * @return true if the minimum parts were extracted, false otherwise.
*/ */
virtual bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults, virtual bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults,
symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const { symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const {
return false; return false;
} }
+12 -23
View File
@@ -81,6 +81,9 @@ static const char* defaultMessageFieldMap[] = { // access level not included in
extern DataFieldTemplates* getTemplates(const string& filename); extern DataFieldTemplates* getTemplates(const string& filename);
extern result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose,
map<string, string>* defaults, string* errorDescription);
Message::Message(const string& circuit, const string& level, const string& name, Message::Message(const string& circuit, const string& level, const string& name,
bool isWrite, bool isPassive, const map<string, string>& attributes, bool isWrite, bool isPassive, const map<string, string>& attributes,
@@ -1692,10 +1695,9 @@ void Instruction::getDestination(ostringstream* ostream) const {
} }
} }
result_t LoadInstruction::execute(MessageMap* messages, ostringstream* log) { result_t LoadInstruction::execute(MessageMap* messages, ostringstream* log) {
string errorDescription; string errorDescription;
result_t result = messages->readFromFile(m_filename, false, &m_defaults, &errorDescription, NULL, NULL, NULL); result_t result = loadDefinitionsFromConfigPath(messages, m_filename, false, &m_defaults, &errorDescription);
if (log->tellp() > 0) { if (log->tellp() > 0) {
*log << ", "; *log << ", ";
} }
@@ -1731,13 +1733,6 @@ result_t LoadInstruction::execute(MessageMap* messages, ostringstream* log) {
vector<string> MessageMap::s_noFiles; vector<string> MessageMap::s_noFiles;
const string MessageMap::getRelativePath(const string& filename) const {
if (filename.length() >= m_configPath.length() && filename.substr(0, m_configPath.length()) == m_configPath) {
return filename.substr(m_configPath.length());
}
return filename;
}
result_t MessageMap::add(bool storeByName, Message* message) { result_t MessageMap::add(bool storeByName, Message* message) {
uint64_t key = message->getKey(); uint64_t key = message->getKey();
bool conditional = message->isConditional(); bool conditional = message->isConditional();
@@ -2109,20 +2104,16 @@ bool MessageMap::extractDefaultsFromFilename(const string& filename, map<string,
return true; return true;
} }
result_t MessageMap::readFromFile(const string& filename, bool verbose, map<string, string>* defaults, result_t MessageMap::readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
string* errorDescription, size_t* hash, size_t* size, time_t* time) { map<string, string>* defaults, string* errorDescription, size_t* hash, size_t* size) {
size_t localHash, localSize; size_t localHash, localSize;
time_t localTime;
if (!hash) { if (!hash) {
hash = &localHash; hash = &localHash;
} }
if (!size) { if (!size) {
size = &localSize; size = &localSize;
} }
if (!time) { result_t result = MappedFileReader::readFromStream(stream, filename, mtime, verbose, defaults, errorDescription, hash, size);
time = &localTime;
}
result_t result = MappedFileReader::readFromFile(filename, verbose, defaults, errorDescription, hash, size, time);
if (defaults) { if (defaults) {
string circuit = AttributedItem::pluck("circuit", defaults); string circuit = AttributedItem::pluck("circuit", defaults);
if (!circuit.empty() && m_circuitData.find(circuit) == m_circuitData.end()) { if (!circuit.empty() && m_circuitData.find(circuit) == m_circuitData.end()) {
@@ -2134,10 +2125,9 @@ result_t MessageMap::readFromFile(const string& filename, bool verbose, map<stri
} }
} }
if (result == RESULT_OK) { if (result == RESULT_OK) {
const string file = getRelativePath(filename); m_loadedFileInfos[filename].m_hash = *hash;
m_loadedFileInfos[file].m_hash = *hash; m_loadedFileInfos[filename].m_size = *size;
m_loadedFileInfos[file].m_size = *size; m_loadedFileInfos[filename].m_time = mtime;
m_loadedFileInfos[file].m_time = *time;
} }
return result; return result;
} }
@@ -2332,10 +2322,9 @@ result_t MessageMap::executeInstructions(void (*readMessageFunc)(Message* messag
void MessageMap::addLoadedFile(symbol_t address, const string& filename, const string& comment) { void MessageMap::addLoadedFile(symbol_t address, const string& filename, const string& comment) {
if (!filename.empty()) { if (!filename.empty()) {
vector<string>& files = m_loadedFiles[address]; vector<string>& files = m_loadedFiles[address];
const string file = getRelativePath(filename); files.push_back(filename);
files.push_back(file);
if (!comment.empty()) { if (!comment.empty()) {
m_loadedFileInfos[file].m_comment = comment; m_loadedFileInfos[filename].m_comment = comment;
} }
} }
} }
+8 -19
View File
@@ -1091,7 +1091,7 @@ class Instruction {
/** /**
* Factory method for creating a new instance. * Factory method for creating a new instance.
* @param contextPath the path and/or filename context being loaded. * @param relPath the relative path and/or filename context being loaded.
* @param type the type of the instruction. * @param type the type of the instruction.
* @param condition the @a Condition for the instruction, or NULL. * @param condition the @a Condition for the instruction, or NULL.
* @param row the definition row by field name. * @param row the definition row by field name.
@@ -1099,7 +1099,7 @@ class Instruction {
* @param returnValue the variable in which to store the created instance. * @param returnValue the variable in which to store the created instance.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
static result_t create(const string& contextPath, const string& type, static result_t create(const string& relPath, const string& type,
Condition* condition, const map<string, string>& row, const map<string, string>& defaults, Condition* condition, const map<string, string>& row, const map<string, string>& defaults,
Instruction** returnValue); Instruction** returnValue);
@@ -1156,7 +1156,7 @@ class LoadInstruction : public Instruction {
* @param singleton whether this @a Instruction belongs to a set of instructions of which only the first one may be * @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. * executed for the same source file.
* @param defaults the mapped definition defaults. * @param defaults the mapped definition defaults.
* @param filename the name of the file to load. * @param filename the relative name of the file to load.
*/ */
LoadInstruction(bool singleton, const map<string, string>& defaults, const string& filename, LoadInstruction(bool singleton, const map<string, string>& defaults, const string& filename,
Condition* condition) Condition* condition)
@@ -1172,7 +1172,7 @@ class LoadInstruction : public Instruction {
private: private:
/** the name of the file to load. */ /** the relative name of the file to load. */
const string m_filename; const string m_filename;
}; };
@@ -1207,9 +1207,8 @@ class MessageMap : public MappedFileReader {
* @param addAll whether to add all messages, even if duplicate. * @param addAll whether to add all messages, even if duplicate.
* @param preferLanguage the preferred language to use, or empty. * @param preferLanguage the preferred language to use, or empty.
*/ */
explicit MessageMap(const string& configPath, bool addAll = false, const string& preferLanguage = "") explicit MessageMap(bool addAll = false, const string& preferLanguage = "")
: MappedFileReader::MappedFileReader(true), : MappedFileReader::MappedFileReader(true),
m_configPath(configPath),
m_addAll(addAll), m_additionalScanMessages(false), m_maxIdLength(0), m_maxBroadcastIdLength(0), m_addAll(addAll), m_additionalScanMessages(false), m_maxIdLength(0), m_maxBroadcastIdLength(0),
m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) { m_messageCount(0), m_conditionalMessageCount(0), m_passiveMessageCount(0) {
m_scanMessage = Message::createScanMessage(); m_scanMessage = Message::createScanMessage();
@@ -1231,13 +1230,6 @@ class MessageMap : public MappedFileReader {
} }
} }
/**
* Return the relative file name of the given filename.
* @param filename the name of the configuration file (including relative path).
* @return the relative file name.
*/
const string getRelativePath(const string& filename) const;
/** /**
* Add a @a Message instance to this set. * Add a @a Message instance to this set.
* @param message the @a Message instance to add. * @param message the @a Message instance to add.
@@ -1266,11 +1258,11 @@ class MessageMap : public MappedFileReader {
// @copydoc // @copydoc
bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults, bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults,
symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const override; symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const override;
// @copydoc // @copydoc
result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults, result_t readFromStream(istream* stream, const string& filename, time_t& mtime, bool verbose,
string* errorDescription, size_t* hash, size_t* size, time_t* time) override; map<string, string>* defaults, string* errorDescription, size_t* hash = NULL, size_t* size = NULL) override;
// @copydoc // @copydoc
result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
@@ -1502,9 +1494,6 @@ class MessageMap : public MappedFileReader {
/** empty vector for @a getLoadedFiles(). */ /** empty vector for @a getLoadedFiles(). */
static vector<string> s_noFiles; static vector<string> s_noFiles;
/** the path to the configuration files. */
const string m_configPath;
/** whether to add all messages, even if duplicate. */ /** whether to add all messages, even if duplicate. */
const bool m_addAll; const bool m_addAll;