added conditional messages to find command with "-a" option and include condition prefix for CSV format

also allow passing scan messages with --checkconfig and --scanconfig (without --inject)
be more verbose on errors in configuration files
improved code style
This commit is contained in:
john30
2017-05-01 15:31:09 +02:00
parent 3d4d876d5e
commit 7b11a540b6
32 changed files with 1946 additions and 1949 deletions
+145 -140
View File
@@ -65,16 +65,16 @@ const char* getStateCode(BusState state) {
result_t PollRequest::prepare(symbol_t ownMasterAddress) { result_t PollRequest::prepare(symbol_t ownMasterAddress) {
istringstream input; istringstream input;
result_t result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, SYN, m_index); result_t result = m_message->prepareMaster(m_index, ownMasterAddress, SYN, UI_FIELD_SEPARATOR, &input, &m_master);
if (result == RESULT_OK) { if (result == RESULT_OK) {
logInfo(lf_bus, "poll cmd: %s", m_master.getStr().c_str()); logInfo(lf_bus, "poll cmd: %s", m_master.getStr().c_str());
} }
return result; return result;
} }
bool PollRequest::notify(result_t result, SlaveSymbolString& slave) { bool PollRequest::notify(result_t result, const SlaveSymbolString& slave) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = m_message->storeLastData(slave, m_index); result = m_message->storeLastData(m_index, slave);
if (result >= RESULT_OK && m_index+1 < m_message->getCount()) { if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
m_index++; m_index++;
result = prepare(m_master[0]); result = prepare(m_master[0]);
@@ -85,7 +85,7 @@ bool PollRequest::notify(result_t result, SlaveSymbolString& slave) {
} }
ostringstream output; ostringstream output;
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = m_message->decodeLastData(output); // decode data result = m_message->decodeLastData(false, NULL, -1, 0, &output); // decode data
} }
if (result < RESULT_OK) { if (result < RESULT_OK) {
logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(), logError(lf_bus, "poll %s %s failed: %s", m_message->getCircuit().c_str(), m_message->getName().c_str(),
@@ -104,28 +104,28 @@ result_t ScanRequest::prepare(symbol_t ownMasterAddress) {
} }
symbol_t dstAddress = m_slaves.front(); symbol_t dstAddress = m_slaves.front();
istringstream input; istringstream input;
m_result = m_message->prepareMaster(ownMasterAddress, m_master, input, UI_FIELD_SEPARATOR, dstAddress, m_index); m_result = m_message->prepareMaster(m_index, ownMasterAddress, dstAddress, UI_FIELD_SEPARATOR, &input, &m_master);
if (m_result >= RESULT_OK) { if (m_result >= RESULT_OK) {
logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getStr().c_str()); logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getStr().c_str());
} }
return m_result; return m_result;
} }
bool ScanRequest::notify(result_t result, SlaveSymbolString& slave) { bool ScanRequest::notify(result_t result, const SlaveSymbolString& slave) {
symbol_t dstAddress = m_master[1]; symbol_t dstAddress = m_master[1];
if (result == RESULT_OK) { if (result == RESULT_OK) {
if (m_message == m_messageMap->getScanMessage()) { if (m_message == m_messageMap->getScanMessage()) {
Message* message = m_messageMap->getScanMessage(dstAddress); Message* message = m_messageMap->getScanMessage(dstAddress);
if (message != NULL) { if (message != NULL) {
m_message = message; m_message = message;
m_message->storeLastData(m_master, m_index); // expected to work since this is a clone m_message->storeLastData(m_index, m_master); // expected to work since this is a clone
} }
} else if (m_message->getDstAddress() == SYN) { } else if (m_message->getDstAddress() == SYN) {
m_message = m_message->derive(dstAddress, true); m_message = m_message->derive(dstAddress, true);
m_messageMap->add(m_message); m_messageMap->add(true, m_message);
m_message->storeLastData(m_master, m_index); // expected to work since this is a clone m_message->storeLastData(m_index, m_master); // expected to work since this is a clone
} }
result = m_message->storeLastData(slave, m_index); result = m_message->storeLastData(m_index, slave);
if (result >= RESULT_OK && m_index+1 < m_message->getCount()) { if (result >= RESULT_OK && m_index+1 < m_message->getCount()) {
m_index++; m_index++;
result = prepare(m_master[0]); result = prepare(m_master[0]);
@@ -135,7 +135,7 @@ bool ScanRequest::notify(result_t result, SlaveSymbolString& slave) {
} }
if (result == RESULT_OK) { if (result == RESULT_OK) {
ostringstream output; ostringstream output;
result = m_message->decodeLastData(output, 0, true); // decode data result = m_message->decodeLastData(true, NULL, -1, 0, &output); // decode data
string str = output.str(); string str = output.str();
m_busHandler->setScanResult(dstAddress, m_notifyIndex+m_index, str); m_busHandler->setScanResult(dstAddress, m_notifyIndex+m_index, str);
} }
@@ -186,66 +186,68 @@ bool ScanRequest::notify(result_t result, SlaveSymbolString& slave) {
} }
bool ActiveBusRequest::notify(result_t result, SlaveSymbolString& slave) { bool ActiveBusRequest::notify(result_t result, const SlaveSymbolString& slave) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
logDebug(lf_bus, "read res: %s", slave.getStr().c_str()); logDebug(lf_bus, "read res: %s", slave.getStr().c_str());
} }
m_result = result; m_result = result;
m_slave = slave; *m_slave = slave;
return false; return false;
} }
void GrabbedMessage::setLastData(MasterSymbolString& master, SlaveSymbolString& slave) {
void GrabbedMessage::setLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) {
m_lastMaster = master; m_lastMaster = master;
m_lastSlave = slave; m_lastSlave = slave;
m_count++; m_count++;
} }
/** /**
* Decode the input @a SymbolString with the specified @a DataType and length. * Decode the input @a SymbolString with the specified @a DataType and length.
* @param type the @a DataType. * @param type the @a DataType.
* @param input the @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param length the number of symbols to read. * @param length the number of symbols to read.
* @param offsets the last offset to the baseOffset to read. * @param offsets the last offset to the baseOffset to read.
* @param output the ostringstream to append the formatted value to.
* @param firstOnly whether to read only the first non-erroneous offset. * @param firstOnly whether to read only the first non-erroneous offset.
* @param output the ostringstream to append the formatted value to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
bool decodeType(const DataType* type, const SymbolString *input, size_t length, bool decodeType(const DataType* type, const SymbolString& input, size_t length,
size_t offsets, ostringstream& output, bool firstOnly = false) { size_t offsets, bool firstOnly, ostringstream* output) {
bool first = true; bool first = true;
string in = input->getStr(input->getDataOffset()); string in = input.getStr(input.getDataOffset());
for (size_t offset = 0; offset <= offsets; offset++) { for (size_t offset = 0; offset <= offsets; offset++) {
ostringstream out; ostringstream out;
result_t result = type->readSymbols(*input, offset, length, out, 0); result_t result = type->readSymbols(offset, length, input, 0, &out);
if (result != RESULT_OK) { if (result != RESULT_OK) {
continue; continue;
} }
if (type->isNumeric() && type->hasFlag(DAY)) { if (type->isNumeric() && type->hasFlag(DAY)) {
unsigned int value = 0; unsigned int value = 0;
if (type->readRawValue(*input, offset, length, value) == RESULT_OK) { if (type->readRawValue(offset, length, input, &value) == RESULT_OK) {
out.str(""); out.str("");
out << DataField::getDayName(reinterpret_cast<const NumberDataType*>(type)->getMinValue()+value); out << DataField::getDayName(reinterpret_cast<const NumberDataType*>(type)->getMinValue()+value);
} }
} }
if (first) { if (first) {
first = false; first = false;
output << endl << " "; *output << endl << " ";
ostringstream::pos_type cnt = output.tellp(); ostringstream::pos_type cnt = output->tellp();
type->dump(output, length, false); type->dump(length, false, output);
cnt = output.tellp() - cnt; cnt = output->tellp() - cnt;
while (cnt < 5) { while (cnt < 5) {
output << " "; *output << " ";
cnt += 1; cnt += 1;
} }
} else { } else {
output << ","; *output << ",";
} }
output << " " << in.substr(offset*2, length*2); *output << " " << in.substr(offset*2, length*2);
if (type->isNumeric()) { if (type->isNumeric()) {
output << "=" << out.str(); *output << "=" << out.str();
} else { } else {
output << "=\"" << out.str() << "\""; *output << "=\"" << out.str() << "\"";
} }
if (firstOnly) { if (firstOnly) {
return true; // only the first offset with maximum length when adjustable maximum size is at least 8 bytes return true; // only the first offset with maximum length when adjustable maximum size is at least 8 bytes
@@ -254,23 +256,22 @@ bool decodeType(const DataType* type, const SymbolString *input, size_t length,
return !first; return !first;
} }
bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output, bool GrabbedMessage::dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output) const {
const bool decode) const {
Message* message = messages->find(m_lastMaster); Message* message = messages->find(m_lastMaster);
if (unknown && message) { if (unknown && message) {
return false; return false;
} }
if (!first) { if (!first) {
output << endl; *output << endl;
} }
symbol_t dstAddress = m_lastMaster[1]; symbol_t dstAddress = m_lastMaster[1];
output << m_lastMaster.getStr(); *output << m_lastMaster.getStr();
if (dstAddress != BROADCAST && !isMaster(dstAddress)) { if (dstAddress != BROADCAST && !isMaster(dstAddress)) {
output << " / " << m_lastSlave.getStr(); *output << " / " << m_lastSlave.getStr();
} }
output << " = " << static_cast<unsigned>(m_count); *output << " = " << static_cast<unsigned>(m_count);
if (message) { if (message) {
output << ": " << message->getCircuit() << " " << message->getName(); *output << ": " << message->getCircuit() << " " << message->getName();
} }
if (decode) { if (decode) {
DataTypeList *types = DataTypeList::getInstance(); DataTypeList *types = DataTypeList::getInstance();
@@ -278,13 +279,7 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first,
return true; return true;
} }
bool master = isMaster(dstAddress) || dstAddress == BROADCAST || m_lastSlave.getDataSize() <= 0; bool master = isMaster(dstAddress) || dstAddress == BROADCAST || m_lastSlave.getDataSize() <= 0;
const SymbolString *input; size_t remain = master ? m_lastMaster.getDataSize() : m_lastSlave.getDataSize();
if (master) {
input = &m_lastMaster;
} else {
input = &m_lastSlave;
}
size_t remain = input->getDataSize();
if (remain == 0) { if (remain == 0) {
return true; return true;
} }
@@ -301,14 +296,22 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first,
if (baseType->isAdjustableLength()) { if (baseType->isAdjustableLength()) {
for (size_t length = maxLength; length >= 1; length--) { for (size_t length = maxLength; length >= 1; length--) {
const DataType* type = types->get(baseType->getId(), length); const DataType* type = types->get(baseType->getId(), length);
if (decodeType(type, input, length, remain-length, output, firstOnly)) { bool decoded;
if (firstOnly) { if (master) {
decoded = decodeType(type, m_lastMaster, length, remain-length, firstOnly, output);
} else {
decoded = decodeType(type, m_lastSlave, length, remain-length, firstOnly, output);
}
if (decoded && firstOnly) {
break; // only a single offset with maximum length when adjustable maximum size is at least 8 bytes break; // only a single offset with maximum length when adjustable maximum size is at least 8 bytes
} }
} }
}
} else if (maxLength > 0) { } else if (maxLength > 0) {
decodeType(baseType, input, maxLength, remain-maxLength, output); if (master) {
decodeType(baseType, m_lastMaster, maxLength, remain-maxLength, false, output);
} else {
decodeType(baseType, m_lastSlave, maxLength, remain-maxLength, false, output);
}
} }
} }
} }
@@ -322,9 +325,9 @@ void BusHandler::clear() {
m_scanResults.clear(); m_scanResults.clear();
} }
result_t BusHandler::sendAndWait(MasterSymbolString& master, SlaveSymbolString& slave) { result_t BusHandler::sendAndWait(const MasterSymbolString& master, SlaveSymbolString* slave) {
result_t result = RESULT_ERR_NO_SIGNAL; result_t result = RESULT_ERR_NO_SIGNAL;
slave.clear(); slave->clear();
ActiveBusRequest request(master, slave); ActiveBusRequest request(master, slave);
logInfo(lf_bus, "send message: %s", master.getStr().c_str()); logInfo(lf_bus, "send message: %s", master.getStr().c_str());
@@ -349,26 +352,26 @@ result_t BusHandler::sendAndWait(MasterSymbolString& master, SlaveSymbolString&
return result; return result;
} }
result_t BusHandler::readFromBus(Message* message, string inputStr, const symbol_t dstAddress, result_t BusHandler::readFromBus(Message* message, const string& inputStr, symbol_t dstAddress,
const symbol_t srcAddress) { symbol_t srcAddress) {
symbol_t masterAddress = srcAddress == SYN ? m_ownMasterAddress : srcAddress; symbol_t masterAddress = srcAddress == SYN ? m_ownMasterAddress : srcAddress;
result_t ret = RESULT_EMPTY; result_t ret = RESULT_EMPTY;
MasterSymbolString master; MasterSymbolString master;
SlaveSymbolString slave; SlaveSymbolString slave;
for (size_t index = 0; index < message->getCount(); index++) { for (size_t index = 0; index < message->getCount(); index++) {
istringstream input(inputStr); istringstream input(inputStr);
ret = message->prepareMaster(masterAddress, master, input, UI_FIELD_SEPARATOR, dstAddress, index); ret = message->prepareMaster(index, masterAddress, dstAddress, UI_FIELD_SEPARATOR, &input, &master);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
logError(lf_bus, "prepare message part %d: %s", index, getResultCode(ret)); logError(lf_bus, "prepare message part %d: %s", index, getResultCode(ret));
break; break;
} }
// send message // send message
ret = sendAndWait(master, slave); ret = sendAndWait(master, &slave);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
logError(lf_bus, "send message part %d: %s", index, getResultCode(ret)); logError(lf_bus, "send message part %d: %s", index, getResultCode(ret));
break; break;
} }
ret = message->storeLastData(slave, index); ret = message->storeLastData(index, slave);
if (ret < RESULT_OK) { if (ret < RESULT_OK) {
logError(lf_bus, "store message part %d: %s", index, getResultCode(ret)); logError(lf_bus, "store message part %d: %s", index, getResultCode(ret));
break; break;
@@ -569,14 +572,14 @@ result_t BusHandler::handleSymbol() {
// receive next symbol (optionally check reception of sent symbol) // receive next symbol (optionally check reception of sent symbol)
symbol_t recvSymbol; symbol_t recvSymbol;
result = m_device->recv(timeout+m_transferLatency, recvSymbol); result = m_device->recv(timeout+m_transferLatency, &recvSymbol);
if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0 if (!sending && result == RESULT_ERR_TIMEOUT && m_generateSynInterval > 0
&& timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) { && timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) {
// check if acting as AUTO-SYN generator is required // check if acting as AUTO-SYN generator is required
result = m_device->send(SYN); result = m_device->send(SYN);
if (result == RESULT_OK) { if (result == RESULT_OK) {
recvSymbol = ESC; recvSymbol = ESC;
result = m_device->recv(SEND_TIMEOUT, recvSymbol); result = m_device->recv(SEND_TIMEOUT, &recvSymbol);
if (result == RESULT_ERR_TIMEOUT) { if (result == RESULT_ERR_TIMEOUT) {
return setState(bs_noSignal, result); return setState(bs_noSignal, result);
} }
@@ -626,7 +629,7 @@ result_t BusHandler::handleSymbol() {
case bs_recvRes: case bs_recvRes:
case bs_sendCmd: case bs_sendCmd:
case bs_sendRes: case bs_sendRes:
SymbolString::updateCrc(m_crc, recvSymbol); SymbolString::updateCrc(recvSymbol, &m_crc);
break; break;
default: default:
break; break;
@@ -883,7 +886,7 @@ result_t BusHandler::handleSymbol() {
} }
// build response and store in m_response for sending back to requesting master // build response and store in m_response for sending back to requesting master
m_response.clear(); m_response.clear();
result = message->prepareSlave(input, m_response); result = message->prepareSlave(&input, &m_response);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return setState(bs_skip, result); return setState(bs_skip, result);
} }
@@ -1060,17 +1063,18 @@ void BusHandler::receiveCompleted() {
// e.g. 10fe07040a b5564149303001248901 // e.g. 10fe07040a b5564149303001248901
MasterSymbolString dummyMaster; MasterSymbolString dummyMaster;
istringstream input; istringstream input;
result_t result = message->prepareMaster(m_ownMasterAddress, dummyMaster, input); result_t result = message->prepareMaster(0, m_ownMasterAddress, SYN, UI_FIELD_SEPARATOR, &input,
&dummyMaster);
if (result == RESULT_OK) { if (result == RESULT_OK) {
SlaveSymbolString idData; SlaveSymbolString idData;
idData.push_back(10); idData.push_back(10);
for (size_t i = 0; i < 10; i++) { for (size_t i = 0; i < 10; i++) {
idData.push_back(m_command.dataAt(i)); idData.push_back(m_command.dataAt(i));
} }
result = message->storeLastData(idData, 0); result = message->storeLastData(0, idData);
if (result == RESULT_OK) { if (result == RESULT_OK) {
ostringstream output; ostringstream output;
result = message->decodeLastData(output, 0, true); result = message->decodeLastData(true, NULL, -1, 0, &output);
if (result == RESULT_OK) { if (result == RESULT_OK) {
string str = output.str(); string str = output.str();
setScanResult(slaveAddress, 0, str); setScanResult(slaveAddress, 0, str);
@@ -1108,7 +1112,7 @@ void BusHandler::receiveCompleted() {
result_t result = message->storeLastData(m_command, m_response); result_t result = message->storeLastData(m_command, m_response);
if (result == RESULT_OK) { if (result == RESULT_OK) {
ostringstream output; ostringstream output;
result = message->decodeLastData(output, 0, true); result = message->decodeLastData(true, NULL, -1, 0, &output);
if (result == RESULT_OK) { if (result == RESULT_OK) {
string str = output.str(); string str = output.str();
setScanResult(dstAddress, 0, str); setScanResult(dstAddress, 0, str);
@@ -1125,7 +1129,7 @@ void BusHandler::receiveCompleted() {
result_t result = message->storeLastData(m_command, m_response); result_t result = message->storeLastData(m_command, m_response);
ostringstream output; ostringstream output;
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = message->decodeLastData(output); result = message->decodeLastData(false, NULL, -1, 0, &output);
} }
if (result < RESULT_OK) { if (result < RESULT_OK) {
logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(), logError(lf_update, "unable to parse %s %s from %s / %s: %s", circuit.c_str(), name.c_str(),
@@ -1151,7 +1155,8 @@ void BusHandler::receiveCompleted() {
} }
} }
result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool& reload, ScanRequest*& request) { result_t BusHandler::prepareScan(symbol_t slave, bool full, const string& levels, bool* reload,
ScanRequest** request) {
Message* scanMessage = m_messages->getScanMessage(); Message* scanMessage = m_messages->getScanMessage();
if (scanMessage == NULL) { if (scanMessage == NULL) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
@@ -1173,14 +1178,14 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool&
deque<symbol_t> slaves; deque<symbol_t> slaves;
if (slave != SYN) { if (slave != SYN) {
slaves.push_back(slave); slaves.push_back(slave);
if (!reload) { if (!*reload) {
Message* message = m_messages->getScanMessage(slave); Message* message = m_messages->getScanMessage(slave);
if (message == NULL || message->getLastChangeTime() == 0) { if (message == NULL || message->getLastChangeTime() == 0) {
reload = true; *reload = true;
} }
} }
} else { } else {
reload = true; *reload = true;
for (slave = 1; slave != 0; slave++) { // 0 is known to be a master for (slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (!isValidAddress(slave, false) || isMaster(slave)) { if (!isValidAddress(slave, false) || isMaster(slave)) {
continue; continue;
@@ -1194,29 +1199,29 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool&
slaves.push_back(slave); slaves.push_back(slave);
} }
} }
if (reload) { if (*reload) {
messages.push_front(scanMessage); messages.push_front(scanMessage);
} }
if (messages.empty()) { if (messages.empty()) {
return RESULT_OK; return RESULT_OK;
} }
request = new ScanRequest(slave == SYN, m_messages, messages, slaves, this, reload ? 0 : 1); *request = new ScanRequest(slave == SYN, m_messages, messages, slaves, this, *reload ? 0 : 1);
result_t result = request->prepare(m_ownMasterAddress); result_t result = (*request)->prepare(m_ownMasterAddress);
if (result < RESULT_OK) { if (result < RESULT_OK) {
delete request; delete *request;
request = NULL; *request = NULL;
return result == RESULT_ERR_EOF ? RESULT_EMPTY : result; return result == RESULT_ERR_EOF ? RESULT_EMPTY : result;
} }
return RESULT_OK; return RESULT_OK;
} }
result_t BusHandler::startScan(bool full, string levels) { result_t BusHandler::startScan(bool full, const string& levels) {
if (m_runningScans > 0) { if (m_runningScans > 0) {
return RESULT_ERR_DUPLICATE; return RESULT_ERR_DUPLICATE;
} }
ScanRequest* request = NULL; ScanRequest* request = NULL;
bool reload = true; bool reload = true;
result_t result = prepareScan(SYN, full, levels, reload, request); result_t result = prepareScan(SYN, full, levels, &reload, &request);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -1229,7 +1234,7 @@ result_t BusHandler::startScan(bool full, string levels) {
return RESULT_OK; return RESULT_OK;
} }
void BusHandler::setScanResult(symbol_t dstAddress, size_t index, string str) { void BusHandler::setScanResult(symbol_t dstAddress, size_t index, const string& str) {
m_seenAddresses[dstAddress] |= SCAN_INIT; m_seenAddresses[dstAddress] |= SCAN_INIT;
if (str.length() > 0) { if (str.length() > 0) {
m_seenAddresses[dstAddress] |= SCAN_DONE; m_seenAddresses[dstAddress] |= SCAN_DONE;
@@ -1248,28 +1253,28 @@ void BusHandler::setScanFinished() {
} }
} }
bool BusHandler::formatScanResult(symbol_t slave, ostringstream& output, bool leadingNewline) { bool BusHandler::formatScanResult(symbol_t slave, bool leadingNewline, ostringstream* output) const {
const auto it = m_scanResults.find(slave); const auto it = m_scanResults.find(slave);
if (it == m_scanResults.end()) { if (it == m_scanResults.end()) {
return false; return false;
} }
if (leadingNewline) { if (leadingNewline) {
output << endl; *output << endl;
} }
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave); *output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave);
for (const auto result : it->second) { for (const auto result : it->second) {
output << result; *output << result;
} }
return true; return true;
} }
void BusHandler::formatScanResult(ostringstream& output) { void BusHandler::formatScanResult(ostringstream* output) const {
if (m_runningScans > 0) { if (m_runningScans > 0) {
output << m_runningScans << " scan(s) still running" << endl; *output << m_runningScans << " scan(s) still running" << endl;
} }
bool first = true; bool first = true;
for (symbol_t slave = 1; slave != 0; slave++) { // 0 is known to be a master for (symbol_t slave = 1; slave != 0; slave++) { // 0 is known to be a master
if (formatScanResult(slave, output, !first)) { if (formatScanResult(slave, !first, output)) {
first = false; first = false;
} }
} }
@@ -1282,55 +1287,55 @@ void BusHandler::formatScanResult(ostringstream& output) {
if (first) { if (first) {
first = false; first = false;
} else { } else {
output << endl; *output << endl;
} }
output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave); *output << hex << setw(2) << setfill('0') << static_cast<unsigned>(slave);
message->decodeLastData(output, 0, true); message->decodeLastData(true, NULL, -1, 0, output);
} }
} }
} }
} }
} }
void BusHandler::formatSeenInfo(ostringstream& output) { void BusHandler::formatSeenInfo(ostringstream* output) const {
symbol_t address = 0; symbol_t address = 0;
for (int index = 0; index < 256; index++, address++) { for (int index = 0; index < 256; index++, address++) {
bool ownAddress = !m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress); bool ownAddress = !m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress);
if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) { if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) {
continue; continue;
} }
output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address); *output << endl << "address " << setfill('0') << setw(2) << hex << static_cast<unsigned>(address);
symbol_t master; symbol_t master;
if (isMaster(address)) { if (isMaster(address)) {
output << ": master"; *output << ": master";
master = address; master = address;
} else { } else {
output << ": slave"; *output << ": slave";
master = getMasterAddress(address); master = getMasterAddress(address);
} }
if (master != SYN) { if (master != SYN) {
output << " #" << setw(0) << dec << static_cast<unsigned>(getMasterNumber(master)); *output << " #" << setw(0) << dec << static_cast<unsigned>(getMasterNumber(master));
} }
if (ownAddress) { if (ownAddress) {
output << ", ebusd"; *output << ", ebusd";
if (m_answer) { if (m_answer) {
output << " (answering)"; *output << " (answering)";
} }
if (m_addressConflict && (m_seenAddresses[address]&SEEN) != 0) { if (m_addressConflict && (m_seenAddresses[address]&SEEN) != 0) {
output << ", conflict"; *output << ", conflict";
} }
} }
if ((m_seenAddresses[address]&SCAN_DONE) != 0) { if ((m_seenAddresses[address]&SCAN_DONE) != 0) {
output << ", scanned"; *output << ", scanned";
Message* message = m_messages->getScanMessage(address); Message* message = m_messages->getScanMessage(address);
if (message != NULL && message->getLastUpdateTime() > 0) { if (message != NULL && message->getLastUpdateTime() > 0) {
// add detailed scan info: Manufacturer ID SW HW // add detailed scan info: Manufacturer ID SW HW
output << " \""; *output << " \"";
result_t result = message->decodeLastData(output, OF_NAMES); result_t result = message->decodeLastData(false, NULL, -1, OF_NAMES, output);
if (result != RESULT_OK) { if (result != RESULT_OK) {
output << "\" error: " << getResultCode(result); *output << "\" error: " << getResultCode(result);
} else { } else {
output << "\""; *output << "\"";
} }
} }
} }
@@ -1340,15 +1345,15 @@ void BusHandler::formatSeenInfo(ostringstream& output) {
for (const auto& loadedFile : loadedFiles) { for (const auto& loadedFile : loadedFiles) {
if (first) { if (first) {
first = false; first = false;
output << ", loaded \""; *output << ", loaded \"";
} else { } else {
output << ", \""; *output << ", \"";
} }
output << loadedFile << "\""; *output << loadedFile << "\"";
string comment; string comment;
if (m_messages->getLoadedFileInfo(loadedFile, comment)) { if (m_messages->getLoadedFileInfo(loadedFile, &comment)) {
if (!comment.empty()) { if (!comment.empty()) {
output << " (" << comment << ")"; *output << " (" << comment << ")";
} }
} }
} }
@@ -1356,15 +1361,15 @@ void BusHandler::formatSeenInfo(ostringstream& output) {
} }
} }
void BusHandler::formatUpdateInfo(ostringstream& output) { void BusHandler::formatUpdateInfo(ostringstream* output) const {
if (hasSignal()) { if (hasSignal()) {
output << ",\"s\":" << m_maxSymPerSec; *output << ",\"s\":" << m_maxSymPerSec;
} }
output << ",\"c\":" << m_masterCount; *output << ",\"c\":" << m_masterCount
output << ",\"m\":" << m_messages->size(); << ",\"m\":" << m_messages->size()
output << ",\"ro\":" << (m_device->isReadOnly() ? 1 : 0); << ",\"ro\":" << (m_device->isReadOnly() ? 1 : 0)
output << ",\"an\":" << (m_answer ? 1 : 0); << ",\"an\":" << (m_answer ? 1 : 0)
output << ",\"co\":" << (m_addressConflict ? 1 : 0); << ",\"co\":" << (m_addressConflict ? 1 : 0);
if (m_grabMessages) { if (m_grabMessages) {
size_t unknownCnt = 0; size_t unknownCnt = 0;
for (auto it : m_grabbedMessages) { for (auto it : m_grabbedMessages) {
@@ -1373,7 +1378,7 @@ void BusHandler::formatUpdateInfo(ostringstream& output) {
unknownCnt++; unknownCnt++;
} }
} }
output << ",\"gu\":" << unknownCnt; *output << ",\"gu\":" << unknownCnt;
} }
unsigned char address = 0; unsigned char address = 0;
for (int index = 0; index < 256; index++, address++) { for (int index = 0; index < 256; index++, address++) {
@@ -1381,68 +1386,68 @@ void BusHandler::formatUpdateInfo(ostringstream& output) {
if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) { if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) {
continue; continue;
} }
output << ",\"" << setfill('0') << setw(2) << hex << static_cast<unsigned>(address) << dec << setw(0); *output << ",\"" << setfill('0') << setw(2) << hex << static_cast<unsigned>(address) << dec << setw(0)
output << "\":{\"o\":" << (ownAddress ? 1 : 0); << "\":{\"o\":" << (ownAddress ? 1 : 0);
const auto it = m_scanResults.find(address); const auto it = m_scanResults.find(address);
if (it != m_scanResults.end()) { if (it != m_scanResults.end()) {
output << ",\"s\":\""; *output << ",\"s\":\"";
for (const auto result : it->second) { for (const auto result : it->second) {
output << result; *output << result;
} }
output << "\""; *output << "\"";
} }
if ((m_seenAddresses[address]&SCAN_DONE) != 0) { if ((m_seenAddresses[address]&SCAN_DONE) != 0) {
Message* message = m_messages->getScanMessage(address); Message* message = m_messages->getScanMessage(address);
if (message != NULL && message->getLastUpdateTime() > 0) { if (message != NULL && message->getLastUpdateTime() > 0) {
// add detailed scan info: Manufacturer ID SW HW // add detailed scan info: Manufacturer ID SW HW
message->decodeLastData(output, OF_NAMES|OF_NUMERIC|OF_JSON|OF_SHORT, true); message->decodeLastData(true, NULL, -1, OF_NAMES|OF_NUMERIC|OF_JSON|OF_SHORT, output);
} }
} }
const vector<string>& loadedFiles = m_messages->getLoadedFiles(address); const vector<string>& loadedFiles = m_messages->getLoadedFiles(address);
if (!loadedFiles.empty()) { if (!loadedFiles.empty()) {
output << ",\"f\":["; *output << ",\"f\":[";
bool first = true; bool first = true;
for (const auto loadedFile : loadedFiles) { for (const auto loadedFile : loadedFiles) {
if (first) { if (first) {
first = false; first = false;
} else { } else {
output << ","; *output << ",";
} }
output << "{\"f\":\"" << loadedFile << "\""; *output << "{\"f\":\"" << loadedFile << "\"";
string comment; string comment;
if (m_messages->getLoadedFileInfo(loadedFile, comment)) { if (m_messages->getLoadedFileInfo(loadedFile, &comment)) {
if (!comment.empty()) { if (!comment.empty()) {
output << ",\"c\":\"" << comment << "\""; *output << ",\"c\":\"" << comment << "\"";
} }
} }
output << "}"; *output << "}";
} }
output << "]"; *output << "]";
} }
output << "}"; *output << "}";
} }
vector<string> loadedFiles = m_messages->getLoadedFiles(); vector<string> loadedFiles = m_messages->getLoadedFiles();
if (!loadedFiles.empty()) { if (!loadedFiles.empty()) {
output << ",\"l\":{"; *output << ",\"l\":{";
bool first = true; bool first = true;
for (const auto& loadedFile : loadedFiles) { for (const auto& loadedFile : loadedFiles) {
if (first) { if (first) {
first = false; first = false;
} else { } else {
output << ","; *output << ",";
} }
output << "\"" << loadedFile << "\":{"; *output << "\"" << loadedFile << "\":{";
string comment; string comment;
size_t hash, size; size_t hash, size;
time_t time; time_t time;
if (m_messages->getLoadedFileInfo(loadedFile, comment, &hash, &size, &time)) { if (m_messages->getLoadedFileInfo(loadedFile, &comment, &hash, &size, &time)) {
output << "\"h\":\""; *output << "\"h\":\"";
MappedFileReader::formatHash(hash, output); MappedFileReader::formatHash(hash, output);
output << "\",\"s\":" << size << ",\"t\":" << time; *output << "\",\"s\":" << size << ",\"t\":" << time;
} }
output << "}"; *output << "}";
} }
output << "}"; *output << "}";
} }
} }
@@ -1452,7 +1457,7 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool
} }
ScanRequest* request = NULL; ScanRequest* request = NULL;
bool hasAdditionalScanMessages = m_messages->hasAdditionalScanMessages(); bool hasAdditionalScanMessages = m_messages->hasAdditionalScanMessages();
result_t result = prepareScan(dstAddress, false, "", reload, request); result_t result = prepareScan(dstAddress, false, "", &reload, &request);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -1473,7 +1478,7 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool
string file; string file;
bool timedOut = result == RESULT_ERR_TIMEOUT; bool timedOut = result == RESULT_ERR_TIMEOUT;
if (timedOut || result == RESULT_OK) { if (timedOut || result == RESULT_OK) {
result = loadScanConfigFile(m_messages, dstAddress, file); // try to load even if one message timed out result = loadScanConfigFile(m_messages, dstAddress, false, &file); // try to load even if one message timed out
if (timedOut && result == RESULT_EMPTY) { if (timedOut && result == RESULT_EMPTY) {
result = RESULT_ERR_TIMEOUT; // back to previous result result = RESULT_ERR_TIMEOUT; // back to previous result
} }
@@ -1503,20 +1508,20 @@ bool BusHandler::enableGrab(bool enable) {
return true; return true;
} }
void BusHandler::formatGrabResult(const bool unknown, ostringstream& output, const bool decode) { void BusHandler::formatGrabResult(bool unknown, bool decode, ostringstream* output) const {
if (!m_grabMessages) { if (!m_grabMessages) {
output << "grab disabled"; *output << "grab disabled";
} else { } else {
bool first = true; bool first = true;
for (const auto& it : m_grabbedMessages) { for (const auto& it : m_grabbedMessages) {
if (it.second.dump(unknown, m_messages, first, output, decode)) { if (it.second.dump(unknown, m_messages, first, decode, output)) {
first = false; first = false;
} }
} }
} }
} }
symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) { symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) const {
if (lastAddress == SYN) { if (lastAddress == SYN) {
return SYN; return SYN;
} }
@@ -1538,7 +1543,7 @@ symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) {
return SYN; return SYN;
} }
void BusHandler::setScanConfigLoaded(symbol_t address, string file) { void BusHandler::setScanConfigLoaded(symbol_t address, const string& file) {
m_seenAddresses[address] |= LOAD_INIT; m_seenAddresses[address] |= LOAD_INIT;
if (!file.empty()) { if (!file.empty()) {
m_seenAddresses[address] |= LOAD_DONE; m_seenAddresses[address] |= LOAD_DONE;
+37 -38
View File
@@ -109,7 +109,7 @@ class BusRequest {
* @param master the master data @a MasterSymbolString to send. * @param master the master data @a MasterSymbolString to send.
* @param deleteOnFinish whether to automatically delete this @a BusRequest when finished. * @param deleteOnFinish whether to automatically delete this @a BusRequest when finished.
*/ */
BusRequest(MasterSymbolString& master, const bool deleteOnFinish) BusRequest(const MasterSymbolString& master, bool deleteOnFinish)
: m_master(master), m_busLostRetries(0), : m_master(master), m_busLostRetries(0),
m_deleteOnFinish(deleteOnFinish) {} m_deleteOnFinish(deleteOnFinish) {}
@@ -124,12 +124,12 @@ class BusRequest {
* @param slave the @a SlaveSymbolString received. * @param slave the @a SlaveSymbolString received.
* @return true if the request needs to be restarted. * @return true if the request needs to be restarted.
*/ */
virtual bool notify(result_t result, SlaveSymbolString& slave) = 0; virtual bool notify(result_t result, const SlaveSymbolString& slave) = 0;
protected: protected:
/** the master data @a MasterSymbolString to send. */ /** the master data @a MasterSymbolString to send. */
MasterSymbolString& m_master; const MasterSymbolString& m_master;
/** the number of times a send is repeated due to lost arbitration. */ /** the number of times a send is repeated due to lost arbitration. */
unsigned int m_busLostRetries; unsigned int m_busLostRetries;
@@ -166,7 +166,7 @@ class PollRequest : public BusRequest {
result_t prepare(symbol_t masterAddress); result_t prepare(symbol_t masterAddress);
// @copydoc // @copydoc
bool notify(result_t result, SlaveSymbolString& slave) override; bool notify(result_t result, const SlaveSymbolString& slave) override;
private: private:
@@ -197,8 +197,8 @@ class ScanRequest : public BusRequest {
* @param busHandler the @a BusHandler instance to notify of final scan result. * @param busHandler the @a BusHandler instance to notify of final scan result.
* @param notifyIndex the offset to the index for notifying the scan result. * @param notifyIndex the offset to the index for notifying the scan result.
*/ */
ScanRequest(bool deleteOnFinish, MessageMap* messageMap, deque<Message*> messages, deque<symbol_t> slaves, ScanRequest(bool deleteOnFinish, MessageMap* messageMap, const deque<Message*>& messages,
BusHandler* busHandler, size_t notifyIndex = 0) const deque<symbol_t>& slaves, BusHandler* busHandler, size_t notifyIndex = 0)
: BusRequest(m_master, deleteOnFinish), m_messageMap(messageMap), m_index(0), m_allMessages(messages), : BusRequest(m_master, deleteOnFinish), m_messageMap(messageMap), m_index(0), m_allMessages(messages),
m_messages(messages), m_slaves(slaves), m_busHandler(busHandler), m_notifyIndex(notifyIndex), m_messages(messages), m_slaves(slaves), m_busHandler(busHandler), m_notifyIndex(notifyIndex),
m_result(RESULT_ERR_NO_SIGNAL) { m_result(RESULT_ERR_NO_SIGNAL) {
@@ -219,7 +219,7 @@ class ScanRequest : public BusRequest {
result_t prepare(symbol_t masterAddress); result_t prepare(symbol_t masterAddress);
// @copydoc // @copydoc
bool notify(result_t result, SlaveSymbolString& slave) override; bool notify(result_t result, const SlaveSymbolString& slave) override;
private: private:
@@ -267,7 +267,7 @@ class ActiveBusRequest : public BusRequest {
* @param master the master data @a MasterSymbolString to send. * @param master the master data @a MasterSymbolString to send.
* @param slave reference to @a SlaveSymbolString for filling in the received slave data. * @param slave reference to @a SlaveSymbolString for filling in the received slave data.
*/ */
ActiveBusRequest(MasterSymbolString& master, SlaveSymbolString& slave) ActiveBusRequest(const MasterSymbolString& master, SlaveSymbolString* slave)
: BusRequest(master, false), m_result(RESULT_ERR_NO_SIGNAL), m_slave(slave) {} : BusRequest(master, false), m_result(RESULT_ERR_NO_SIGNAL), m_slave(slave) {}
/** /**
@@ -276,7 +276,7 @@ class ActiveBusRequest : public BusRequest {
virtual ~ActiveBusRequest() {} virtual ~ActiveBusRequest() {}
// @copydoc // @copydoc
bool notify(result_t result, SlaveSymbolString& slave) override; bool notify(result_t result, const SlaveSymbolString& slave) override;
private: private:
@@ -284,7 +284,7 @@ class ActiveBusRequest : public BusRequest {
result_t m_result; result_t m_result;
/** reference to @a SlaveSymbolString for filling in the received slave data. */ /** reference to @a SlaveSymbolString for filling in the received slave data. */
SlaveSymbolString& m_slave; SlaveSymbolString* m_slave;
}; };
@@ -312,7 +312,7 @@ class GrabbedMessage {
* @param master the last @a MasterSymbolString. * @param master the last @a MasterSymbolString.
* @param slave the last @a SymbolString. * @param slave the last @a SymbolString.
*/ */
void setLastData(MasterSymbolString& master, SlaveSymbolString& slave); void setLastData(const MasterSymbolString& master, const SlaveSymbolString& slave);
/** /**
* Get the last @a MasterSymbolString. * Get the last @a MasterSymbolString.
@@ -325,12 +325,11 @@ class GrabbedMessage {
* @param unknown whether to dump only if this message is unknown. * @param unknown whether to dump only if this message is unknown.
* @param messages the @a MessageMap instance for resolving known @a Message instances. * @param messages the @a MessageMap instance for resolving known @a Message instances.
* @param first whether this is the first message to be added to the output. * @param first whether this is the first message to be added to the output.
* @param output the @a ostringstream to format the messages to.
* @param decode whether to add decoding hints. * @param decode whether to add decoding hints.
* @param output the @a ostringstream to format the messages to.
* @return whether the message was added to the output. * @return whether the message was added to the output.
*/ */
bool dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output, bool dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output) const;
const bool decode = false) const;
private: private:
@@ -366,11 +365,11 @@ class BusHandler : public WaitThread {
* @param pollInterval the interval in seconds in which poll messages are cycled, or 0 if disabled. * @param pollInterval the interval in seconds in which poll messages are cycled, or 0 if disabled.
*/ */
BusHandler(Device* device, MessageMap* messages, BusHandler(Device* device, MessageMap* messages,
const symbol_t ownAddress, const bool answer, symbol_t ownAddress, bool answer,
const unsigned int busLostRetries, const unsigned int failedSendRetries, unsigned int busLostRetries, unsigned int failedSendRetries,
const unsigned int transferLatency, const unsigned int busAcquireTimeout, const unsigned int slaveRecvTimeout, unsigned int transferLatency, unsigned int busAcquireTimeout, unsigned int slaveRecvTimeout,
const unsigned int lockCount, const bool generateSyn, unsigned int lockCount, bool generateSyn,
const unsigned int pollInterval) unsigned int pollInterval)
: WaitThread(), m_device(device), m_reconnect(false), m_messages(messages), : WaitThread(), m_device(device), m_reconnect(false), m_messages(messages),
m_ownMasterAddress(ownAddress), m_ownSlaveAddress(getSlaveAddress(ownAddress)), m_ownMasterAddress(ownAddress), m_ownSlaveAddress(getSlaveAddress(ownAddress)),
m_answer(answer), m_addressConflict(false), m_answer(answer), m_addressConflict(false),
@@ -418,7 +417,7 @@ class BusHandler : public WaitThread {
* @param master the @a MasterSymbolString with the master data. * @param master the @a MasterSymbolString with the master data.
* @param slave the @a SlaveSymbolString with the slave data. * @param slave the @a SlaveSymbolString with the slave data.
*/ */
void injectMessage(MasterSymbolString& master, SlaveSymbolString& slave) { void injectMessage(const MasterSymbolString& master, const SlaveSymbolString& slave) {
m_command = master; m_command = master;
m_response = slave; m_response = slave;
m_addressConflict = true; // avoid conflict messages m_addressConflict = true; // avoid conflict messages
@@ -432,7 +431,7 @@ class BusHandler : public WaitThread {
* @param slave the @a SlaveSymbolString that will be filled with retrieved slave data. * @param slave the @a SlaveSymbolString that will be filled with retrieved slave data.
* @return the result code. * @return the result code.
*/ */
result_t sendAndWait(MasterSymbolString& master, SlaveSymbolString& slave); result_t sendAndWait(const MasterSymbolString& master, SlaveSymbolString* slave);
/** /**
* Prepare the master part for the @a Message, send it to the bus and wait for the answer. * Prepare the master part for the @a Message, send it to the bus and wait for the answer.
@@ -442,8 +441,8 @@ class BusHandler : public WaitThread {
* @param srcAddress the source address to set, or @a SYN for the own master address. * @param srcAddress the source address to set, or @a SYN for the own master address.
* @return the result code. * @return the result code.
*/ */
result_t readFromBus(Message* message, string inputStr, const symbol_t dstAddress = SYN, result_t readFromBus(Message* message, const string& inputStr, symbol_t dstAddress = SYN,
const symbol_t srcAddress = SYN); symbol_t srcAddress = SYN);
/** /**
* Main thread entry. * Main thread entry.
@@ -456,7 +455,7 @@ class BusHandler : public WaitThread {
* @param levels the current user's access levels. * @param levels the current user's access levels.
* @return the result code. * @return the result code.
*/ */
result_t startScan(bool full, string levels); result_t startScan(bool full, const string& levels);
/** /**
* Set the scan result @a string for a scanned slave address. * Set the scan result @a string for a scanned slave address.
@@ -464,7 +463,7 @@ class BusHandler : public WaitThread {
* @param index the index of the result to set (starting with 0 for the ident message). * @param index the index of the result to set (starting with 0 for the ident message).
* @param str the scan result @a string to set, or empty if not a single part of the scan was successful. * @param str the scan result @a string to set, or empty if not a single part of the scan was successful.
*/ */
void setScanResult(symbol_t dstAddress, size_t index, string str); void setScanResult(symbol_t dstAddress, size_t index, const string& str);
/** /**
* Called from @a ScanRequest upon completion. * Called from @a ScanRequest upon completion.
@@ -478,25 +477,25 @@ class BusHandler : public WaitThread {
* @param output the @a ostringstream to format the scan result to. * @param output the @a ostringstream to format the scan result to.
* @return true when a scan result was formatted, false otherwise. * @return true when a scan result was formatted, false otherwise.
*/ */
bool formatScanResult(symbol_t slave, ostringstream& output, bool leadingNewline); bool formatScanResult(symbol_t slave, bool leadingNewline, ostringstream* output) const;
/** /**
* Format the scan result to the @a ostringstream. * Format the scan result to the @a ostringstream.
* @param output the @a ostringstream to format the scan result to. * @param output the @a ostringstream to format the scan result to.
*/ */
void formatScanResult(ostringstream& output); void formatScanResult(ostringstream* output) const;
/** /**
* Format information about seen participants to the @a ostringstream. * Format information about seen participants to the @a ostringstream.
* @param output the @a ostringstream to append the info to. * @param output the @a ostringstream to append the info to.
*/ */
void formatSeenInfo(ostringstream& output); void formatSeenInfo(ostringstream* output) const;
/** /**
* Format information for running the update check to the @a ostringstream. * Format information for running the update check to the @a ostringstream.
* @param output the @a ostringstream to append the info to. * @param output the @a ostringstream to append the info to.
*/ */
void formatUpdateInfo(ostringstream& output); void formatUpdateInfo(ostringstream* output) const;
/** /**
* Send a scan message on the bus and wait for the answer. * Send a scan message on the bus and wait for the answer.
@@ -517,16 +516,16 @@ class BusHandler : public WaitThread {
/** /**
* Format the grabbed messages to the @a ostringstream. * Format the grabbed messages to the @a ostringstream.
* @param unknown whether to dump only unknown messages. * @param unknown whether to dump only unknown messages.
* @param output the @a ostringstream to format the messages to.
* @param decode whether to add decoding hints. * @param decode whether to add decoding hints.
* @param output the @a ostringstream to format the messages to.
*/ */
void formatGrabResult(const bool unknown, ostringstream& output, const bool decode = false); void formatGrabResult(bool unknown, bool decode, ostringstream* output) const;
/** /**
* Return true when a signal on the bus is available. * Return true when a signal on the bus is available.
* @return true when a signal on the bus is available. * @return true when a signal on the bus is available.
*/ */
bool hasSignal() { return m_state != bs_noSignal; } bool hasSignal() const { return m_state != bs_noSignal; }
/** /**
* Reconnect the device. * Reconnect the device.
@@ -537,33 +536,33 @@ class BusHandler : public WaitThread {
* Return the current symbol rate. * Return the current symbol rate.
* @return the number of received symbols in the last second. * @return the number of received symbols in the last second.
*/ */
unsigned int getSymbolRate() { return m_symPerSec; } unsigned int getSymbolRate() const { return m_symPerSec; }
/** /**
* Return the maximum seen symbol rate. * Return the maximum seen symbol rate.
* @return the maximum number of received symbols per second ever seen. * @return the maximum number of received symbols per second ever seen.
*/ */
unsigned int getMaxSymbolRate() { return m_maxSymPerSec; } unsigned int getMaxSymbolRate() const { return m_maxSymPerSec; }
/** /**
* Return the number of masters already seen. * Return the number of masters already seen.
* @return the number of masters already seen (including ebusd itself). * @return the number of masters already seen (including ebusd itself).
*/ */
unsigned int getMasterCount() { return m_masterCount; } unsigned int getMasterCount() const { return m_masterCount; }
/** /**
* Get the next slave address that still needs to be scanned or loaded. * Get the next slave address that still needs to be scanned or loaded.
* @param lastAddress the last returned slave address, or 0 for returning the first one. * @param lastAddress the last returned slave address, or 0 for returning the first one.
* @return the next slave address that still needs to be scanned or loaded, or @a SYN. * @return the next slave address that still needs to be scanned or loaded, or @a SYN.
*/ */
symbol_t getNextScanAddress(symbol_t lastAddress); symbol_t getNextScanAddress(symbol_t lastAddress) const;
/** /**
* Set the state of the participant to configuration @a LOADED. * Set the state of the participant to configuration @a LOADED.
* @param address the slave address. * @param address the slave address.
* @param file the file from which the configuration was loaded, or empty if loading was not possible. * @param file the file from which the configuration was loaded, or empty if loading was not possible.
*/ */
void setScanConfigLoaded(symbol_t address, string file); void setScanConfigLoaded(symbol_t address, const string& file);
private: private:
@@ -603,7 +602,7 @@ class BusHandler : public WaitThread {
* @param request the created @a ScanRequest (may be NULL with positive result if scan is not needed). * @param request the created @a ScanRequest (may be NULL with positive result if scan is not needed).
* @return the result code. * @return the result code.
*/ */
result_t prepareScan(symbol_t slave, bool full, string levels, bool& reload, ScanRequest*& request); result_t prepareScan(symbol_t slave, bool full, const string& levels, bool* reload, ScanRequest** request);
/** the @a Device instance for accessing the bus. */ /** the @a Device instance for accessing the bus. */
Device* m_device; Device* m_device;
+2 -2
View File
@@ -51,12 +51,12 @@ const struct argp_child* datahandler_getargs() {
} }
bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
list<DataHandler*>& handlers) { list<DataHandler*>* handlers) {
bool success = true; bool success = true;
#ifdef HAVE_MQTT #ifdef HAVE_MQTT
DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages); DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages);
if (handler) { if (handler) {
handlers.push_back(handler); handlers->push_back(handler);
} else { } else {
success = false; success = false;
} }
+6 -6
View File
@@ -55,7 +55,7 @@ const struct argp_child* datahandler_getargs();
* @return true if registration was successful. * @return true if registration was successful.
*/ */
bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages,
list<DataHandler*>& handlers); list<DataHandler*>* handlers);
/** /**
@@ -73,7 +73,7 @@ class UserInfo {
* @param user the user name. * @param user the user name.
* @return whether the user exists. * @return whether the user exists.
*/ */
virtual bool hasUser(const string user) const = 0; // abstract virtual bool hasUser(const string& user) const = 0; // abstract
/** /**
* Check whether the secret string matches the one of the specified user. * Check whether the secret string matches the one of the specified user.
@@ -81,14 +81,14 @@ class UserInfo {
* @param secret the secret to check. * @param secret the secret to check.
* @return whether the secret string is valid. * @return whether the secret string is valid.
*/ */
virtual bool checkSecret(const string user, const string secret) const = 0; // abstract virtual bool checkSecret(const string& user, const string& secret) const = 0; // abstract
/** /**
* Get the access levels associated with the specified user. * Get the access levels associated with the specified user.
* @param user the user name, or empty for default levels. * @param user the user name, or empty for default levels.
* @return the access levels separated by semicolon. * @return the access levels separated by semicolon.
*/ */
virtual string getLevels(const string user) const = 0; // abstract virtual string getLevels(const string& user) const = 0; // abstract
}; };
@@ -136,7 +136,7 @@ class DataSink : virtual public DataHandler {
* @param userInfo the @a UserInfo instance. * @param userInfo the @a UserInfo instance.
* @param user the user name for determining the allowed access levels (fall back to default levels). * @param user the user name for determining the allowed access levels (fall back to default levels).
*/ */
DataSink(UserInfo* userInfo, string user) { DataSink(const UserInfo* userInfo, const string& user) {
m_levels = userInfo->getLevels(userInfo->hasUser(user) ? user : ""); m_levels = userInfo->getLevels(userInfo->hasUser(user) ? user : "");
} }
@@ -158,7 +158,7 @@ class DataSink : virtual public DataHandler {
* Notify the sink of the latest update check result. * Notify the sink of the latest update check result.
* @param checkResult a string describing available updates, or empty if no update is available. * @param checkResult a string describing available updates, or empty if no update is available.
*/ */
virtual void notifyUpdateCheckResult(string checkResult) {} virtual void notifyUpdateCheckResult(const string& checkResult) {}
protected: protected:
/** the allowed access levels. */ /** the allowed access levels. */
+70 -58
View File
@@ -178,9 +178,8 @@ static const struct argp_option argpoptions[] = {
{"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 }, {"configpath", 'c', "PATH", 0, "Read CSV config files from PATH [" CONFIG_PATH "]", 0 },
{"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR=" {"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR="
"\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, " "\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, "
"default is broadcast ident message). If combined with --checkconfig and --inject, you can add scan message " "default is broadcast ident message). If combined with --checkconfig, you can add scan message data as "
"data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", "arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 },
0 },
{"configlang", O_CFGLNG, "LANG", 0, {"configlang", O_CFGLNG, "LANG", 0,
"Prefer LANG in multilingual configuration files [system default language]", 0 }, "Prefer LANG in multilingual configuration files [system default language]", 0 },
{"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 }, {"checkconfig", O_CHKCFG, NULL, 0, "Check CSV config files, then stop", 0 },
@@ -280,7 +279,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->initialSend = true; opt->initialSend = true;
break; break;
case O_DEVLAT: // --latency=10000 case O_DEVLAT: // --latency=10000
opt->latency = parseInt(arg, 10, 0, 200000, result); opt->latency = parseInt(arg, 10, 0, 200000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid latency"); argp_error(state, "invalid latency");
return EINVAL; return EINVAL;
@@ -307,7 +306,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
} else if (strcmp("full", arg) == 0) { } else if (strcmp("full", arg) == 0) {
opt->initialScan = SYN; opt->initialScan = SYN;
} else { } else {
opt->initialScan = (symbol_t)parseInt(arg, 16, 0x00, 0xff, result); opt->initialScan = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result);
if (!isValidAddress(opt->initialScan)) { if (!isValidAddress(opt->initialScan)) {
argp_error(state, "invalid initial scan address"); argp_error(state, "invalid initial scan address");
return EINVAL; return EINVAL;
@@ -333,7 +332,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->dumpConfig = true; opt->dumpConfig = true;
break; break;
case O_POLINT: // --pollinterval=5 case O_POLINT: // --pollinterval=5
opt->pollInterval = parseInt(arg, 10, 0, 3600, result); opt->pollInterval = parseInt(arg, 10, 0, 3600, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid pollinterval"); argp_error(state, "invalid pollinterval");
return EINVAL; return EINVAL;
@@ -349,7 +348,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
// eBUS options: // eBUS options:
case 'a': // --address=31 case 'a': // --address=31
opt->address = (symbol_t)parseInt(arg, 16, 0, 0xff, result); opt->address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result);
if (result != RESULT_OK || !isMaster(opt->address)) { if (result != RESULT_OK || !isMaster(opt->address)) {
argp_error(state, "invalid address"); argp_error(state, "invalid address");
return EINVAL; return EINVAL;
@@ -363,35 +362,35 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->answer = true; opt->answer = true;
break; break;
case O_ACQTIM: // --acquiretimeout=9400 case O_ACQTIM: // --acquiretimeout=9400
opt->acquireTimeout = parseInt(arg, 10, 1000, 100000, result); opt->acquireTimeout = parseInt(arg, 10, 1000, 100000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid acquiretimeout"); argp_error(state, "invalid acquiretimeout");
return EINVAL; return EINVAL;
} }
break; break;
case O_ACQRET: // --acquireretries=3 case O_ACQRET: // --acquireretries=3
opt->acquireRetries = parseInt(arg, 10, 0, 10, result); opt->acquireRetries = parseInt(arg, 10, 0, 10, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid acquireretries"); argp_error(state, "invalid acquireretries");
return EINVAL; return EINVAL;
} }
break; break;
case O_SNDRET: // --sendretries=2 case O_SNDRET: // --sendretries=2
opt->sendRetries = parseInt(arg, 10, 0, 10, result); opt->sendRetries = parseInt(arg, 10, 0, 10, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid sendretries"); argp_error(state, "invalid sendretries");
return EINVAL; return EINVAL;
} }
break; break;
case O_RCVTIM: // --receivetimeout=25000 case O_RCVTIM: // --receivetimeout=25000
opt->receiveTimeout = parseInt(arg, 10, 1000, 100000, result); opt->receiveTimeout = parseInt(arg, 10, 1000, 100000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid receivetimeout"); argp_error(state, "invalid receivetimeout");
return EINVAL; return EINVAL;
} }
break; break;
case O_MASCNT: // --numbermasters=0 case O_MASCNT: // --numbermasters=0
opt->masterCount = parseInt(arg, 10, 0, 25, result); opt->masterCount = parseInt(arg, 10, 0, 25, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid numbermasters"); argp_error(state, "invalid numbermasters");
return EINVAL; return EINVAL;
@@ -434,7 +433,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->pidFile = arg; opt->pidFile = arg;
break; break;
case 'p': // --port=8888 case 'p': // --port=8888
opt->port = (uint16_t)parseInt(arg, 10, 1, 65535, result); opt->port = (uint16_t)parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid port"); argp_error(state, "invalid port");
return EINVAL; return EINVAL;
@@ -444,7 +443,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->localOnly = true; opt->localOnly = true;
break; break;
case O_HTTPPT: // --httpport=0 case O_HTTPPT: // --httpport=0
opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, result); opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid httpport"); argp_error(state, "invalid httpport");
return EINVAL; return EINVAL;
@@ -527,7 +526,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->logRawFile = arg; opt->logRawFile = arg;
break; break;
case O_RAWSIZ: // --lograwdatasize=100 case O_RAWSIZ: // --lograwdatasize=100
opt->logRawSize = parseInt(arg, 10, 1, 1000000, result); opt->logRawSize = parseInt(arg, 10, 1, 1000000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid lograwdatasize"); argp_error(state, "invalid lograwdatasize");
return EINVAL; return EINVAL;
@@ -547,7 +546,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->dumpFile = arg; opt->dumpFile = arg;
break; break;
case O_DMPSIZ: // --dumpsize=100 case O_DMPSIZ: // --dumpsize=100
opt->dumpSize = parseInt(arg, 10, 1, 1000000, result); opt->dumpSize = parseInt(arg, 10, 1, 1000000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid dumpsize"); argp_error(state, "invalid dumpsize");
return EINVAL; return EINVAL;
@@ -555,11 +554,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
break; break;
case ARGP_KEY_ARG: case ARGP_KEY_ARG:
if (!opt->injectMessages) { if (opt->injectMessages || (opt->checkConfig && opt->scanConfig)) {
return ARGP_ERR_UNKNOWN;
}
argp_error(state, "invalid arguments starting with \"%s\"", arg); argp_error(state, "invalid arguments starting with \"%s\"", arg);
return EINVAL; return EINVAL;
}
return ARGP_ERR_UNKNOWN;
default: default:
return ARGP_ERR_UNKNOWN; return ARGP_ERR_UNKNOWN;
} }
@@ -704,7 +703,7 @@ void signalHandler(int sig) {
* @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 path, const string prefix, const string extension,
vector<string>& files, vector<string>* dirs = NULL, bool* hasTemplates = NULL) { vector<string>* files, vector<string>* dirs = NULL, bool* hasTemplates = NULL) {
DIR* dir = opendir(path.c_str()); DIR* dir = opendir(path.c_str());
if (dir == NULL) { if (dir == NULL) {
@@ -735,7 +734,7 @@ static result_t collectConfigFiles(const string path, const string prefix, const
} }
} else if (prefix.length() == 0 } else if (prefix.length() == 0
|| (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) { || (name.length() >= prefix.length() && name.substr(0, prefix.length()) == prefix)) {
files.push_back(p); files->push_back(p);
} }
} }
} }
@@ -744,7 +743,7 @@ static result_t collectConfigFiles(const string path, const string prefix, const
return RESULT_OK; return RESULT_OK;
} }
DataFieldTemplates* getTemplates(const string filename) { DataFieldTemplates* getTemplates(const string& filename) {
string path; string path;
size_t pos = filename.find_last_of('/'); size_t pos = filename.find_last_of('/');
if (pos != string::npos) { if (pos != string::npos) {
@@ -783,7 +782,8 @@ static bool readTemplates(const string path, const string extension, bool availa
return true; return true;
} }
string errorDescription; string errorDescription;
result_t result = templates->readFromFile(path+"/_templates"+extension, errorDescription, verbose); result_t result = templates->readFromFile(path+"/_templates"+extension, verbose, NULL, &errorDescription,
NULL, NULL, NULL);
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", path.c_str());
return true; return true;
@@ -802,18 +802,18 @@ static bool readTemplates(const string path, const string extension, bool availa
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @return the result code. * @return the result code.
*/ */
static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, static result_t readConfigFiles(const string& path, const string& extension, const bool recursive,
bool verbose, string& errorDescription) { 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(path, "", extension, &files, &dirs, &hasTemplates);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
readTemplates(path, extension, hasTemplates, verbose); readTemplates(path, 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, errorDescription, verbose); result = messages->readFromFile(name, verbose, NULL, errorDescription, NULL, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -821,7 +821,7 @@ static result_t readConfigFiles(const string path, const string extension, Messa
if (recursive) { if (recursive) {
for (const auto& name : dirs) { for (const auto& name : dirs) {
logInfo(lf_main, "reading dir %s", name.c_str()); logInfo(lf_main, "reading dir %s", name.c_str());
result = readConfigFiles(name, extension, messages, true, verbose, errorDescription); result = readConfigFiles(name, extension, true, verbose, errorDescription, messages);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -848,13 +848,13 @@ void readMessage(Message* message) {
void executeInstructions(MessageMap* messages, bool verbose) { void executeInstructions(MessageMap* messages, bool verbose) {
string errorDescription; string errorDescription;
result_t result = messages->resolveConditions(errorDescription, verbose); result_t result = messages->resolveConditions(verbose, &errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result),
errorDescription.c_str()); errorDescription.c_str());
} }
ostringstream log; ostringstream log;
result = messages->executeInstructions(log, readMessage); result = messages->executeInstructions(readMessage, &log);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "error executing instructions: %s, last error: %s", getResultCode(result), logError(lf_main, "error executing instructions: %s, last error: %s", getResultCode(result),
log.str().c_str()); log.str().c_str());
@@ -878,8 +878,8 @@ 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", messages, result_t result = readConfigFiles(string(opt.configPath), ".csv",
(!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, errorDescription); (!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");
} else { } else {
@@ -889,7 +889,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
return RESULT_OK; return RESULT_OK;
} }
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose) { result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) {
Message* message = messages->getScanMessage(address); Message* message = messages->getScanMessage(address);
if (!message || message->getLastUpdateTime() == 0) { if (!message || message->getLastUpdateTime() == 0) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
@@ -905,9 +905,9 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
ostringstream out; ostringstream out;
size_t offset = 0; size_t offset = 0;
size_t field = 0; size_t field = 0;
result_t result = (*identFields)[field]->read(data, offset, out, 0); // 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) {
result = (*identFields)[field]->read(data, offset, out, OF_NUMERIC); // 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(); path = out.str();
@@ -918,22 +918,22 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
prefix = out.str(); prefix = out.str();
out.str(""); out.str("");
out.clear(); out.clear();
offset += (*identFields)[field++]->getLength(pt_slaveData); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN);
result = (*identFields)[field]->read(data, offset, out, 0); // identification string result = (*identFields)[field]->read(data, offset, false, NULL, -1, 0, -1, &out); // identification string
} }
if (result == RESULT_OK) { if (result == RESULT_OK) {
ident = out.str(); ident = out.str();
out.str(""); out.str("");
offset += (*identFields)[field++]->getLength(pt_slaveData); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN);
result = (*identFields)[field]->read(data, offset, sw, 0); // 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) {
sw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead sw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead
result = RESULT_OK; result = RESULT_OK;
} }
} }
if (result == RESULT_OK) { if (result == RESULT_OK) {
offset += (*identFields)[field++]->getLength(pt_slaveData); offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN);
result = (*identFields)[field]->read(data, offset, hw, 0); // hardware version number result = (*identFields)[field]->read(data, offset, NULL, -1, &hw); // hardware version number
if (result == RESULT_ERR_OUT_OF_RANGE) { if (result == RESULT_ERR_OUT_OF_RANGE) {
hw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead hw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead
result = RESULT_OK; result = RESULT_OK;
@@ -947,7 +947,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
vector<string> files; vector<string> files;
bool hasTemplates = false; bool hasTemplates = false;
// find files matching MANUFACTURER/ZZ.*csv in cfgpath // find files matching MANUFACTURER/ZZ.*csv in cfgpath
result = collectConfigFiles(path, prefix, ".csv", files, NULL, &hasTemplates); result = collectConfigFiles(path, prefix, ".csv", &files, NULL, &hasTemplates);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(),
getResultCode(result)); getResultCode(result));
@@ -978,7 +978,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
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(path.length()+1);
if (!messages->extractDefaultsFromFilename(filename, defaults, &checkDest, &checkSw, &checkHw)) { if (!messages->extractDefaultsFromFilename(filename, &defaults, &checkDest, &checkSw, &checkHw)) {
continue; continue;
} }
if (address != checkDest || (checkSw != UINT_MAX && sw != checkSw) || (checkHw != UINT_MAX && hw != checkHw)) { if (address != checkDest || (checkSw != UINT_MAX && sw != checkSw) || (checkHw != UINT_MAX && hw != checkHw)) {
@@ -1022,7 +1022,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
// 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(path, ".csv", hasTemplates, opt.checkConfig);
if (readCommon) { if (readCommon) {
result = collectConfigFiles(path, "", ".csv", files); result = collectConfigFiles(path, "", ".csv", &files);
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(path.length()+1, name.length()-path.length()-strlen(".csv")); // *.
@@ -1031,7 +1031,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
} }
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, errorDescription, opt.checkConfig); result = messages->readFromFile(name, opt.checkConfig, NULL, &errorDescription, NULL, NULL, NULL);
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 {
@@ -1044,39 +1044,51 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela
} }
string errorDescription; string errorDescription;
bestDefaults["name"] = ident; bestDefaults["name"] = ident;
result = messages->readFromFile(best, errorDescription, opt.checkConfig, &bestDefaults); result = messages->readFromFile(best, opt.checkConfig, &bestDefaults, &errorDescription, NULL, NULL, NULL);
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", 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)); 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.substr(strlen(opt.configPath)+1);
return RESULT_OK; return RESULT_OK;
} }
bool parseMessage(const string& arg, MasterSymbolString& master, SlaveSymbolString& slave, bool onlyMasterSlave) { /**
* Helper method for parsing a master/slave message pair from a command line argument.
* @param arg the argument to parse.
* @param onlyMasterSlave true to parse only a MS message, false to also parse MM and BC message.
* @param master the @a MasterSymbolString to parse into.
* @param slave the @a SlaveSymbolString to parse into.
* @return true when the argument was valid, false otherwise.
*/
bool parseMessage(const string& arg, bool onlyMasterSlave, MasterSymbolString* master, SlaveSymbolString* slave) {
size_t pos = arg.find_first_of('/'); size_t pos = arg.find_first_of('/');
if (pos == string::npos) { if (pos == string::npos) {
logError(lf_main, "invalid message %s: missing \"/\"", arg.c_str()); logError(lf_main, "invalid message %s: missing \"/\"", arg.c_str());
return false; return false;
} }
result_t result = master.parseHex(arg.substr(0, pos)); result_t result = master->parseHex(arg.substr(0, pos));
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = slave.parseHex(arg.substr(pos+1)); result = slave->parseHex(arg.substr(pos+1));
} }
if (result != RESULT_OK) { if (result != RESULT_OK) {
logError(lf_main, "invalid message %s: %s", arg.c_str(), getResultCode(result)); logError(lf_main, "invalid message %s: %s", arg.c_str(), getResultCode(result));
return false; return false;
} }
if (master.size() < 5) { // skip QQ ZZ PB SB NN if (master->size() < 5) { // skip QQ ZZ PB SB NN
logError(lf_main, "invalid message %s: master part too short", arg.c_str()); logError(lf_main, "invalid message %s: master part too short", arg.c_str());
return false; return false;
} }
if (!isMaster(master[0])) { if (!isMaster((*master)[0])) {
logError(lf_main, "invalid message %s: QQ is no master", arg.c_str()); logError(lf_main, "invalid message %s: QQ is no master", arg.c_str());
return false; return false;
} }
if (!isValidAddress((*master)[1], !onlyMasterSlave) || (onlyMasterSlave && isMaster((*master)[1]))) {
logError(lf_main, "invalid message %s: ZZ is invalid", arg.c_str());
return false;
}
return true; return true;
} }
@@ -1114,7 +1126,7 @@ int main(int argc, char* argv[]) {
SlaveSymbolString slave; SlaveSymbolString slave;
while (result == RESULT_OK && opt.scanConfig && arg_index < argc) { while (result == RESULT_OK && opt.scanConfig && arg_index < argc) {
// check scan config for each passed ident message // check scan config for each passed ident message
if (!parseMessage(argv[arg_index++], master, slave, true)) { if (!parseMessage(argv[arg_index++], true, &master, &slave)) {
continue; continue;
} }
symbol_t address = master[1]; symbol_t address = master[1];
@@ -1124,7 +1136,7 @@ int main(int argc, char* argv[]) {
} else { } else {
message->storeLastData(master, slave); message->storeLastData(master, slave);
string file; string file;
result_t res = loadScanConfigFile(s_messageMap, address, file, true); result_t res = loadScanConfigFile(s_messageMap, address, true, &file);
executeInstructions(s_messageMap, true); executeInstructions(s_messageMap, true);
if (res == RESULT_OK) { if (res == RESULT_OK) {
logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str()); logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str());
@@ -1133,7 +1145,7 @@ int main(int argc, char* argv[]) {
} }
if (result == RESULT_OK && opt.dumpConfig) { if (result == RESULT_OK && opt.dumpConfig) {
logNotice(lf_main, "configuration dump:"); logNotice(lf_main, "configuration dump:");
s_messageMap->dump(cout, true); s_messageMap->dump(true, &cout);
} }
shutdown(); shutdown();
return 0; return 0;
@@ -1170,7 +1182,7 @@ int main(int argc, char* argv[]) {
SlaveSymbolString slave; SlaveSymbolString slave;
while (arg_index < argc) { while (arg_index < argc) {
// add each passed message // add each passed message
if (!parseMessage(argv[arg_index++], master, slave, false)) { if (!parseMessage(argv[arg_index++], false, &master, &slave)) {
continue; continue;
} }
busHandler->injectMessage(master, slave); busHandler->injectMessage(master, slave);
+3 -3
View File
@@ -89,7 +89,7 @@ struct options {
* @param filename the full name of the configuration file. * @param filename the full name of the configuration file.
* @return the @a DataFieldTemplates. * @return the @a DataFieldTemplates.
*/ */
DataFieldTemplates* getTemplates(const string filename); DataFieldTemplates* getTemplates(const string& filename);
/** /**
* Load the message definitions from configuration files. * Load the message definitions from configuration files.
@@ -106,11 +106,11 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose = false, bool denyRe
* @param address the address of the scan participant * @param address the address of the scan participant
* (either master for broadcast master data or slave for read slave data). * (either master for broadcast master data or slave for read slave data).
* @param data the scan @a SlaveSymbolString for which to load the configuration file. * @param data the scan @a SlaveSymbolString for which to load the configuration file.
* @param relativeFile the string in which the name of the configuration file is stored on success.
* @param verbose whether to verbosely log problems. * @param verbose whether to verbosely log problems.
* @param relativeFile the string in which the name of the configuration file is stored on success.
* @return the result code. * @return the result code.
*/ */
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& relativeFile, bool verbose = false); result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile);
/** /**
* Helper method for executing all loaded and resolvable instructions. * Helper method for executing all loaded and resolvable instructions.
+135 -131
View File
@@ -41,26 +41,26 @@ using std::ifstream;
#define RECONNECT_MISSING_SIGNAL 60 #define RECONNECT_MISSING_SIGNAL 60
result_t UserList::getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const { result_t UserList::getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const {
// name,secret,level[,level]* // name,secret,level[,level]*
if (row.empty()) { if (row->empty()) {
row.push_back("name"); row->push_back("name");
row.push_back("secret"); row->push_back("secret");
row.push_back("*level"); row->push_back("*level");
return RESULT_OK; return RESULT_OK;
} }
map<string, string> seen; map<string, string> seen;
for (auto& name : row) { for (auto& name : *row) {
tolower(name); tolower(&name);
if (name == "name" || name == "secret") { if (name == "name" || name == "secret") {
if (seen.find(name) != seen.end()) { if (seen.find(name) != seen.end()) {
errorDescription = "duplicate field " + name; *errorDescription = "duplicate field " + name;
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
} else if (name == "level") { } else if (name == "level") {
name = "*level"; name = "*level";
} else { } else {
errorDescription = "unknown field " + name; *errorDescription = "unknown field " + name;
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
seen[name] = name; seen[name] = name;
@@ -71,10 +71,10 @@ result_t UserList::getFieldMap(vector<string>& row, string& errorDescription, co
return RESULT_OK; return RESULT_OK;
} }
result_t UserList::addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) { vector< map<string, string> >* subRows, string* errorDescription) {
string name = row["name"]; string name = (*row)["name"];
string secret = row["secret"]; string secret = (*row)["secret"];
if (name.empty()) { if (name.empty()) {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
@@ -82,7 +82,7 @@ result_t UserList::addFromFile(map<string, string>& row, vector< map<string, str
name = ""; // default levels name = ""; // default levels
} }
string levels; string levels;
for (const auto& entry : subRows) { for (const auto& entry : *subRows) {
const auto it = entry.find("level"); const auto it = entry.find("level");
if (it != entry.end() && !it->second.empty()) { if (it != entry.end() && !it->second.empty()) {
if (!levels.empty()) { if (!levels.empty()) {
@@ -97,7 +97,7 @@ result_t UserList::addFromFile(map<string, string>& row, vector< map<string, str
} }
MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* messages) MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages)
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages), : Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.readOnly ? ESC : opt.initialScan), m_address(opt.address), m_scanConfig(opt.scanConfig), m_initialScan(opt.readOnly ? ESC : opt.initialScan),
m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex), m_shutdown(false) { m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex), m_shutdown(false) {
@@ -125,7 +125,7 @@ MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* message
m_logRawLastSymbol = SYN; m_logRawLastSymbol = SYN;
if (opt.aclFile[0]) { if (opt.aclFile[0]) {
string errorDescription; string errorDescription;
result_t result = m_userList.readFromFile(opt.aclFile, errorDescription); result_t result = m_userList.readFromFile(opt.aclFile, false, NULL, &errorDescription, NULL, NULL, NULL);
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));
} }
@@ -149,7 +149,7 @@ MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* message
m_htmlPath = opt.htmlPath; m_htmlPath = opt.htmlPath;
m_network = new Network(opt.localOnly, opt.port, opt.httpPort, &m_netQueue); m_network = new Network(opt.localOnly, opt.port, opt.httpPort, &m_netQueue);
m_network->start("network"); m_network->start("network");
if (!datahandler_register(&m_userList, m_busHandler, messages, m_dataHandlers)) { if (!datahandler_register(&m_userList, m_busHandler, messages, &m_dataHandlers)) {
logError(lf_main, "error registering data handlers"); logError(lf_main, "error registering data handlers");
} }
} }
@@ -247,9 +247,9 @@ void MainLoop::run() {
MasterSymbolString master; MasterSymbolString master;
SlaveSymbolString slave; SlaveSymbolString slave;
istringstream input; istringstream input;
result = message->prepareMaster(m_address, master, input); result = message->prepareMaster(0, m_address, SYN, UI_FIELD_SEPARATOR, &input, &master);
if (result == RESULT_OK) { if (result == RESULT_OK) {
result = m_busHandler->sendAndWait(master, slave); result = m_busHandler->sendAndWait(master, &slave);
} }
} else { } else {
result = RESULT_ERR_NOTFOUND; result = RESULT_ERR_NOTFOUND;
@@ -259,7 +259,7 @@ void MainLoop::run() {
result = m_busHandler->scanAndWait(m_initialScan, true); result = m_busHandler->scanAndWait(m_initialScan, true);
if (result == RESULT_OK) { if (result == RESULT_OK) {
ostringstream ret; ostringstream ret;
if (m_busHandler->formatScanResult(m_initialScan, ret, false)) { if (m_busHandler->formatScanResult(m_initialScan, false, &ret)) {
logNotice(lf_main, "initial scan result: %s", ret.str().c_str()); logNotice(lf_main, "initial scan result: %s", ret.str().c_str());
} }
} }
@@ -301,37 +301,37 @@ void MainLoop::run() {
if (socket) { if (socket) {
socket->setTimeout(5); socket->setTimeout(5);
ostringstream ostr; ostringstream ostr;
ostr << "{\"v\":\"" << PACKAGE_VERSION "\""; ostr << "{\"v\":\"" << PACKAGE_VERSION "\""
ostr << ",\"r\":\"" << REVISION << "\""; << ",\"r\":\"" << REVISION << "\""
#if defined(__amd64__) || defined(__x86_64__) || defined(__ia64__) || defined(__IA64__) #if defined(__amd64__) || defined(__x86_64__) || defined(__ia64__) || defined(__IA64__)
ostr << ",\"a\":\"amd64\""; << ",\"a\":\"amd64\""
#elif defined(__aarch64__) #elif defined(__aarch64__)
ostr << ",\"a\":\"aarch64\""; << ",\"a\":\"aarch64\""
#elif defined(__arm__) #elif defined(__arm__)
ostr << ",\"a\":\"arm\""; << ",\"a\":\"arm\""
#elif defined(__i386__) || defined(__i686__) #elif defined(__i386__) || defined(__i686__)
ostr << ",\"a\":\"i386\""; << ",\"a\":\"i386\""
#elif defined(__mips__) #elif defined(__mips__)
ostr << ",\"a\":\"mips\""; << ",\"a\":\"mips\""
#else #else
ostr << ",\"a\":\"other\""; << ",\"a\":\"other\""
#endif #endif
ostr << ",\"u\":" << (now-start); << ",\"u\":" << (now-start);
if (m_reconnectCount) { if (m_reconnectCount) {
ostr << ",\"rc\":" << m_reconnectCount; ostr << ",\"rc\":" << m_reconnectCount;
} }
m_busHandler->formatUpdateInfo(ostr); m_busHandler->formatUpdateInfo(&ostr);
ostr << "}"; ostr << "}";
string str = ostr.str(); string str = ostr.str();
ostr.clear(); ostr.clear();
ostr.str(""); ostr.str("");
ostr << "POST /updatecheck/ HTTP/1.0\r\n"; ostr << "POST /updatecheck/ HTTP/1.0\r\n"
ostr << "Host: ebusd.eu" << "\r\n"; << "Host: ebusd.eu" << "\r\n"
ostr << "User-Agent: " << PACKAGE_NAME << "/" << PACKAGE_VERSION << "\r\n"; << "User-Agent: " << PACKAGE_NAME << "/" << PACKAGE_VERSION << "\r\n"
ostr << "Content-Type: application/json; charset=utf-8\r\n"; << "Content-Type: application/json; charset=utf-8\r\n"
ostr << "Content-Length: " << dec << str.length() << "\r\n"; << "Content-Length: " << dec << str.length() << "\r\n"
ostr << "\r\n"; << "\r\n"
ostr << str; << str;
str = ostr.str(); str = ostr.str();
const char* cstr = str.c_str(); const char* cstr = str.c_str();
size_t len = str.size(); size_t len = str.size();
@@ -417,7 +417,7 @@ void MainLoop::run() {
bool connected = true; bool connected = true;
if (request.length() > 0) { if (request.length() > 0) {
logDebug(lf_main, ">>> %s", request.c_str()); logDebug(lf_main, ">>> %s", request.c_str());
ostream << decodeMessage(request, netMessage->isHttp(), connected, listening, user, reload); ostream << decodeMessage(request, netMessage->isHttp(), &connected, &listening, &user, &reload);
if (ostream.tellp() == 0 && !netMessage->isHttp()) { if (ostream.tellp() == 0 && !netMessage->isHttp()) {
ostream << getResultCode(RESULT_EMPTY); ostream << getResultCode(RESULT_EMPTY);
@@ -438,7 +438,7 @@ void MainLoop::run() {
messages = m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now); messages = m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now);
for (const auto message : messages) { for (const auto message : messages) {
ostream << message->getCircuit() << " " << message->getName() << " = " << dec; ostream << message->getCircuit() << " " << message->getName() << " = " << dec;
message->decodeLastData(ostream); message->decodeLastData(false, NULL, -1, 0, &ostream);
ostream << endl; ostream << endl;
} }
} }
@@ -447,7 +447,7 @@ void MainLoop::run() {
} }
} }
void MainLoop::notifyDeviceData(const symbol_t symbol, bool received) { void MainLoop::notifyDeviceData(symbol_t symbol, bool received) {
if (received && m_dumpFile) { if (received && m_dumpFile) {
m_dumpFile->write((unsigned char*)&symbol, 1); m_dumpFile->write((unsigned char*)&symbol, 1);
} }
@@ -488,8 +488,8 @@ void MainLoop::notifyDeviceData(const symbol_t symbol, bool received) {
} }
} }
string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, string MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, bool* listening,
string& user, bool& reload) { string* user, bool* reload) {
string token, previous; string token, previous;
istringstream stream(data); istringstream stream(data);
vector<string> args; vector<string> args;
@@ -528,7 +528,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
if (strcmp(str, "GET") == 0) { if (strcmp(str, "GET") == 0) {
return executeGet(args, connected); return executeGet(args, connected);
} }
connected = false; *connected = false;
return "HTTP/1.0 405 Method Not Allowed\r\n\r\n"; return "HTTP/1.0 405 Method Not Allowed\r\n\r\n";
} }
@@ -553,10 +553,10 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
return executeAuth(args, user); return executeAuth(args, user);
} }
if (cmd == "R" || cmd == "READ") { if (cmd == "R" || cmd == "READ") {
return executeRead(args, getUserLevels(user)); return executeRead(args, getUserLevels(*user));
} }
if (cmd == "W" || cmd == "WRITE") { if (cmd == "W" || cmd == "WRITE") {
return executeWrite(args, getUserLevels(user)); return executeWrite(args, getUserLevels(*user));
} }
if (cmd == "HEX") { if (cmd == "HEX") {
if (m_enableHex) { if (m_enableHex) {
@@ -565,7 +565,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
return "ERR: command not enabled"; return "ERR: command not enabled";
} }
if (cmd == "F" || cmd == "FIND") { if (cmd == "F" || cmd == "FIND") {
return executeFind(args, getUserLevels(user)); return executeFind(args, getUserLevels(*user));
} }
if (cmd == "L" || cmd == "LISTEN") { if (cmd == "L" || cmd == "LISTEN") {
return executeListen(args, listening); return executeListen(args, listening);
@@ -577,7 +577,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
return executeGrab(args); return executeGrab(args);
} }
if (cmd == "SCAN") { if (cmd == "SCAN") {
return executeScan(args, getUserLevels(user)); return executeScan(args, getUserLevels(*user));
} }
if (cmd == "LOG") { if (cmd == "LOG") {
return executeLog(args); return executeLog(args);
@@ -589,14 +589,14 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
return executeDump(args); return executeDump(args);
} }
if (cmd == "RELOAD") { if (cmd == "RELOAD") {
reload = true; *reload = true;
return executeReload(args); return executeReload(args);
} }
if (cmd == "Q" || cmd == "QUIT") { if (cmd == "Q" || cmd == "QUIT") {
return executeQuit(args, connected); return executeQuit(args, connected);
} }
if (cmd == "I" || cmd == "INFO") { if (cmd == "I" || cmd == "INFO") {
return executeInfo(args, user); return executeInfo(args, *user);
} }
if (cmd == "?" || cmd == "H" || cmd == "HELP") { if (cmd == "?" || cmd == "H" || cmd == "HELP") {
return executeHelp(); return executeHelp();
@@ -604,8 +604,8 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn
return "ERR: command not found"; return "ERR: command not found";
} }
result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, MasterSymbolString& master, result_t MainLoop::parseHexMaster(const vector<string>& args, size_t argPos, symbol_t srcAddress,
symbol_t srcAddress) { MasterSymbolString* master) {
ostringstream msg; ostringstream msg;
while (argPos < args.size()) { while (argPos < args.size()) {
if ((args[argPos].length() % 2) != 0) { if ((args[argPos].length() % 2) != 0) {
@@ -617,22 +617,22 @@ result_t MainLoop::parseHexMaster(vector<string> &args, size_t argPos, MasterSym
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
result_t ret; result_t ret;
unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, ret); unsigned int length = parseInt(msg.str().substr(3*2, 2).c_str(), 16, 0, MAX_POS, &ret);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return ret; return ret;
} }
if ((4+length)*2 != msg.str().size()) { if ((4+length)*2 != msg.str().size()) {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
master.push_back(srcAddress == SYN ? m_address : srcAddress); master->push_back(srcAddress == SYN ? m_address : srcAddress);
ret = master.parseHex(msg.str()); ret = master->parseHex(msg.str());
if (ret == RESULT_OK && !isValidAddress(master[1])) { if (ret == RESULT_OK && !isValidAddress((*master)[1])) {
ret = RESULT_ERR_INVALID_ADDR; ret = RESULT_ERR_INVALID_ADDR;
} }
return ret; return ret;
} }
string MainLoop::executeAuth(vector<string> &args, string &user) { string MainLoop::executeAuth(const vector<string>& args, string *user) {
if (args.size() != 3) { if (args.size() != 3) {
return "usage: auth USER SECRET\n" return "usage: auth USER SECRET\n"
" Authenticate with USER name and SECRET.\n" " Authenticate with USER name and SECRET.\n"
@@ -640,13 +640,13 @@ string MainLoop::executeAuth(vector<string> &args, string &user) {
" SECRET the secret string of the user"; " SECRET the secret string of the user";
} }
if (m_userList.checkSecret(args[1], args[2])) { if (m_userList.checkSecret(args[1], args[2])) {
user = args[1]; *user = args[1];
return getResultCode(RESULT_OK); return getResultCode(RESULT_OK);
} }
return "ERR: invalid user name or secret"; return "ERR: invalid user name or secret";
} }
string MainLoop::executeRead(vector<string> &args, const string levels) { string MainLoop::executeRead(const vector<string>& args, const string& levels) {
size_t argPos = 1; size_t argPos = 1;
bool hex = false, numeric = false, valueName = false; bool hex = false, numeric = false, valueName = false;
OutputFormat verbosity = 0; OutputFormat verbosity = 0;
@@ -684,7 +684,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
argPos++; argPos++;
if (args.size() > argPos) { if (args.size() > argPos) {
result_t result; result_t result;
maxAge = parseInt(args[argPos].c_str(), 10, 0, 24*60*60, result); maxAge = parseInt(args[argPos].c_str(), 10, 0, 24*60*60, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
@@ -708,7 +708,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
} }
bool dest = args[argPos] == "-d"; bool dest = args[argPos] == "-d";
result_t ret; result_t ret;
symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, ret); symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, &ret);
if (ret != RESULT_OK || !isValidAddress(address, dest) || dest == isMaster(address)) { if (ret != RESULT_OK || !isValidAddress(address, dest) || dest == isMaster(address)) {
return getResultCode(RESULT_ERR_INVALID_ADDR); return getResultCode(RESULT_ERR_INVALID_ADDR);
} }
@@ -724,7 +724,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
break; break;
} }
result_t ret; result_t ret;
pollPriority = (size_t)parseInt(args[argPos].c_str(), 10, 1, 9, ret); pollPriority = (size_t)parseInt(args[argPos].c_str(), 10, 1, 9, &ret);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(RESULT_ERR_INVALID_NUM); return getResultCode(RESULT_ERR_INVALID_NUM);
} }
@@ -751,7 +751,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
if (hex && argPos > 0) { if (hex && argPos > 0) {
MasterSymbolString master; MasterSymbolString master;
result_t ret = parseHexMaster(args, argPos, master, srcAddress); result_t ret = parseHexMaster(args, argPos, srcAddress, &master);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
@@ -785,13 +785,13 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
// send message // send message
SlaveSymbolString slave; SlaveSymbolString slave;
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, &slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->storeLastData(master, slave); ret = message->storeLastData(master, slave);
ostringstream result; ostringstream result;
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->decodeLastData(result); ret = message->decodeLastData(false, NULL, -1, 0, &result);
} }
if (ret >= RESULT_OK) { if (ret >= RESULT_OK) {
logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(), logInfo(lf_main, "read hex %s %s cache update: %s", message->getCircuit().c_str(), message->getName().c_str(),
@@ -839,7 +839,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
size_t pos = fieldName.find_last_of('.'); size_t pos = fieldName.find_last_of('.');
if (pos != string::npos) { if (pos != string::npos) {
result_t result = RESULT_OK; result_t result = RESULT_OK;
fieldIndex = static_cast<ssize_t>(parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, result)); fieldIndex = static_cast<ssize_t>(parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, &result));
if (result == RESULT_OK) { if (result == RESULT_OK) {
fieldName = fieldName.substr(0, pos); fieldName = fieldName.substr(0, pos);
} }
@@ -850,7 +850,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
Message* message = m_messages->find(circuit, args[argPos], levels, false); Message* message = m_messages->find(circuit, args[argPos], levels, false);
// adjust poll priority // adjust poll priority
if (message != NULL && pollPriority > 0 && message->setPollPriority(pollPriority)) { if (message != NULL && pollPriority > 0 && message->setPollPriority(pollPriority)) {
m_messages->addPollMessage(message); m_messages->addPollMessage(false, message);
} }
verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0; verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0;
result_t ret; result_t ret;
@@ -866,8 +866,8 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
if (verbosity & OF_NAMES) { if (verbosity & OF_NAMES) {
result << cacheMessage->getCircuit() << " " << cacheMessage->getName() << " "; result << cacheMessage->getCircuit() << " " << cacheMessage->getName() << " ";
} }
ret = cacheMessage->decodeLastData(result, verbosity, false, fieldIndex == -2 ? NULL : fieldName.c_str(), ret = cacheMessage->decodeLastData(false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex, verbosity,
fieldIndex); &result);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
if (ret < RESULT_OK) { if (ret < RESULT_OK) {
logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(),
@@ -899,8 +899,8 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
if (verbosity & OF_NAMES) { if (verbosity & OF_NAMES) {
result << message->getCircuit() << " " << message->getName() << " "; result << message->getCircuit() << " " << message->getName() << " ";
} }
ret = message->decodeLastSlaveData(result, verbosity, false, fieldIndex == -2 ? NULL : fieldName.c_str(), ret = message->decodeLastData(false, false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex, verbosity,
fieldIndex); &result);
if (ret < RESULT_OK) { if (ret < RESULT_OK) {
logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret)); getResultCode(ret));
@@ -915,7 +915,7 @@ string MainLoop::executeRead(vector<string> &args, const string levels) {
return result.str(); return result.str();
} }
string MainLoop::executeWrite(vector<string> &args, const string levels) { string MainLoop::executeWrite(const vector<string>& args, const string levels) {
size_t argPos = 1; size_t argPos = 1;
bool hex = false; bool hex = false;
string circuit; string circuit;
@@ -931,7 +931,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
} }
bool dest = args[argPos] == "-d"; bool dest = args[argPos] == "-d";
result_t ret; result_t ret;
symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, ret); symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, &ret);
if (ret != RESULT_OK || !isValidAddress(address, dest) || dest == isMaster(address)) { if (ret != RESULT_OK || !isValidAddress(address, dest) || dest == isMaster(address)) {
return getResultCode(RESULT_ERR_INVALID_ADDR); return getResultCode(RESULT_ERR_INVALID_ADDR);
} }
@@ -960,7 +960,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
if (hex && argPos > 0) { if (hex && argPos > 0) {
MasterSymbolString master; MasterSymbolString master;
result_t ret = parseHexMaster(args, argPos, master, srcAddress); result_t ret = parseHexMaster(args, argPos, srcAddress, &master);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
@@ -983,14 +983,14 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
} }
// send message // send message
SlaveSymbolString slave; SlaveSymbolString slave;
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, &slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
// also update read messages // also update read messages
ret = message->storeLastData(master, slave); ret = message->storeLastData(master, slave);
ostringstream result; ostringstream result;
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
ret = message->decodeLastData(result); ret = message->decodeLastData(false, NULL, -1, 0, &result);
} }
if (ret >= RESULT_OK) { if (ret >= RESULT_OK) {
logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(),
@@ -1054,7 +1054,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
return getResultCode(RESULT_OK); return getResultCode(RESULT_OK);
} }
ret = message->decodeLastSlaveData(result); // decode data ret = message->decodeLastData(false, false, NULL, -1, 0, &result); // decode data
if (ret >= RESULT_OK && result.str().empty()) { if (ret >= RESULT_OK && result.str().empty()) {
logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(ret)); getResultCode(ret));
@@ -1072,7 +1072,7 @@ string MainLoop::executeWrite(vector<string> &args, const string levels) {
return result.str(); return result.str();
} }
string MainLoop::executeHex(vector<string> &args) { string MainLoop::executeHex(const vector<string>& args) {
size_t argPos = 1; size_t argPos = 1;
symbol_t srcAddress = SYN; symbol_t srcAddress = SYN;
if (args.size() > argPos && args[argPos] == "-s") { if (args.size() > argPos && args[argPos] == "-s") {
@@ -1081,7 +1081,7 @@ string MainLoop::executeHex(vector<string> &args) {
argPos = 0; // print usage argPos = 0; // print usage
} else { } else {
result_t ret; result_t ret;
symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, ret); symbol_t address = (symbol_t)parseInt(args[argPos].c_str(), 16, 0, 0xff, &ret);
if (ret != RESULT_OK || !isValidAddress(address, false) || !isMaster(address)) { if (ret != RESULT_OK || !isValidAddress(address, false) || !isMaster(address)) {
return getResultCode(RESULT_ERR_INVALID_ADDR); return getResultCode(RESULT_ERR_INVALID_ADDR);
} }
@@ -1095,7 +1095,7 @@ string MainLoop::executeHex(vector<string> &args) {
if (argPos > 0) { if (argPos > 0) {
MasterSymbolString master; MasterSymbolString master;
result_t ret = parseHexMaster(args, argPos, master, srcAddress); result_t ret = parseHexMaster(args, argPos, srcAddress, &master);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
return getResultCode(ret); return getResultCode(ret);
} }
@@ -1103,7 +1103,7 @@ string MainLoop::executeHex(vector<string> &args) {
// send message // send message
SlaveSymbolString slave; SlaveSymbolString slave;
ret = m_busHandler->sendAndWait(master, slave); ret = m_busHandler->sendAndWait(master, &slave);
if (ret == RESULT_OK) { if (ret == RESULT_OK) {
if (master[1] == BROADCAST) { if (master[1] == BROADCAST) {
@@ -1127,10 +1127,11 @@ string MainLoop::executeHex(vector<string> &args) {
" Dx data byte(s) to send"; " Dx data byte(s) to send";
} }
string MainLoop::executeFind(vector<string> &args, string levels) { string MainLoop::executeFind(const vector<string>& args, const string& levels) {
size_t argPos = 1; size_t argPos = 1;
bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true, bool configFormat = false, exact = false, withRead = true, withWrite = false, withPassive = true, first = true,
onlyWithData = false, hexFormat = false, userLevel = true; onlyWithData = false, hexFormat = false, userLevel = true, withConditions = false;
string useLevels = levels;
OutputFormat verbosity = 0; OutputFormat verbosity = 0;
vector<string> fieldNames; vector<string> fieldNames;
string circuit; string circuit;
@@ -1166,7 +1167,7 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
} }
if (!Message::extractFieldNames(args[argPos], fieldNames)) { if (!Message::extractFieldNames(args[argPos], true, &fieldNames)) {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
} }
@@ -1191,7 +1192,7 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
} }
withPassive = true; withPassive = true;
} else if (args[argPos] == "-a") { } else if (args[argPos] == "-a") {
withRead = withWrite = withPassive = true; withRead = withWrite = withPassive = withConditions = true;
} else if (args[argPos] == "-d") { } else if (args[argPos] == "-d") {
onlyWithData = true; onlyWithData = true;
} else if (args[argPos] == "-h") { } else if (args[argPos] == "-h") {
@@ -1206,7 +1207,7 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
} }
result_t result = Message::parseId(args[argPos], id); result_t result = Message::parseId(args[argPos], &id);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return getResultCode(result); return getResultCode(result);
} }
@@ -1227,7 +1228,7 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
argPos = 0; // print usage argPos = 0; // print usage
break; break;
} }
levels = args[argPos]; useLevels = args[argPos];
userLevel = false; userLevel = false;
} else { } else {
argPos = 0; // print usage argPos = 0; // print usage
@@ -1244,7 +1245,7 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
" -r limit to active read messages (default: read + passive)\n" " -r limit to active read messages (default: read + passive)\n"
" -w limit to active write messages (default: read + passive)\n" " -w limit to active write messages (default: read + passive)\n"
" -p limit to passive messages (default: read + passive)\n" " -p limit to passive messages (default: read + passive)\n"
" -a include all message types (read, passive, and write)\n" " -a include all message types (read, passive, and write) and all conditional\n"
" -d only include messages with actual data\n" " -d only include messages with actual data\n"
" -h show hex data instead of decoded values\n" " -h show hex data instead of decoded values\n"
" -i ID limit to messages with ID (in hex, PB, SB and further ID bytes)\n" " -i ID limit to messages with ID (in hex, PB, SB and further ID bytes)\n"
@@ -1256,8 +1257,8 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
" -l LEVEL limit to messages with access LEVEL (\"*\" for any, default: current level)\n" " -l LEVEL limit to messages with access LEVEL (\"*\" for any, default: current level)\n"
" NAME NAME of the messages to find (or a part thereof without '-e')"; " NAME NAME of the messages to find (or a part thereof without '-e')";
} }
deque<Message*> messages = m_messages->findAll( deque<Message*> messages = m_messages->findAll(circuit, args.size() == argPos ? "" : args[argPos], useLevels,
circuit, args.size() == argPos ? "" : args[argPos], levels, exact, withRead, withWrite, withPassive, userLevel); exact, withRead, withWrite, withPassive, userLevel, !withConditions);
bool found = false; bool found = false;
ostringstream result; ostringstream result;
@@ -1274,12 +1275,12 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
if (found) { if (found) {
result << endl; result << endl;
} }
message->dump(result); message->dump(NULL, withConditions, &result);
} else if (!fieldNames.empty()) { } else if (!fieldNames.empty()) {
if (found) { if (found) {
result << endl; result << endl;
} }
message->dump(result, &fieldNames); message->dump(&fieldNames, withConditions, &result);
} else { } else {
if (found) { if (found) {
result << endl; result << endl;
@@ -1287,10 +1288,13 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
result << message->getCircuit() << " " << message->getName() << " = "; result << message->getCircuit() << " " << message->getName() << " = ";
if (lastup == 0) { if (lastup == 0) {
result << "no data stored"; result << "no data stored";
if (!message->isAvailable()) {
result << " (message not available due to condition)";
}
} else if (hexFormat) { } else if (hexFormat) {
result << message->getLastMasterData().getStr() << " / " << message->getLastSlaveData().getStr(); result << message->getLastMasterData().getStr() << " / " << message->getLastSlaveData().getStr();
} else { } else {
result_t ret = message->decodeLastData(result, verbosity); result_t ret = message->decodeLastData(false, NULL, -1, verbosity, &result);
if (ret != RESULT_OK) { if (ret != RESULT_OK) {
result << " (" << getResultCode(ret) result << " (" << getResultCode(ret)
<< " for " << message->getLastMasterData().getStr() << " for " << message->getLastMasterData().getStr()
@@ -1335,12 +1339,12 @@ string MainLoop::executeFind(vector<string> &args, string levels) {
return result.str(); return result.str();
} }
string MainLoop::executeListen(vector<string> &args, bool& listening) { string MainLoop::executeListen(const vector<string>& args, bool* listening) {
if (args.size() == 1) { if (args.size() == 1) {
if (listening) { if (listening) {
return "listen continued"; return "listen continued";
} }
listening = true; *listening = true;
return "listen started"; return "listen started";
} }
@@ -1348,11 +1352,11 @@ string MainLoop::executeListen(vector<string> &args, bool& listening) {
return "usage: listen [stop]\n" return "usage: listen [stop]\n"
" Listen for updates or stop it."; " Listen for updates or stop it.";
} }
listening = false; *listening = false;
return "listen stopped"; return "listen stopped";
} }
string MainLoop::executeState(vector<string> &args) { string MainLoop::executeState(const vector<string>& args) {
if (args.size() == 0) { if (args.size() == 0) {
return "usage: state\n" return "usage: state\n"
" Report bus state."; " Report bus state.";
@@ -1368,7 +1372,7 @@ string MainLoop::executeState(vector<string> &args) {
return "no signal"; return "no signal";
} }
string MainLoop::executeGrab(vector<string> &args) { string MainLoop::executeGrab(const vector<string>& args) {
if (args.size() == 1) { if (args.size() == 1) {
return m_busHandler->enableGrab(true) ? "grab started" : "grab continued"; return m_busHandler->enableGrab(true) ? "grab started" : "grab continued";
} }
@@ -1378,12 +1382,12 @@ string MainLoop::executeGrab(vector<string> &args) {
if (args.size() >= 2 && args[1] == "result") { if (args.size() >= 2 && args[1] == "result") {
if (args.size() == 2 || args[2] == "all") { if (args.size() == 2 || args[2] == "all") {
ostringstream result; ostringstream result;
m_busHandler->formatGrabResult(args.size() == 2, result); m_busHandler->formatGrabResult(args.size() == 2, false, &result);
return result.str(); return result.str();
} }
if (args.size() == 3 || args[2] == "decode") { if (args.size() == 3 || args[2] == "decode") {
ostringstream result; ostringstream result;
m_busHandler->formatGrabResult(true, result, true); m_busHandler->formatGrabResult(true, true, &result);
return result.str(); return result.str();
} }
} }
@@ -1392,7 +1396,7 @@ string MainLoop::executeGrab(vector<string> &args) {
" Start or stop grabbing, or report/decode unknown or all grabbed messages."; " Start or stop grabbing, or report/decode unknown or all grabbed messages.";
} }
string MainLoop::executeScan(vector<string> &args, string levels) { string MainLoop::executeScan(const vector<string>& args, string levels) {
if (args.size() == 1) { if (args.size() == 1) {
result_t result = m_busHandler->startScan(false, levels); result_t result = m_busHandler->startScan(false, levels);
if (result == RESULT_ERR_DUPLICATE) { if (result == RESULT_ERR_DUPLICATE) {
@@ -1415,12 +1419,12 @@ string MainLoop::executeScan(vector<string> &args, string levels) {
if (args[1] == "result") { if (args[1] == "result") {
ostringstream ret; ostringstream ret;
m_busHandler->formatScanResult(ret); m_busHandler->formatScanResult(&ret);
return ret.str(); return ret.str();
} }
result_t result; result_t result;
symbol_t dstAddress = (symbol_t)parseInt(args[1].c_str(), 16, 0, 0xff, result); symbol_t dstAddress = (symbol_t)parseInt(args[1].c_str(), 16, 0, 0xff, &result);
if (result == RESULT_OK && !isValidAddress(dstAddress, false)) { if (result == RESULT_OK && !isValidAddress(dstAddress, false)) {
result = RESULT_ERR_INVALID_ADDR; result = RESULT_ERR_INVALID_ADDR;
} }
@@ -1432,7 +1436,7 @@ string MainLoop::executeScan(vector<string> &args, string levels) {
return getResultCode(result); return getResultCode(result);
} }
ostringstream ret; ostringstream ret;
if (!m_busHandler->formatScanResult(dstAddress, ret, false)) { if (!m_busHandler->formatScanResult(dstAddress, false, &ret)) {
return getResultCode(RESULT_EMPTY); return getResultCode(RESULT_EMPTY);
} }
return ret.str(); return ret.str();
@@ -1443,7 +1447,7 @@ string MainLoop::executeScan(vector<string> &args, string levels) {
" Scan seen slaves, all slaves (full), a single slave (address ZZ), or report scan result."; " Scan seen slaves, all slaves (full), a single slave (address ZZ), or report scan result.";
} }
string MainLoop::executeLog(vector<string> &args) { string MainLoop::executeLog(const vector<string>& args) {
if (args.size() == 1) { if (args.size() == 1) {
ostringstream ret; ostringstream ret;
for (int val = 0; val < lf_COUNT; val++) { for (int val = 0; val < lf_COUNT; val++) {
@@ -1469,7 +1473,7 @@ string MainLoop::executeLog(vector<string> &args) {
return getResultCode(RESULT_ERR_INVALID_ARG); return getResultCode(RESULT_ERR_INVALID_ARG);
} }
string MainLoop::executeRaw(vector<string> &args) { string MainLoop::executeRaw(const vector<string>& args) {
bool bytes = args.size() == 2 && args[1] == "bytes"; bool bytes = args.size() == 2 && args[1] == "bytes";
if (args.size() != 1 && !bytes) { if (args.size() != 1 && !bytes) {
return "usage: raw [bytes]\n" return "usage: raw [bytes]\n"
@@ -1487,7 +1491,7 @@ string MainLoop::executeRaw(vector<string> &args) {
return enabled ? "raw logging enabled" : "raw logging disabled"; return enabled ? "raw logging enabled" : "raw logging disabled";
} }
string MainLoop::executeDump(vector<string> &args) { string MainLoop::executeDump(const vector<string>& args) {
if (args.size() != 1) { if (args.size() != 1) {
return "usage: dump\n" return "usage: dump\n"
" Toggle binary dump of received bytes."; " Toggle binary dump of received bytes.";
@@ -1500,7 +1504,7 @@ string MainLoop::executeDump(vector<string> &args) {
return enabled ? "dump enabled" : "dump disabled"; return enabled ? "dump enabled" : "dump disabled";
} }
string MainLoop::executeReload(vector<string> &args) { string MainLoop::executeReload(const vector<string>& args) {
if (args.size() != 1) { if (args.size() != 1) {
return "usage: reload\n" return "usage: reload\n"
" Reload CSV config files."; " Reload CSV config files.";
@@ -1510,7 +1514,7 @@ string MainLoop::executeReload(vector<string> &args) {
return getResultCode(result); return getResultCode(result);
} }
string MainLoop::executeInfo(vector<string> &args, const string user) { string MainLoop::executeInfo(const vector<string>& args, const string& user) {
if (args.size() == 0) { if (args.size() == 0) {
return "usage: info\n" return "usage: info\n"
" Report information about the daemon, the configuration, and seen devices."; " Report information about the daemon, the configuration, and seen devices.";
@@ -1528,25 +1532,25 @@ string MainLoop::executeInfo(vector<string> &args, const string user) {
result << "access: " << levels << "\n"; result << "access: " << levels << "\n";
} }
if (m_busHandler->hasSignal()) { if (m_busHandler->hasSignal()) {
result << "signal: acquired\n"; result << "signal: acquired\n"
result << "symbol rate: " << m_busHandler->getSymbolRate() << "\n"; << "symbol rate: " << m_busHandler->getSymbolRate() << "\n"
result << "max symbol rate: " << m_busHandler->getMaxSymbolRate() << "\n"; << "max symbol rate: " << m_busHandler->getMaxSymbolRate() << "\n";
} else { } else {
result << "signal: no signal\n"; result << "signal: no signal\n";
} }
result << "reconnects: " << m_reconnectCount << "\n"; result << "reconnects: " << m_reconnectCount << "\n"
result << "masters: " << m_busHandler->getMasterCount() << "\n"; << "masters: " << m_busHandler->getMasterCount() << "\n"
result << "messages: " << m_messages->size() << "\n"; << "messages: " << m_messages->size() << "\n"
result << "conditional: " << m_messages->sizeConditional() << "\n"; << "conditional: " << m_messages->sizeConditional() << "\n"
result << "poll: " << m_messages->sizePoll() << "\n"; << "poll: " << m_messages->sizePoll() << "\n"
result << "update: " << m_messages->sizePassive(); << "update: " << m_messages->sizePassive();
m_busHandler->formatSeenInfo(result); m_busHandler->formatSeenInfo(&result);
return result.str(); return result.str();
} }
string MainLoop::executeQuit(vector<string> &args, bool& connected) { string MainLoop::executeQuit(const vector<string>& args, bool *connected) {
if (args.size() == 1) { if (args.size() == 1) {
connected = false; *connected = false;
return "connection closed"; return "connection closed";
} }
return "usage: quit\n" return "usage: quit\n"
@@ -1579,7 +1583,7 @@ string MainLoop::executeHelp() {
" help|? Print help help [COMMAND], COMMMAND ?"; " help|? Print help help [COMMAND], COMMMAND ?";
} }
string MainLoop::executeGet(vector<string> &args, bool& connected) { string MainLoop::executeGet(const vector<string>& args, bool* connected) {
result_t ret = RESULT_OK; result_t ret = RESULT_OK;
bool numeric = false, valueName = false, required = false, full = false; bool numeric = false, valueName = false, required = false, full = false;
OutputFormat verbosity = OF_NAMES; OutputFormat verbosity = OF_NAMES;
@@ -1616,9 +1620,9 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
qname = token; qname = token;
} }
if (qname == "since") { if (qname == "since") {
since = parseInt(value.c_str(), 10, 0, 0xffffffff, ret); since = parseInt(value.c_str(), 10, 0, 0xffffffff, &ret);
} else if (qname == "poll") { } else if (qname == "poll") {
pollPriority = (size_t)parseInt(value.c_str(), 10, 1, 9, ret); pollPriority = (size_t)parseInt(value.c_str(), 10, 1, 9, &ret);
} else if (qname == "exact") { } else if (qname == "exact") {
exact = value.length() == 0 || value == "1" || value == "true"; exact = value.length() == 0 || value == "1" || value == "true";
} else if (qname == "verbose") { } else if (qname == "verbose") {
@@ -1664,7 +1668,7 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
continue; continue;
} }
if (pollPriority > 0 && message->setPollPriority(pollPriority)) { if (pollPriority > 0 && message->setPollPriority(pollPriority)) {
m_messages->addPollMessage(message); m_messages->addPollMessage(false, message);
} }
time_t lastup = message->getLastUpdateTime(); time_t lastup = message->getLastUpdateTime();
if (lastup == 0 && required) { if (lastup == 0 && required) {
@@ -1691,11 +1695,11 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
lastCircuit = message->getCircuit(); lastCircuit = message->getCircuit();
result << "\n \"" << lastCircuit << "\": {"; result << "\n \"" << lastCircuit << "\": {";
first = true; first = true;
if (full && m_messages->decodeCircuit(lastCircuit, result, verbosity)) { // add circuit specific values if (full && m_messages->decodeCircuit(lastCircuit, verbosity, &result)) { // add circuit specific values
first = false; first = false;
} }
} }
message->decode(result, verbosity, !first); message->decode(!first, NULL, verbosity, &result);
first = false; first = false;
} }
@@ -1727,8 +1731,8 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
result << "\n}"; result << "\n}";
type = 6; type = 6;
} }
connected = false; *connected = false;
return formatHttpResult(ret, result, type); return formatHttpResult(ret, type, result);
} // request for "/data..." } // request for "/data..."
if (uri.length() < 1 || uri[0] != '/' || uri.find("//") != string::npos || uri.find("..") != string::npos) { if (uri.length() < 1 || uri[0] != '/' || uri.find("//") != string::npos || uri.find("..") != string::npos) {
@@ -1770,11 +1774,11 @@ string MainLoop::executeGet(vector<string> &args, bool& connected) {
} }
} }
} }
connected = false; *connected = false;
return formatHttpResult(ret, result, type); return formatHttpResult(ret, type, result);
} }
string MainLoop::formatHttpResult(result_t ret, ostringstream& result, int type) { string MainLoop::formatHttpResult(result_t ret, int type, ostringstream &result) {
string data = ret == RESULT_OK ? result.str() : ""; string data = ret == RESULT_OK ? result.str() : "";
result.str(""); result.str("");
result.clear(); result.clear();
+33 -33
View File
@@ -46,7 +46,7 @@ class UserList : public UserInfo, public MappedFileReader {
* Constructor. * Constructor.
* @param defaultLevels the default access levels. * @param defaultLevels the default access levels.
*/ */
explicit UserList(const string defaultLevels) : MappedFileReader::MappedFileReader(false) { explicit UserList(const string& defaultLevels) : MappedFileReader::MappedFileReader(false) {
if (!defaultLevels.empty()) { if (!defaultLevels.empty()) {
string levels = defaultLevels; string levels = defaultLevels;
transform(levels.begin(), levels.end(), levels.begin(), [](unsigned char c) { transform(levels.begin(), levels.end(), levels.begin(), [](unsigned char c) {
@@ -62,25 +62,25 @@ class UserList : public UserInfo, public MappedFileReader {
virtual ~UserList() {} virtual ~UserList() {}
// @copydoc // @copydoc
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override; result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override;
// @copydoc // @copydoc
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override; vector< map<string, string> >* subRows, string* errorDescription) override;
// @copydoc // @copydoc
bool hasUser(const string user) const override { bool hasUser(const string& user) const override {
return m_userLevels.find(user) != m_userLevels.end(); return m_userLevels.find(user) != m_userLevels.end();
} }
// @copydoc // @copydoc
bool checkSecret(const string user, const string secret) const override { bool checkSecret(const string& user, const string& secret) const override {
auto it = m_userSecrets.find(user); auto it = m_userSecrets.find(user);
return it != m_userSecrets.end() && it->second == secret; return it != m_userSecrets.end() && it->second == secret;
} }
// @copydoc // @copydoc
string getLevels(const string user) const override { string getLevels(const string& user) const override {
auto it = m_userLevels.find(user); auto it = m_userLevels.find(user);
return it == m_userLevels.end() ? "" : it->second; return it == m_userLevels.end() ? "" : it->second;
} }
@@ -105,7 +105,7 @@ class MainLoop : public Thread, DeviceListener {
* @param device the @a Device instance. * @param device the @a Device instance.
* @param messages the @a MessageMap instance. * @param messages the @a MessageMap instance.
*/ */
MainLoop(const struct options opt, Device *device, MessageMap* messages); MainLoop(const struct options& opt, Device *device, MessageMap* messages);
/** /**
* Destructor. * Destructor.
@@ -130,7 +130,7 @@ class MainLoop : public Thread, DeviceListener {
void addMessage(NetMessage* message) { m_netQueue.push(message); } void addMessage(NetMessage* message) { m_netQueue.push(message); }
// @copydoc // @copydoc
void notifyDeviceData(const symbol_t symbol, bool received) override; void notifyDeviceData(symbol_t symbol, bool received) override;
protected: protected:
@@ -149,26 +149,26 @@ class MainLoop : public Thread, DeviceListener {
* @param reload set to true when the configuration files were reloaded. * @param reload set to true when the configuration files were reloaded.
* @return result string to send back to the client. * @return result string to send back to the client.
*/ */
string decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, string decodeMessage(const string& data, bool isHttp, bool* connected, bool* listening,
string& user, bool& reload); string* user, bool* reload);
/** /**
* Parse the hex master message from the remaining arguments. * Parse the hex master message from the remaining arguments.
* @param args the arguments passed to the command. * @param args the arguments passed to the command.
* @param argPos the index of the first argument to parse. * @param argPos the index of the first argument to parse.
* @param master the @a MasterSymbolString to write the data to.
* @param srcAddress the source address to set, or @a SYN for the own master address. * @param srcAddress the source address to set, or @a SYN for the own master address.
* @param master the @a MasterSymbolString to write the data to.
* @return the result from parsing the arguments. * @return the result from parsing the arguments.
*/ */
result_t parseHexMaster(vector<string> &args, size_t argPos, MasterSymbolString& master, result_t parseHexMaster(const vector<string>& args, size_t argPos, symbol_t srcAddress,
symbol_t srcAddress = SYN); MasterSymbolString* master);
/** /**
* Get the access levels associated with the specified user name. * Get the access levels associated with the specified user name.
* @param user the user name, or empty for default levels. * @param user the user name, or empty for default levels.
* @return the access levels separated by semicolon. * @return the access levels separated by semicolon.
*/ */
string getUserLevels(const string user) { return m_userList.getLevels(user); } string getUserLevels(const string& user) { return m_userList.getLevels(user); }
/** /**
* Execute the auth command. * Execute the auth command.
@@ -176,7 +176,7 @@ class MainLoop : public Thread, DeviceListener {
* @param user the current user name to set to the new user name on success. * @param user the current user name to set to the new user name on success.
* @return the result string. * @return the result string.
*/ */
string executeAuth(vector<string> &args, string &user); string executeAuth(const vector<string>& args, string *user);
/** /**
* Execute the read command. * Execute the read command.
@@ -184,7 +184,7 @@ class MainLoop : public Thread, DeviceListener {
* @param levels the current user's access levels. * @param levels the current user's access levels.
* @return the result string. * @return the result string.
*/ */
string executeRead(vector<string> &args, const string levels); string executeRead(const vector<string>& args, const string& levels);
/** /**
* Execute the write command. * Execute the write command.
@@ -192,14 +192,14 @@ class MainLoop : public Thread, DeviceListener {
* @param levels the current user's access levels. * @param levels the current user's access levels.
* @return the result string. * @return the result string.
*/ */
string executeWrite(vector<string> &args, const string levels); string executeWrite(const vector<string>& args, const string levels);
/** /**
* Execute the hex command. * Execute the hex command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeHex(vector<string> &args); string executeHex(const vector<string>& args);
/** /**
* Execute the find command. * Execute the find command.
@@ -207,7 +207,7 @@ class MainLoop : public Thread, DeviceListener {
* @param levels the current user's access levels. * @param levels the current user's access levels.
* @return the result string. * @return the result string.
*/ */
string executeFind(vector<string> &args, string levels); string executeFind(const vector<string>& args, const string& levels);
/** /**
* Execute the listen command. * Execute the listen command.
@@ -215,21 +215,21 @@ class MainLoop : public Thread, DeviceListener {
* @param listening set to true when the client is in listening mode. * @param listening set to true when the client is in listening mode.
* @return the result string. * @return the result string.
*/ */
string executeListen(vector<string> &args, bool& listening); string executeListen(const vector<string>& args, bool* listening);
/** /**
* Execute the state command. * Execute the state command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeState(vector<string> &args); string executeState(const vector<string>& args);
/** /**
* Execute the grab command. * Execute the grab command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeGrab(vector<string> &args); string executeGrab(const vector<string>& args);
/** /**
* Execute the scan command. * Execute the scan command.
@@ -237,35 +237,35 @@ class MainLoop : public Thread, DeviceListener {
* @param levels the current user's access levels. * @param levels the current user's access levels.
* @return the result string. * @return the result string.
*/ */
string executeScan(vector<string> &args, const string levels); string executeScan(const vector<string>& args, const string levels);
/** /**
* Execute the log command. * Execute the log command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeLog(vector<string> &args); string executeLog(const vector<string>& args);
/** /**
* Execute the raw command. * Execute the raw command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeRaw(vector<string> &args); string executeRaw(const vector<string>& args);
/** /**
* Execute the dump command. * Execute the dump command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeDump(vector<string> &args); string executeDump(const vector<string>& args);
/** /**
* Execute the reload command. * Execute the reload command.
* @param args the arguments passed to the command (starting with the command itself), or empty for help. * @param args the arguments passed to the command (starting with the command itself), or empty for help.
* @return the result string. * @return the result string.
*/ */
string executeReload(vector<string> &args); string executeReload(const vector<string>& args);
/** /**
* Execute the info command. * Execute the info command.
@@ -273,7 +273,7 @@ class MainLoop : public Thread, DeviceListener {
* @param user the current user name. * @param user the current user name.
* @return the result string. * @return the result string.
*/ */
string executeInfo(vector<string> &args, const string user); string executeInfo(const vector<string>& args, const string& user);
/** /**
* Execute the quit command. * Execute the quit command.
@@ -281,7 +281,7 @@ class MainLoop : public Thread, DeviceListener {
* @param connected set to false when the client connection shall be closed. * @param connected set to false when the client connection shall be closed.
* @return the result string. * @return the result string.
*/ */
string executeQuit(vector<string> &args, bool& connected); string executeQuit(const vector<string>& args, bool *connected);
/** /**
* Execute the help command. * Execute the help command.
@@ -295,16 +295,16 @@ class MainLoop : public Thread, DeviceListener {
* @param connected set to false when the client connection shall be closed. * @param connected set to false when the client connection shall be closed.
* @return the result string. * @return the result string.
*/ */
string executeGet(vector<string> &args, bool& connected); string executeGet(const vector<string>& args, bool* connected);
/** /**
* Format the HTTP answer to the result string. * Format the HTTP answer to the result string.
* @param ret the result code of handling the request. * @param ret the result code of handling the request.
* @param result the @a ostringstream containing the successful result.
* @param type the content type. * @param type the content type.
* @param result the @a ostringstream containing the successful result.
* @return the result string. * @return the result string.
*/ */
string formatHttpResult(result_t ret, ostringstream& result, int type); string formatHttpResult(result_t ret, int type, ostringstream &result);
/** the @a Device instance. */ /** the @a Device instance. */
Device* m_device; Device* m_device;
+18 -18
View File
@@ -81,7 +81,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
break; break;
case 2: // --mqttport=1883 case 2: // --mqttport=1883
g_port = (uint16_t)parseInt(arg, 10, 1, 65535, result); g_port = (uint16_t)parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid mqttport"); argp_error(state, "invalid mqttport");
return EINVAL; return EINVAL;
@@ -187,7 +187,7 @@ static const size_t knownFieldCount = sizeof(knownFieldNames) / sizeof(char*);
* @param fields the @a vector to which the field parts shall be added. * @param fields the @a vector to which the field parts shall be added.
* @return true on success, false on malformed topic template. * @return true on success, false on malformed topic template.
*/ */
bool parseTopic(const string topic, vector<string> &strs, vector<string> &fields) { bool parseTopic(const string& topic, vector<string>* strs, vector<string>* fields) {
size_t lastpos = 0; size_t lastpos = 0;
size_t end = topic.length(); size_t end = topic.length();
vector<string> columns; vector<string> columns;
@@ -205,18 +205,18 @@ bool parseTopic(const string topic, vector<string> &strs, vector<string> &fields
return false; return false;
} }
string fieldName = knownFieldNames[idx]; string fieldName = knownFieldNames[idx];
for (const auto& it : fields) { for (const auto& it : *fields) {
if (it == fieldName) { if (it == fieldName) {
return false; // duplicate column return false; // duplicate column
} }
} }
strs.push_back(topic.substr(lastpos, pos-lastpos)); strs->push_back(topic.substr(lastpos, pos-lastpos));
fields.push_back(fieldName); fields->push_back(fieldName);
lastpos = pos+1+len; lastpos = pos+1+len;
pos = topic.find('%', lastpos); pos = topic.find('%', lastpos);
} }
if (lastpos < end) { if (lastpos < end) {
strs.push_back(topic.substr(lastpos, end-lastpos)); strs->push_back(topic.substr(lastpos, end-lastpos));
} }
return true; return true;
} }
@@ -259,7 +259,7 @@ MqttHandler::MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap*
bool enabled = g_port != 0; bool enabled = g_port != 0;
m_publishByField = false; m_publishByField = false;
m_mosquitto = NULL; m_mosquitto = NULL;
if (enabled && !parseTopic(g_topic, m_topicStrs, m_topicFields)) { if (enabled && !parseTopic(g_topic, &m_topicStrs, &m_topicFields)) {
logOtherError("mqtt", "malformed topic %s", g_topic); logOtherError("mqtt", "malformed topic %s", g_topic);
return; return;
} }
@@ -386,7 +386,7 @@ void on_message(
handler->notifyTopic(topic, data); handler->notifyTopic(topic, data);
} }
void MqttHandler::notifyTopic(string topic, string data) { void MqttHandler::notifyTopic(const string& topic, const string& data) {
size_t pos = topic.rfind('/'); size_t pos = topic.rfind('/');
if (pos == string::npos) { if (pos == string::npos) {
return; return;
@@ -466,10 +466,10 @@ void MqttHandler::notifyTopic(string topic, string data) {
logOtherNotice("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), data.c_str()); logOtherNotice("mqtt", "%s %s %s: %s", isWrite?"write":"read", circuit.c_str(), name.c_str(), data.c_str());
} }
ostringstream ostream; ostringstream ostream;
publishMessage(message, ostream); publishMessage(message, &ostream);
} }
void MqttHandler::notifyUpdateCheckResult(string checkResult) { void MqttHandler::notifyUpdateCheckResult(const string& checkResult) {
if (checkResult != m_lastUpdateCheckResult) { if (checkResult != m_lastUpdateCheckResult) {
m_lastUpdateCheckResult = checkResult; m_lastUpdateCheckResult = checkResult;
publishTopic(m_globalTopic+"updatecheck", checkResult.empty() ? "OK" : checkResult); publishTopic(m_globalTopic+"updatecheck", checkResult.empty() ? "OK" : checkResult);
@@ -525,7 +525,7 @@ void MqttHandler::run() {
updates.str(""); updates.str("");
updates.clear(); updates.clear();
updates << dec; updates << dec;
publishMessage(it.first, updates); publishMessage(it.first, &updates);
} }
} }
m_updatedMessages.clear(); m_updatedMessages.clear();
@@ -557,7 +557,7 @@ void MqttHandler::handleTraffic() {
} }
} }
string MqttHandler::getTopic(Message* message, ssize_t fieldIndex) { string MqttHandler::getTopic(const Message* message, ssize_t fieldIndex) {
ostringstream ret; ostringstream ret;
for (size_t i = 0; i < m_topicStrs.size(); i++) { for (size_t i = 0; i < m_topicStrs.size(); i++) {
ret << m_topicStrs[i]; ret << m_topicStrs[i];
@@ -568,15 +568,15 @@ string MqttHandler::getTopic(Message* message, ssize_t fieldIndex) {
if (m_topicFields[i] == "fields" && fieldIndex >= 0) { if (m_topicFields[i] == "fields" && fieldIndex >= 0) {
ret << message->getFieldName(fieldIndex); // TODO skip ignored fields ret << message->getFieldName(fieldIndex); // TODO skip ignored fields
} else { } else {
message->dumpField(ret, m_topicFields[i]); message->dumpField(m_topicFields[i], false, &ret);
} }
} }
} }
return ret.str(); return ret.str();
} }
void MqttHandler::publishMessage(Message* message, ostringstream& updates) { void MqttHandler::publishMessage(const Message* message, ostringstream* updates) {
result_t result = message->decodeLastData(updates); result_t result = message->decodeLastData(false, NULL, -1, 0, updates);
if (result != RESULT_OK) { if (result != RESULT_OK) {
logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(),
getResultCode(result)); getResultCode(result));
@@ -584,7 +584,7 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
} }
if (m_publishByField) { if (m_publishByField) {
ssize_t index = 0; ssize_t index = 0;
istringstream input(updates.str()); istringstream input(updates->str());
string token; string token;
while (getline(input, token, UI_FIELD_SEPARATOR)) { while (getline(input, token, UI_FIELD_SEPARATOR)) {
string topic = getTopic(message, index); string topic = getTopic(message, index);
@@ -592,11 +592,11 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) {
index++; index++;
} }
} else { } else {
publishTopic(getTopic(message), updates.str()); publishTopic(getTopic(message), updates->str());
} }
} }
void MqttHandler::publishTopic(string topic, string data, bool retain) { void MqttHandler::publishTopic(const string& topic, const string& data, bool retain) {
logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str()); logOtherDebug("mqtt", "publish %s %s", topic.c_str(), data.c_str());
mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(),
reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain); reinterpret_cast<const uint8_t*>(data.c_str()), 0, retain);
+5 -5
View File
@@ -78,10 +78,10 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
* @param topic the topic string. * @param topic the topic string.
* @param data the data string. * @param data the data string.
*/ */
void notifyTopic(string topic, string data); void notifyTopic(const string& topic, const string& data);
// @copydoc // @copydoc
void notifyUpdateCheckResult(string checkResult) override; void notifyUpdateCheckResult(const string& checkResult) override;
protected: protected:
// @copydoc // @copydoc
@@ -100,14 +100,14 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
* @param fieldIndex the optional field index for the field column, or -1. * @param fieldIndex the optional field index for the field column, or -1.
* @return the topic string. * @return the topic string.
*/ */
string getTopic(Message* message, ssize_t fieldIndex = -1); string getTopic(const Message* message, ssize_t fieldIndex = -1);
/** /**
* Prepare a @a Message and publish as topic. * Prepare a @a Message and publish as topic.
* @param message the @a Message to publish. * @param message the @a Message to publish.
* @param updates the @a ostringstream for preparation. * @param updates the @a ostringstream for preparation.
*/ */
void publishMessage(Message* message, ostringstream& updates); void publishMessage(const Message* message, ostringstream* updates);
/** /**
* Publish a topic update to MQTT. * Publish a topic update to MQTT.
@@ -115,7 +115,7 @@ class MqttHandler : public DataSink, public DataSource, public Thread {
* @param data the data string. * @param data the data string.
* @param retain whether the topic shall be retained. * @param retain whether the topic shall be retained.
*/ */
void publishTopic(string topic, string data, bool retain = true); void publishTopic(const string& topic, const string& data, bool retain = true);
/** the @a MessageMap instance. */ /** the @a MessageMap instance. */
MessageMap* m_messages; MessageMap* m_messages;
+34
View File
@@ -35,6 +35,40 @@ int Connection::m_ids = 0;
#define POLLRDHUP 0 #define POLLRDHUP 0
#endif #endif
bool NetMessage::add(const char* request) {
if (request && request[0]) {
string add = request;
add.erase(remove(add.begin(), add.end(), '\r'), add.end());
m_request.append(add);
}
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
if (pos != string::npos) {
if (m_isHttp) {
pos = m_request.find("\n");
m_request.resize(pos); // reduce to first line
// typical first line: GET /ehp/outsidetemp HTTP/1.1
pos = m_request.rfind(" HTTP/");
if (pos != string::npos) {
m_request.resize(pos); // remove "HTTP/x.x" suffix
}
pos = 0;
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
unsigned int value1, value2;
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2) < 2) {
break;
}
m_request[pos] = static_cast<char>(((value1&0x0f) << 4) | (value2&0x0f));
m_request.erase(pos+1, 2);
}
} else if (pos+1 == m_request.length()) {
m_request.resize(pos); // reduce to complete lines
}
return true;
}
return m_request.length() == 0 && m_listening;
}
void Connection::run() { void Connection::run() {
int ret; int ret;
struct timespec tdiff; struct timespec tdiff;
+1 -31
View File
@@ -76,37 +76,7 @@ class NetMessage {
* @param request the request data from the client. * @param request the request data from the client.
* @return true when the request is complete and the response shall be prepared. * @return true when the request is complete and the response shall be prepared.
*/ */
bool add(string request) { bool add(const char* request);
if (request.length() > 0) {
request.erase(remove(request.begin(), request.end(), '\r'), request.end());
m_request.append(request);
}
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
if (pos != string::npos) {
if (m_isHttp) {
pos = m_request.find("\n");
m_request.resize(pos); // reduce to first line
// typical first line: GET /ehp/outsidetemp HTTP/1.1
pos = m_request.rfind(" HTTP/");
if (pos != string::npos) {
m_request.resize(pos); // remove "HTTP/x.x" suffix
}
pos = 0;
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
unsigned int value1, value2;
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2) < 2) {
break;
}
m_request[pos] = static_cast<char>(((value1&0x0f) << 4) | (value2&0x0f));
m_request.erase(pos+1, 2);
}
} else if (pos+1 == m_request.length()) {
m_request.resize(pos); // reduce to complete lines
}
return true;
}
return m_request.length() == 0 && m_listening;
}
/** /**
* Return whether this is a HTTP message. * Return whether this is a HTTP message.
+19 -22
View File
@@ -39,7 +39,7 @@ void contrib_tem_register() {
DataTypeList::getInstance()->add(new TemParamDataType("TEM_P")); DataTypeList::getInstance()->add(new TemParamDataType("TEM_P"));
} }
result_t TemParamDataType::derive(int divisor, size_t bitCount, const NumberDataType* &derived) const { result_t TemParamDataType::derive(int divisor, size_t bitCount, const NumberDataType** derived) const {
if (divisor == 0) { if (divisor == 0) {
divisor = 1; divisor = 1;
} }
@@ -47,27 +47,26 @@ result_t TemParamDataType::derive(int divisor, size_t bitCount, const NumberData
bitCount = m_bitCount; bitCount = m_bitCount;
} }
if (divisor == 1 && bitCount == 16) { if (divisor == 1 && bitCount == 16) {
derived = this; *derived = this;
return RESULT_OK; return RESULT_OK;
} }
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
result_t TemParamDataType::readSymbols(const SymbolString& input, result_t TemParamDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const {
ostringstream& output, OutputFormat outputFormat) const {
unsigned int value = 0; unsigned int value = 0;
result_t result = readRawValue(input, offset, length, value); result_t result = readRawValue(offset, length, input, &value);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
if (value == m_replacement) { if (value == m_replacement) {
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << "null"; *output << "null";
} else { } else {
output << NULL_VALUE; *output << NULL_VALUE;
} }
return RESULT_OK; return RESULT_OK;
} }
@@ -80,31 +79,29 @@ result_t TemParamDataType::readSymbols(const SymbolString& input,
num = (value & 0x7f); // num in bits 0...6 num = (value & 0x7f); // num in bits 0...6
} }
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
output << setfill('0') << setw(2) << dec << static_cast<int>(grp) << '-' << setw(3) << static_cast<int>(num); *output << setfill('0') << setw(2) << dec << static_cast<int>(grp) << '-' << setw(3) << static_cast<int>(num);
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
output << setfill(' ') << setw(0); // reset *output << setfill(' ') << setw(0); // reset
return RESULT_OK; return RESULT_OK;
} }
result_t TemParamDataType::writeSymbols(istringstream& input, result_t TemParamDataType::writeSymbols(const size_t offset, const size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const {
SymbolString& output, size_t* usedLength) const {
unsigned int value; unsigned int value;
int grp, num; int grp, num;
string token;
const char* str = input.str().c_str(); if (input->str() == NULL_VALUE) {
if (strcmp(str, NULL_VALUE) == 0) {
value = m_replacement; // replacement value value = m_replacement; // replacement value
} else { } else {
if (input.eof() || !getline(input, token, '-')) { string token;
if (input->eof() || !getline(*input, token, '-')) {
return RESULT_ERR_EOF; // incomplete return RESULT_ERR_EOF; // incomplete
} }
str = token.c_str(); const char* str = token.c_str();
if (str == NULL || *str == 0) { if (str == NULL || *str == 0) {
return RESULT_ERR_EOF; // input too short return RESULT_ERR_EOF; // input too short
} }
@@ -113,7 +110,7 @@ result_t TemParamDataType::writeSymbols(istringstream& input,
if (strEnd == NULL || strEnd == str || *strEnd != 0) { if (strEnd == NULL || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value return RESULT_ERR_INVALID_NUM; // invalid value
} }
if (input.eof() || !getline(input, token, '-')) { if (input->eof() || !getline(*input, token, '-')) {
return RESULT_ERR_EOF; // incomplete return RESULT_ERR_EOF; // incomplete
} }
str = token.c_str(); str = token.c_str();
@@ -128,7 +125,7 @@ result_t TemParamDataType::writeSymbols(istringstream& input,
if (grp < 0 || grp > 0x1f || num < 0 || num > 0x7f) { if (grp < 0 || grp > 0x1f || num < 0 || num > 0x7f) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
if (output.isMaster()) { if (output->isMaster()) {
value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13 value = grp | (num << 8); // grp in bits 0...5, num in bits 8...13
} else { } else {
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6 value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
+6 -8
View File
@@ -46,21 +46,19 @@ class TemParamDataType : public NumberDataType {
* Constructs a new instance. * Constructs a new instance.
* @param id the type identifier. * @param id the type identifier.
*/ */
explicit TemParamDataType(const string id) explicit TemParamDataType(const string& id)
: NumberDataType(id, 16, 0, 0xffff, 0, 0xffff, 0, NULL) {} : NumberDataType(id, 16, 0, 0xffff, 0, 0xffff, 0, NULL) {}
// @copydoc // @copydoc
result_t derive(int divisor, size_t bitCount, const NumberDataType* &derived) const override; result_t derive(int divisor, size_t bitCount, const NumberDataType** derived) const override;
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, result_t readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, const OutputFormat outputFormat, ostream* output) const override;
ostringstream& output, OutputFormat outputFormat) const override;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, result_t writeSymbols(size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const override;
SymbolString& output, size_t* usedLength) const override;
}; };
/** /**
+28 -28
View File
@@ -54,31 +54,31 @@ class TestReader : public MappedFileReader {
TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest) TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest)
: MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest), : MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest),
m_fields(NULL) {} m_fields(NULL) {}
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override { result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override {
if (row.empty()) { if (row->empty()) {
row.push_back("*name"); row->push_back("*name");
row.push_back("part"); row->push_back("part");
row.push_back("type"); row->push_back("type");
row.push_back("divisor/values"); row->push_back("divisor/values");
row.push_back("unit"); row->push_back("unit");
row.push_back("comment"); row->push_back("comment");
return RESULT_OK; return RESULT_OK;
} }
if (row[0][0] != '*') { if ((*row)[0][0] != '*') {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
return RESULT_OK; // leave it to DataField::create return RESULT_OK; // leave it to DataField::create
} }
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override { vector< map<string, string> >* subRows, string* errorDescription) override {
if (!row.empty() || subRows.empty()) { if (!row->empty() || subRows->empty()) {
cout << "read line " << static_cast<unsigned>(lineNo) << ": read error: got " cout << "read line " << static_cast<unsigned>(lineNo) << ": read error: got "
<< static_cast<unsigned>(row.size()) << "/0 main, " << static_cast<unsigned>(subRows.size()) << static_cast<unsigned>(row->size()) << "/0 main, " << static_cast<unsigned>(subRows->size())
<< "/>=3 sub" << endl; << "/>=3 sub" << endl;
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
} }
cout << "read line " << static_cast<unsigned>(lineNo) << ": read OK" << endl; cout << "read line " << static_cast<unsigned>(lineNo) << ": read OK" << endl;
return DataField::create(subRows, errorDescription, m_templates, m_fields, m_isSet, false, m_isMasterDest); return DataField::create(m_isSet, false, m_isMasterDest, MAX_POS, m_templates, subRows, errorDescription, &m_fields);
} }
private: private:
DataFieldTemplates* m_templates; DataFieldTemplates* m_templates;
@@ -118,7 +118,7 @@ int main() {
istringstream dummystr("#"); istringstream dummystr("#");
string errorDescription; string errorDescription;
vector<string> row; vector<string> row;
templates->readLineFromStream(dummystr, errorDescription, "inline", lineNo, row); templates->readLineFromStream("inline", false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
const DataField* fields = NULL; const DataField* fields = NULL;
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
string check[5] = checks[i]; string check[5] = checks[i];
@@ -156,7 +156,7 @@ int main() {
lineNo = 0; lineNo = 0;
dummystr.clear(); dummystr.clear();
dummystr.str("#"); dummystr.str("#");
result = reader.readLineFromStream(dummystr, errorDescription, "inline", lineNo, row); result = reader.readLineFromStream("inline", false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription
<< endl; << endl;
@@ -164,7 +164,7 @@ int main() {
continue; continue;
} }
lineNo = baseLine + i; lineNo = baseLine + i;
result = reader.readLineFromStream(isstr, errorDescription, "", lineNo, row); result = reader.readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
fields = reader.m_fields; fields = reader.m_fields;
if (result != RESULT_OK) { if (result != RESULT_OK) {
@@ -178,7 +178,7 @@ int main() {
continue; continue;
} }
cout << "\"" << check[0] << "\"=\""; cout << "\"" << check[0] << "\"=\"";
fields->dump(cout); fields->dump(&cout);
cout << "\": create OK" << endl; cout << "\": create OK" << endl;
ostringstream output; ostringstream output;
@@ -194,21 +194,21 @@ int main() {
cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl;
error = true; error = true;
} }
result = fields->read(mstr, 0, output, 0, -1, false); result = fields->read(mstr, 0, false, NULL, -1, 0, -1, &output);
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->read(sstr, 0, output, 0, -1, !output.str().empty()); result = fields->read(sstr, 0, !output.str().empty(), NULL, -1, 0, -1, &output);
} }
if (failedRead) { if (failedRead) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else { } else {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< OK" << endl; << "< OK" << endl;
} }
} else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
@@ -217,21 +217,21 @@ int main() {
} }
istringstream input(expectStr); istringstream input(expectStr);
result = fields->write(input, writeMstr, 0); result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeMstr, NULL);
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->write(input, writeSstr, 0); result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeSstr, NULL);
} }
if (failedWrite) { if (failedWrite) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< error: unexpectedly succeeded" << endl; << expectStr << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else { } else {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< OK" << endl; << expectStr << "< OK" << endl;
} }
} else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " write " << fields->getName() << " >" << expectStr cout << " write " << fields->getName(-1) << " >" << expectStr
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
+244 -262
View File
File diff suppressed because it is too large Load Diff
+126 -124
View File
@@ -56,7 +56,7 @@ namespace ebusd {
* @param supportsLanguage set to true when the field supports multiple language. * @param supportsLanguage set to true when the field supports multiple language.
* @return the normalized data field name, or empty if unknown. * @return the normalized data field name, or empty if unknown.
*/ */
string getDataFieldName(const string name, bool& supportsLanguage); string getDataFieldName(const string& name, bool* supportsLanguage);
class DataFieldTemplates; class DataFieldTemplates;
class SingleDataField; class SingleDataField;
@@ -71,14 +71,14 @@ class AttributedItem {
* @param name the item name. * @param name the item name.
* @param attributes the additional named attributes. * @param attributes the additional named attributes.
*/ */
AttributedItem(const string name, const map<string, string>& attributes) AttributedItem(const string& name, const map<string, string>& attributes)
: m_name(name), m_attributes(attributes) {} : m_name(name), m_attributes(attributes) {}
/** /**
* Constructs a new instance (without additional attributes). * Constructs a new instance (without additional attributes).
* @param name the field name. * @param name the field name.
*/ */
explicit AttributedItem(const string name) explicit AttributedItem(const string& name)
: m_name(name) {} : m_name(name) {}
/** /**
@@ -92,69 +92,69 @@ class AttributedItem {
* @param value the int value. * @param value the int value.
* @return the formatted string. * @return the formatted string.
*/ */
static const string formatInt(size_t value); static string formatInt(size_t value);
/** /**
* Remove and return a certain value from a map. * Remove and return a certain value from a map.
* @param row the map to remove the value from.
* @param key the name of the value to remove. * @param key the name of the value to remove.
* @param row the map to remove the value from.
* @return the named value from the map, or empty if not available. * @return the named value from the map, or empty if not available.
*/ */
static const string pluck(map<string, string>& row, const string key); static string pluck(const string& key, map<string, string>* row);
/** /**
* Dump the @a string optionally embedded in @a TEXT_SEPARATOR to the output. * Dump the @a string optionally embedded in @a TEXT_SEPARATOR to the output.
* @param output the @a ostream to dump to.
* @param str the @a string to dump.
* @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR.
* @param str the @a string to dump.
* @param output the @a ostream to dump to.
*/ */
static void dumpString(ostream& output, const string str, const bool prependFieldSeparator = true); static void dumpString(bool prependFieldSeparator, const string& str, ostream* output);
/** /**
* Append a named attribute as JSON to the output. * Append a named attribute as JSON to the output.
* @param output the @a ostream to append to. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR.
* @param name the name of the attribute. * @param name the name of the attribute.
* @param value the value of the attribute. * @param value the value of the attribute.
* @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR.
* @param asString true to force writing as string, false to detect the type from the value. * @param asString true to force writing as string, false to detect the type from the value.
* @param output the @a ostream to append to.
*/ */
static void appendJson(ostream& output, const string name, const string value, static void appendJson(bool prependFieldSeparator, const string& name, const string& value,
const bool prependFieldSeparator = true, bool asString = false); bool asString, ostream* output);
/** /**
* Merge this instance's additional named attributes into the specified attributes. * Merge this instance's additional named attributes into the specified attributes.
* @param attributes the additional named attributes to merge in this instance's additional named attributes. * @param attributes the additional named attributes to merge in this instance's additional named attributes.
*/ */
void mergeAttributes(map<string, string>& attributes) const; void mergeAttributes(map<string, string>* attributes) const;
/** /**
* Dump the attribute optionally embedded in @a TEXT_SEPARATOR to the output. * Dump the attribute optionally embedded in @a TEXT_SEPARATOR to the output.
* @param output the @a ostream to dump to.
* @param name the name of the attribute to dump.
* @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR. * @param prependFieldSeparator whether to start with a @a FIELD_SEPARATOR.
* @param name the name of the attribute to dump.
* @param output the @a ostream to dump to.
*/ */
void dumpAttribute(ostream& output, const string name, const bool prependFieldSeparator = true) const; void dumpAttribute(bool prependFieldSeparator, const string& name, ostream* output) const;
/** /**
* Append the attribute value to the output. * Append the attribute value to the output.
* @param output the @a ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param name the name of the attribute to append. * @param name the name of the attribute to append.
* @param onlyIfNonEmpty true to append only if the value is not empty. * @param onlyIfNonEmpty true to append only if the value is not empty.
* @param prefix optional prefix to use (only for non-JSON output). * @param prefix optional prefix to use (only for non-JSON output).
* @param suffix optional suffix to use (only for non-JSON output). * @param suffix optional suffix to use (only for non-JSON output).
* @param output the @a ostream to append the formatted value to.
* @return true if data was added, false otherwise. * @return true if data was added, false otherwise.
*/ */
bool appendAttribute(ostringstream& output, OutputFormat outputFormat, const string name, bool appendAttribute(OutputFormat outputFormat, const string& name, bool onlyIfNonEmpty,
const bool onlyIfNonEmpty = true, const string prefix = "", const string suffix = "") const; const string& prefix, const string& suffix, ostream* output) const;
/** /**
* Append the attributes to the output. * Append the attributes to the output.
* @param output the @a ostringstream to append the formatted values to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param output the @a ostream to append the formatted values to.
* @return true if data was added, false otherwise. * @return true if data was added, false otherwise.
*/ */
bool appendAttributes(ostringstream& output, OutputFormat outputFormat) const; bool appendAttributes(OutputFormat outputFormat, ostream* output) const;
/** /**
* Get the item name. * Get the item name.
@@ -167,7 +167,7 @@ class AttributedItem {
* @param name the name of the attribute. * @param name the name of the attribute.
* @return the named attribute value, or empty. * @return the named attribute value, or empty.
*/ */
string getAttribute(const string name) const; string getAttribute(const string& name) const;
protected: protected:
@@ -178,6 +178,7 @@ class AttributedItem {
const map<string, string> m_attributes; const map<string, string> m_attributes;
}; };
/** /**
* Base class for all kinds of data fields. * Base class for all kinds of data fields.
*/ */
@@ -188,14 +189,14 @@ class DataField : public AttributedItem {
* @param name the field name. * @param name the field name.
* @param attributes the additional named attributes. * @param attributes the additional named attributes.
*/ */
DataField(const string name, const map<string, string>& attributes) DataField(const string& name, const map<string, string>& attributes)
: AttributedItem(name, attributes) {} : AttributedItem(name, attributes) {}
/** /**
* Constructs a new instance (without additional attributes). * Constructs a new instance (without additional attributes).
* @param name the field name. * @param name the field name.
*/ */
explicit DataField(const string name) explicit DataField(const string& name)
: AttributedItem(name) {} : AttributedItem(name) {}
/** /**
@@ -211,63 +212,62 @@ class DataField : public AttributedItem {
/** /**
* Factory method for creating new instances. * Factory method for creating new instances.
* @param rows the mapped field definition rows.
* @param errorDescription a string in which to store the error description in case of error.
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param returnField the variable in which to store the created instance.
* @param isWriteMessage whether the field is part of a write message (default false). * @param isWriteMessage whether the field is part of a write message (default false).
* @param isTemplate true for creating a template @a DataField. * @param isTemplate true for creating a template @a DataField.
* @param isBroadcastOrMasterDestination true if the destination bus address is @a BRODCAST or a master address. * @param isBroadcastOrMasterDestination true if the destination bus address is @a BRODCAST or a master address.
* @param maxFieldLength the maximum allowed length of a single field (default @a MAX_POS). * @param maxFieldLength the maximum allowed length of a single field (e.g. @a MAX_POS).
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param rows the mapped field definition rows (may be modified).
* @param errorDescription a string in which to store the error description in case of error.
* @param returnField 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.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static result_t create(vector< map<string, string> >& rows, string& errorDescription, static result_t create(bool isWriteMessage, bool isTemplate, bool isBroadcastOrMasterDestination,
DataFieldTemplates* templates, const DataField*& returnField, size_t maxFieldLength, const DataFieldTemplates* templates, vector< map<string, string> >* rows,
const bool isWriteMessage, string* errorDescription, const DataField** returnField);
const bool isTemplate, const bool isBroadcastOrMasterDestination,
const size_t maxFieldLength = MAX_POS);
/** /**
* Return the name of the specified day. * Return the name of the specified day.
* @param day the day (between 0 and 6). * @param day the day (between 0 and 6).
* @return the name of the specified day. * @return the name of the specified day.
*/ */
static string getDayName(int day); static const char* getDayName(int day);
/** /**
* Returns the length of this field (or contained fields) in bytes. * Returns the length of this field (or contained fields) in bytes.
* @param partType the message part of the contained fields to limit the length calculation to. * @param partType the message part of the contained fields to limit the length calculation to.
* @param maxLength the maximum length for calculating remainder of input. * @param maxLength the maximum length for calculating remainder of input (e.g. @a MAX_LEN).
* @return the length of this field (or contained fields) in bytes. * @return the length of this field (or contained fields) in bytes.
*/ */
virtual size_t getLength(PartType partType, size_t maxLength = MAX_LEN) const = 0; virtual size_t getLength(PartType partType, size_t maxLength) const = 0;
/** /**
* Derive a new @a DataField from this field. * Derive a new @a DataField from this field.
* @param name the field name, or empty to use this fields name. * @param name the field name, or empty to use this fields name.
* @param attributes the additional named attributes to override.
* @param partType the message part in which the field is stored. * @param partType the message part in which the field is stored.
* @param divisor the extra divisor (negative for reciprocal) to apply on the value, or 1 for none (if applicable). * @param divisor the extra divisor (negative for reciprocal) to apply on the value, or 1 for none (if applicable).
* @param attributes the additional named attributes to override (may be modified).
* @param values the value=text assignments, or empty to use this fields assignments (if applicable). * @param values the value=text assignments, or empty to use this fields assignments (if applicable).
* @param fields the @a vector to which created @a SingleDataField instances shall be added. * @param fields the @a vector to which created @a SingleDataField instances shall be added.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t derive(const string name, map<string, string> attributes, const PartType partType, virtual result_t derive(const string& name, PartType partType, int divisor,
int divisor, map<unsigned int, string> values, vector<const SingleDataField*>& fields) const = 0; const map<unsigned int, string>& values, map<string, string>* attributes,
vector<const SingleDataField*>* fields) const = 0;
/** /**
* Get the specified field name. * Get the specified field name.
* @param fieldIndex the index of the field, or -1 for this. * @param fieldIndex the index of the field, or -1 for this.
* @return the field name, or the index as string if not unique or not available. * @return the field name, or the index as string if not unique or not available.
*/ */
virtual string getName(const ssize_t fieldIndex = -1) const { return m_name; } virtual string getName(ssize_t fieldIndex) const { return m_name; }
/** /**
* Dump the field settings to the output. * Dump the field settings to the output.
* @param output the @a ostream to dump to. * @param output the @a ostream to dump to.
*/ */
virtual void dump(ostream& output) const = 0; virtual void dump(ostream* output) const = 0;
/** /**
* Return whether the field is available. * Return whether the field is available.
@@ -281,46 +281,46 @@ class DataField : public AttributedItem {
* Reads the numeric value from the @a SymbolString. * Reads the numeric value from the @a SymbolString.
* @param data the data @a SymbolString for reading binary data. * @param data the data @a SymbolString for reading binary data.
* @param offset the additional offset to add for reading binary data. * @param offset the additional offset to add for reading binary data.
* @param output the variable in which to store the numeric value.
* @param fieldName the name of the field to read, or NULL for the first field. * @param fieldName the name of the field to read, or NULL for the first field.
* @param fieldIndex the optional index of the named field, or -1. * @param fieldIndex the optional index of the named field, or -1.
* @param output the variable in which to store the numeric value.
* @return @a RESULT_OK on success, * @return @a RESULT_OK on success,
* or @a RESULT_EMPTY if the field was skipped (either if the partType does * or @a RESULT_EMPTY if the field was skipped (either if the partType does
* not match or ignored, or due to @a fieldName or @a fieldIndex), * not match or ignored, or due to @a fieldName or @a fieldIndex),
* or an error code. * or an error code.
*/ */
virtual result_t read(const SymbolString& data, size_t offset, virtual result_t read(const SymbolString& data, size_t offset,
unsigned int& output, const char* fieldName = NULL, ssize_t fieldIndex = -1) const = 0; const char* fieldName, ssize_t fieldIndex, unsigned int* output) const = 0;
/** /**
* Reads the value from the @a SymbolString. * Reads the value from the @a SymbolString.
* @param data the data @a SymbolString for reading binary data. * @param data the data @a SymbolString for reading binary data.
* @param offset the additional offset to add for reading binary data. * @param offset the additional offset to add for reading binary data.
* @param output the @a ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use.
* @param outputIndex the optional index of the field when using an indexed output format, or -1.
* @param leadingSeparator whether to prepend a separator before the formatted value. * @param leadingSeparator whether to prepend a separator before the formatted value.
* @param fieldName the optional name of a field to limit the output to. * @param fieldName the optional name of a field to limit the output to.
* @param fieldIndex the optional index of the named field to limit the output to, or -1. * @param fieldIndex the optional index of the named field to limit the output to, or -1.
* @param outputFormat the @a OutputFormat options to use.
* @param outputIndex the optional index of the field when using an indexed output format, or -1.
* @param output the @a ostream to append the formatted value to.
* @return @a RESULT_OK on success (or if the partType does not match), * @return @a RESULT_OK on success (or if the partType does not match),
* or @a RESULT_EMPTY if the field was skipped (either ignored or due to @a fieldName or @a fieldIndex), * or @a RESULT_EMPTY if the field was skipped (either ignored or due to @a fieldName or @a fieldIndex),
* or an error code. * or an error code.
*/ */
virtual result_t read(const SymbolString& data, size_t offset, virtual result_t read(const SymbolString& data, size_t offset,
ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, bool leadingSeparator, const char* fieldName, ssize_t fieldIndex,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const = 0; OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const = 0;
/** /**
* Writes the value to the master or slave @a SymbolString. * Writes the value to the master or slave @a SymbolString.
* @param input the @a istringstream to parse the formatted value from. * @param input the @a istringstream to parse the formatted value from.
* @param data the unescaped data @a SymbolString for writing binary data.
* @param offset the additional offset to add for writing binary data.
* @param separator the separator character between multiple fields. * @param separator the separator character between multiple fields.
* @param length the variable in which to store the used length in bytes, or NULL. * @param offset the additional offset to add for writing binary data.
* @param data the data @a SymbolString to write binary data to.
* @param usedLength the variable in which to store the used length in bytes, 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 write(istringstream& input, SymbolString& data, virtual result_t write(char separator, size_t offset, istringstream* input,
size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const = 0; SymbolString* data, size_t* usedLength) const = 0;
}; };
@@ -337,8 +337,8 @@ class SingleDataField : public DataField {
* @param partType the message part in which the field is stored. * @param partType the message part in which the field is stored.
* @param length the number of symbols in the message part in which the field is stored. * @param length the number of symbols in the message part in which the field is stored.
*/ */
SingleDataField(const string name, const map<string, string>& attributes, const DataType* dataType, SingleDataField(const string& name, const map<string, string>& attributes, const DataType* dataType,
const PartType partType, const size_t length) PartType partType, size_t length)
: DataField(name, attributes), : DataField(name, attributes),
m_partType(partType), m_dataType(dataType), m_length(length) {} m_partType(partType), m_dataType(dataType), m_length(length) {}
@@ -365,9 +365,9 @@ class SingleDataField : public DataField {
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static result_t create(const string name, const map<string, string>& attributes, const DataType* dataType, static result_t create(const string& name, const map<string, string>& attributes, const DataType* dataType,
const PartType partType, const size_t length, int divisor, map<unsigned int, string> values, PartType partType, size_t length, int divisor, const string& constantValue,
const string constantValue, const bool verifyValue, SingleDataField* &returnField); bool verifyValue, map<unsigned int, string>* values, SingleDataField** returnField);
/** /**
* Get whether this field is ignored. * Get whether this field is ignored.
@@ -382,11 +382,12 @@ class SingleDataField : public DataField {
PartType getPartType() const { return m_partType; } PartType getPartType() const { return m_partType; }
// @copydoc // @copydoc
size_t getLength(PartType partType, size_t maxLength = MAX_LEN) const override; size_t getLength(PartType partType, size_t maxLength) const override;
// @copydoc // @copydoc
result_t derive(const string name, map<string, string> attributes, const PartType partType, result_t derive(const string& name, PartType partType, int divisor,
int divisor, map<unsigned int, string> values, vector<const SingleDataField*>& fields) const override; const map<unsigned int, string>& values, map<string, string>* attributes,
vector<const SingleDataField*>* fields) const override;
/** /**
* Get whether this field uses a full byte offset. * Get whether this field uses a full byte offset.
@@ -396,24 +397,36 @@ class SingleDataField : public DataField {
*/ */
bool hasFullByteOffset(bool after) const; bool hasFullByteOffset(bool after) const;
/**
* Dump the common prefix field settings to the output (name and part type).
* @param output the @a ostream to dump to.
*/
void dumpPrefix(ostream* output) const;
/**
* Dump the common suffix field settings to the output (optiona unit and comment).
* @param output the @a ostream to dump to.
*/
void dumpSuffix(ostream* output) const;
// @copydoc // @copydoc
void dump(ostream& output) const override; void dump(ostream* output) const override;
// @copydoc // @copydoc
bool hasField(const char* fieldName, bool numeric) const override; bool hasField(const char* fieldName, bool numeric) const override;
// @copydoc // @copydoc
result_t read(const SymbolString& data, size_t offset, result_t read(const SymbolString& data, size_t offset,
unsigned int& output, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; const char* fieldName, ssize_t fieldIndex, unsigned int* output) const override;
// @copydoc // @copydoc
result_t read(const SymbolString& data, size_t offset, result_t read(const SymbolString& data, size_t offset,
ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, bool leadingSeparator, const char* fieldName, ssize_t fieldIndex,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const override;
// @copydoc // @copydoc
result_t write(istringstream& input, SymbolString& data, result_t write(char separator, size_t offset, istringstream* input,
size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const override; SymbolString* data, size_t* usedLength) const override;
protected: protected:
@@ -421,13 +434,12 @@ class SingleDataField : public DataField {
* Internal method for reading the field from a @a SymbolString. * Internal method for reading the field from a @a SymbolString.
* @param input the @a SymbolString to read the binary value from. * @param input the @a SymbolString to read the binary value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param output the ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param output the ostream to append the formatted value to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readSymbols(const SymbolString& input, virtual result_t readSymbols(const SymbolString& input, size_t offset,
const size_t offset, OutputFormat outputFormat, ostream* output) const;
ostringstream& output, OutputFormat outputFormat) const;
/** /**
* Internal method for writing the field to a @a SymbolString. * Internal method for writing the field to a @a SymbolString.
@@ -437,9 +449,8 @@ class SingleDataField : public DataField {
* @param usedLength the variable in which to store the used length in bytes, or NULL. * @param usedLength the variable in which to store the used length in bytes, 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 writeSymbols(istringstream& input, virtual result_t writeSymbols(size_t offset, istringstream* input,
const size_t offset, SymbolString* output, size_t* usedLength) const;
SymbolString& output, size_t* usedLength) const;
/** the message part in which the field is stored. */ /** the message part in which the field is stored. */
const PartType m_partType; const PartType m_partType;
@@ -466,8 +477,8 @@ class ValueListDataField : public SingleDataField {
* @param length the number of symbols in the message part in which the field is stored. * @param length the number of symbols in the message part in which the field is stored.
* @param values the value=text assignments. * @param values the value=text assignments.
*/ */
ValueListDataField(const string name, const map<string, string>& attributes, const DataType* dataType, ValueListDataField(const string& name, const map<string, string>& attributes, const DataType* dataType,
const PartType partType, const size_t length, const map<unsigned int, string> values) PartType partType, size_t length, const map<unsigned int, string>& values)
: SingleDataField(name, attributes, dataType, partType, length), : SingleDataField(name, attributes, dataType, partType, length),
m_values(values) {} m_values(values) {}
@@ -480,21 +491,22 @@ class ValueListDataField : public SingleDataField {
const ValueListDataField* clone() const override; const ValueListDataField* clone() const override;
// @copydoc // @copydoc
result_t derive(const string name, map<string, string> attributes, const PartType partType, result_t derive(const string& name, PartType partType, int divisor,
int divisor, map<unsigned int, string> values, vector<const SingleDataField*>& fields) const override; const map<unsigned int, string>& values, map<string, string>* attributes,
vector<const SingleDataField*>* fields) const override;
// @copydoc // @copydoc
void dump(ostream& output) const override; void dump(ostream* output) const override;
protected: protected:
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, const size_t offset, result_t readSymbols(const SymbolString& input, size_t offset,
ostringstream& output, OutputFormat outputFormat) const override; const OutputFormat outputFormat, ostream* output) const override;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, const size_t offset, result_t writeSymbols(size_t offset, istringstream* input,
SymbolString& output, size_t* usedLength) const override; SymbolString* output, size_t* usedLength) const override;
private: private:
@@ -518,8 +530,8 @@ class ConstantDataField : public SingleDataField {
* @param value the constant value. * @param value the constant value.
* @param verify whether to verify the read value against the constant value. * @param verify whether to verify the read value against the constant value.
*/ */
ConstantDataField(const string name, const map<string, string>& attributes, const DataType* dataType, ConstantDataField(const string& name, const map<string, string>& attributes, const DataType* dataType,
const PartType partType, const size_t length, const string value, const bool verify) PartType partType, size_t length, const string& value, bool verify)
: SingleDataField(name, attributes, dataType, partType, length), : SingleDataField(name, attributes, dataType, partType, length),
m_value(value), m_verify(verify) {} m_value(value), m_verify(verify) {}
@@ -532,21 +544,22 @@ class ConstantDataField : public SingleDataField {
const ConstantDataField* clone() const override; const ConstantDataField* clone() const override;
// @copydoc // @copydoc
result_t derive(const string name, map<string, string> attributes, const PartType partType, result_t derive(const string& name, PartType partType, int divisor,
int divisor, map<unsigned int, string> values, vector<const SingleDataField*>& fields) const override; const map<unsigned int, string>& values, map<string, string>* attributes,
vector<const SingleDataField*>* fields) const override;
// @copydoc // @copydoc
void dump(ostream& output) const override; void dump(ostream* output) const override;
protected: protected:
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, const size_t offset, result_t readSymbols(const SymbolString& input, size_t offset,
ostringstream& output, OutputFormat outputFormat) const override; const OutputFormat outputFormat, ostream* output) const override;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, const size_t offset, result_t writeSymbols(size_t offset, istringstream* input,
SymbolString& output, size_t* usedLength) const override; SymbolString* output, size_t* usedLength) const override;
private: private:
@@ -580,7 +593,7 @@ class DataFieldSet : public DataField {
* @param name the field name. * @param name the field name.
* @param fields the @a vector of @a SingleDataField instances part of this set. * @param fields the @a vector of @a SingleDataField instances part of this set.
*/ */
DataFieldSet(const string name, const vector<const SingleDataField*> fields) DataFieldSet(const string& name, const vector<const SingleDataField*> fields)
: DataField(name), m_fields(fields) { : DataField(name), m_fields(fields) {
bool uniqueNames = true; bool uniqueNames = true;
map<string, string> names; map<string, string> names;
@@ -588,7 +601,7 @@ class DataFieldSet : public DataField {
if (field->isIgnored()) { if (field->isIgnored()) {
continue; continue;
} }
string name = field->getName(); string name = field->getName(-1);
if (name.empty() || names.find(name) != names.end()) { if (name.empty() || names.find(name) != names.end()) {
uniqueNames = false; uniqueNames = false;
break; break;
@@ -607,33 +620,22 @@ class DataFieldSet : public DataField {
const DataFieldSet* clone() const override; const DataFieldSet* clone() const override;
// @copydoc // @copydoc
size_t getLength(PartType partType, size_t maxLength = MAX_LEN) const override; size_t getLength(PartType partType, size_t maxLength) const override;
// @copydoc // @copydoc
string getName(const ssize_t fieldIndex = -1) const override; string getName(ssize_t fieldIndex) const override;
// @copydoc // @copydoc
result_t derive(const string name, map<string, string> attributes, const PartType partType, result_t derive(const string& name, PartType partType, int divisor,
int divisor, map<unsigned int, string> values, vector<const SingleDataField*>& fields) const override; const map<unsigned int, string>& values, map<string, string>* attributes,
vector<const SingleDataField*>* fields) const override;
/** /**
* Returns the @a SingleDataField at the specified index. * Returns the @a SingleDataField at the specified index.
* @param index the index of the @a SingleDataField to return. * @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL. * @return the @a SingleDataField at the specified index, or NULL.
*/ */
/*SingleDataField* operator[](const size_t index) { const SingleDataField* operator[](size_t index) const {
if (index >= m_fields.size()) {
return NULL;
}
return m_fields[index];
}*/
/**
* Returns the @a SingleDataField at the specified index.
* @param index the index of the @a SingleDataField to return.
* @return the @a SingleDataField at the specified index, or NULL.
*/
const SingleDataField* operator[](const size_t index) const {
if (index >= m_fields.size()) { if (index >= m_fields.size()) {
return NULL; return NULL;
} }
@@ -650,20 +652,20 @@ class DataFieldSet : public DataField {
bool hasField(const char* fieldName, bool numeric) const override; bool hasField(const char* fieldName, bool numeric) const override;
// @copydoc // @copydoc
void dump(ostream& output) const override; void dump(ostream* output) const override;
// @copydoc // @copydoc
result_t read(const SymbolString& data, size_t offset, result_t read(const SymbolString& data, size_t offset,
unsigned int& output, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; const char* fieldName, ssize_t fieldIndex, unsigned int* output) const override;
// @copydoc // @copydoc
result_t read(const SymbolString& data, size_t offset, result_t read(const SymbolString& data, size_t offset,
ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, bool leadingSeparator, const char* fieldName, ssize_t fieldIndex,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const override;
// @copydoc // @copydoc
result_t write(istringstream& input, SymbolString& data, result_t write(char separator, size_t offset, istringstream* input,
size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const override; SymbolString* data, size_t* usedLength) const override;
private: private:
@@ -692,7 +694,7 @@ class DataFieldTemplates : public MappedFileReader {
* Constructs a new copied instance. * Constructs a new copied instance.
* @param other the @a DataFieldTemplates to copy from. * @param other the @a DataFieldTemplates to copy from.
*/ */
DataFieldTemplates(DataFieldTemplates& other); DataFieldTemplates(const DataFieldTemplates& other);
/** /**
* Destructor. * Destructor.
@@ -717,11 +719,11 @@ class DataFieldTemplates : public MappedFileReader {
result_t add(const DataField* field, string name = "", bool replace = false); result_t add(const DataField* field, string name = "", bool replace = false);
// @copydoc // @copydoc
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override; result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override;
// @copydoc // @copydoc
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override; vector< map<string, string> >* subRows, string* errorDescription) override;
/** /**
* Gets the template @a DataField instance with the specified name. * Gets the template @a DataField instance with the specified name.
@@ -729,7 +731,7 @@ class DataFieldTemplates : public MappedFileReader {
* @return the template @a DataField instance, or NULL. * @return the template @a DataField instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
const DataField* get(string name) const; const DataField* get(const string& name) const;
private: private:
+114 -123
View File
@@ -42,30 +42,29 @@ using std::setw;
using std::endl; using std::endl;
bool DataType::dump(ostream& output, const size_t length, const bool appendSeparatorDivisor) const { bool DataType::dump(size_t length, bool appendSeparatorDivisor, ostream* output) const {
output << m_id; *output << m_id;
if (isAdjustableLength()) { if (isAdjustableLength()) {
if (length == REMAIN_LEN) { if (length == REMAIN_LEN) {
output << ":*"; *output << ":*";
} else { } else {
output << ":" << static_cast<unsigned>(length); *output << ":" << static_cast<unsigned>(length);
} }
} }
if (appendSeparatorDivisor) { if (appendSeparatorDivisor) {
output << FIELD_SEPARATOR; *output << FIELD_SEPARATOR;
} }
return false; return false;
} }
result_t StringDataType::readRawValue(const SymbolString& input, const size_t offset, result_t StringDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t length, unsigned int& value) const { unsigned int* value) const {
return RESULT_EMPTY; return RESULT_EMPTY;
} }
result_t StringDataType::readSymbols(const SymbolString& input, result_t StringDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const {
ostringstream& output, OutputFormat outputFormat) const {
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
symbol_t symbol; symbol_t symbol;
@@ -81,16 +80,16 @@ result_t StringDataType::readSymbols(const SymbolString& input,
} }
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
output << setfill('0') << (m_isHex ? hex : dec); *output << setfill('0') << (m_isHex ? hex : dec);
for (size_t index = start, i = 0; i < count; index += incr, i++) { for (size_t index = start, i = 0; i < count; index += incr, i++) {
symbol = input.dataAt(offset + index); symbol = input.dataAt(offset + index);
if (m_isHex) { if (m_isHex) {
if (i > 0) { if (i > 0) {
output << ' '; *output << ' ';
} }
output << setw(2) << static_cast<unsigned>(symbol); *output << setw(2) << static_cast<unsigned>(symbol);
} else { } else {
if (symbol == 0x00) { if (symbol == 0x00) {
terminated = true; terminated = true;
@@ -101,22 +100,21 @@ result_t StringDataType::readSymbols(const SymbolString& input,
symbol = '?'; symbol = '?';
} else if (outputFormat & OF_JSON) { } else if (outputFormat & OF_JSON) {
if (symbol == '"' || symbol == '\\') { if (symbol == '"' || symbol == '\\') {
output << '\\'; // escape *output << '\\'; // escape
} }
} }
output << static_cast<char>(symbol); *output << static_cast<char>(symbol);
} }
} }
} }
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
return RESULT_OK; return RESULT_OK;
} }
result_t StringDataType::writeSymbols(istringstream& input, result_t StringDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const {
SymbolString& output, size_t* usedLength) const {
size_t start = 0, count = length; size_t start = 0, count = length;
bool remainder = count == REMAIN_LEN && hasFlag(ADJ); bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
int incr = 1; int incr = 1;
@@ -132,7 +130,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
count = 1; count = 1;
} }
for (size_t index = start, i = 0; i < count; index += incr, i++) { for (size_t index = start, i = 0; i < count; index += incr, i++) {
output.dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement output->dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement
} }
if (usedLength != NULL) { if (usedLength != NULL) {
*usedLength = count; *usedLength = count;
@@ -143,39 +141,39 @@ result_t StringDataType::writeSymbols(istringstream& input,
size_t i = 0, index; size_t i = 0, index;
for (index = start; i < count; index += incr, i++) { for (index = start; i < count; index += incr, i++) {
if (m_isHex) { if (m_isHex) {
while (!input.eof() && input.peek() == ' ') { while (!input->eof() && input->peek() == ' ') {
input.get(); input->get();
} }
if (input.eof()) { // no more digits if (input->eof()) { // no more digits
value = m_replacement; // fill up with replacement value = m_replacement; // fill up with replacement
} else { } else {
token.clear(); token.clear();
token.push_back((symbol_t)input.get()); token.push_back((symbol_t)input->get());
if (input.eof()) { if (input->eof()) {
return RESULT_ERR_INVALID_NUM; // too short hex value return RESULT_ERR_INVALID_NUM; // too short hex value
} }
token.push_back((symbol_t)input.get()); token.push_back((symbol_t)input->get());
if (input.eof()) { if (input->eof()) {
return RESULT_ERR_INVALID_NUM; // too short hex value return RESULT_ERR_INVALID_NUM; // too short hex value
} }
value = parseInt(token.c_str(), 16, 0, 0xff, result); value = parseInt(token.c_str(), 16, 0, 0xff, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; // invalid hex value return result; // invalid hex value
} }
} }
} else { } else {
if (input.eof()) { if (input->eof()) {
value = m_replacement; value = m_replacement;
} else { } else {
value = input.get(); value = input->get();
if (input.eof() || value < 0x20) { if (input->eof() || value < 0x20) {
value = m_replacement; value = m_replacement;
} }
} }
} }
if (remainder && input.eof() && i > 0) { if (remainder && input->eof() && i > 0) {
if (value == 0x00 && !m_isHex) { if (value == 0x00 && !m_isHex) {
output.dataAt(offset + index) = 0; output->dataAt(offset + index) = 0;
index += incr; index += incr;
} }
break; break;
@@ -183,7 +181,7 @@ result_t StringDataType::writeSymbols(istringstream& input,
if (value > 0xff) { if (value > 0xff) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
output.dataAt(offset + index) = (symbol_t)value; output->dataAt(offset + index) = (symbol_t)value;
} }
if (!remainder && i < count) { if (!remainder && i < count) {
@@ -196,14 +194,13 @@ result_t StringDataType::writeSymbols(istringstream& input,
} }
result_t DateTimeDataType::readRawValue(const SymbolString& input, const size_t offset, result_t DateTimeDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t length, unsigned int& value) const { unsigned int* value) const {
return RESULT_EMPTY; return RESULT_EMPTY;
} }
result_t DateTimeDataType::readSymbols(const SymbolString& input, result_t DateTimeDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const {
ostringstream& output, OutputFormat outputFormat) const {
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
symbol_t symbol, last = 0, hour = 0; symbol_t symbol, last = 0, hour = 0;
@@ -218,7 +215,7 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input,
} }
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
int type = (m_hasDate?2:0) | (m_hasTime?1:0); int type = (m_hasDate?2:0) | (m_hasTime?1:0);
for (size_t index = start, i = 0; i < count; index += incr, i++) { for (size_t index = start, i = 0; i < count; index += incr, i++) {
@@ -236,13 +233,13 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input,
case 2: // date only case 2: // date only
if (!hasFlag(REQ) && symbol == m_replacement) { if (!hasFlag(REQ) && symbol == m_replacement) {
if (i + 1 != length) { if (i + 1 != length) {
output << NULL_VALUE << "."; *output << NULL_VALUE << ".";
break; break;
} else if (last == m_replacement) { } else if (last == m_replacement) {
if (length == 2) { // number of days since 01.01.1900 if (length == 2) { // number of days since 01.01.1900
output << NULL_VALUE << "."; *output << NULL_VALUE << ".";
} }
output << NULL_VALUE; *output << NULL_VALUE;
break; break;
} }
} }
@@ -259,29 +256,29 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input,
y++; y++;
m -= 12; m -= 12;
} }
output << dec << setfill('0') << setw(2) << static_cast<unsigned>(d) << "." *output << dec << setfill('0') << setw(2) << static_cast<unsigned>(d) << "."
<< setw(2) << static_cast<unsigned>(m) << "." << static_cast<unsigned>(y + 1900); << setw(2) << static_cast<unsigned>(m) << "." << static_cast<unsigned>(y + 1900);
break; break;
} }
if (i + 1 == length) { if (i + 1 == length) {
output << (2000 + symbol); *output << (2000 + symbol);
} else if (symbol < 1 || (i == 0 && symbol > 31) || (i == 1 && symbol > 12)) { } else if (symbol < 1 || (i == 0 && symbol > 31) || (i == 1 && symbol > 12)) {
return RESULT_ERR_OUT_OF_RANGE; // invalid date return RESULT_ERR_OUT_OF_RANGE; // invalid date
} else { } else {
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol) << "."; *output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol) << ".";
} }
break; break;
case 1: // time only case 1: // time only
if (!hasFlag(REQ) && symbol == m_replacement) { if (!hasFlag(REQ) && symbol == m_replacement) {
if (length == 1) { // truncated time if (length == 1) { // truncated time
output << NULL_VALUE << ":" << NULL_VALUE; *output << NULL_VALUE << ":" << NULL_VALUE;
break; break;
} }
if (i > 0) { if (i > 0) {
output << ":"; *output << ":";
} }
output << NULL_VALUE; *output << NULL_VALUE;
break; break;
} }
if (hasFlag(SPE)) { // minutes since midnight if (hasFlag(SPE)) { // minutes since midnight
@@ -297,7 +294,7 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input,
if (hour > 24) { if (hour > 24) {
return RESULT_ERR_OUT_OF_RANGE; // invalid hour return RESULT_ERR_OUT_OF_RANGE; // invalid hour
} }
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(hour); *output << setw(2) << dec << setfill('0') << static_cast<unsigned>(hour);
symbol = (symbol_t)(minutes % 60); symbol = (symbol_t)(minutes % 60);
} else if (length == 1) { // truncated time } else if (length == 1) { // truncated time
if (m_bitCount < 8) { if (m_bitCount < 8) {
@@ -320,22 +317,21 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input,
return RESULT_ERR_OUT_OF_RANGE; // invalid time return RESULT_ERR_OUT_OF_RANGE; // invalid time
} }
if (i > 0) { if (i > 0) {
output << ":"; *output << ":";
} }
output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol); *output << setw(2) << dec << setfill('0') << static_cast<unsigned>(symbol);
break; break;
} }
last = symbol; last = symbol;
} }
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"';
} }
return RESULT_OK; return RESULT_OK;
} }
result_t DateTimeDataType::writeSymbols(istringstream& input, result_t DateTimeDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const {
SymbolString& output, size_t* usedLength) const {
size_t start = 0, count = length; size_t start = 0, count = length;
bool remainder = count == REMAIN_LEN && hasFlag(ADJ); bool remainder = count == REMAIN_LEN && hasFlag(ADJ);
int incr = 1; int incr = 1;
@@ -351,7 +347,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
count = 1; count = 1;
} }
for (size_t index = start, i = 0; i < count; index += incr, i++) { for (size_t index = start, i = 0; i < count; index += incr, i++) {
output.dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement output->dataAt(offset + index) = (symbol_t)m_replacement; // fill up with replacement
} }
if (usedLength != NULL) { if (usedLength != NULL) {
*usedLength = count; *usedLength = count;
@@ -369,14 +365,14 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (length == 4 && i == 2) { if (length == 4 && i == 2) {
continue; // skip weekday in between continue; // skip weekday in between
} }
if (input.eof() || !getline(input, token, '.')) { if (input->eof() || !getline(*input, token, '.')) {
return RESULT_ERR_EOF; // incomplete return RESULT_ERR_EOF; // incomplete
} }
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) { if (!hasFlag(REQ) && token == NULL_VALUE) {
value = m_replacement; value = m_replacement;
break; break;
} }
value = parseInt(token.c_str(), 10, 0, 2099, result); value = parseInt(token.c_str(), 10, 0, 2099, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; // invalid date part return result; // invalid date part
} }
@@ -389,7 +385,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
int l = last <= 2 ? 1 : 0; int l = last <= 2 ? 1 : 0;
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001); int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
value = mjd - 15020; // 01.01.1900 value = mjd - 15020; // 01.01.1900
output.dataAt(offset + index) = (symbol_t)(value&0xff); output->dataAt(offset + index) = (symbol_t)(value&0xff);
value >>= 8; value >>= 8;
index += incr; index += incr;
skip = false; skip = false;
@@ -404,10 +400,10 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001); int mjd = 14956 + lastLast + static_cast<int>((y-l)*365.25) + static_cast<int>((last+1+l*12)*30.6001);
int daysSinceSunday = (mjd+3) % 7; // Sun=0 int daysSinceSunday = (mjd+3) % 7; // Sun=0
if (hasFlag(BCD)) { if (hasFlag(BCD)) {
output.dataAt(offset + index - incr) = (symbol_t)((6+daysSinceSunday) % 7); // Sun=0x06 output->dataAt(offset + index - incr) = (symbol_t)((6+daysSinceSunday) % 7); // Sun=0x06
} else { } else {
// Sun=0x07 // Sun=0x07
output.dataAt(offset + index - incr) = (symbol_t)(daysSinceSunday == 0 ? 7 : daysSinceSunday); output->dataAt(offset + index - incr) = (symbol_t)(daysSinceSunday == 0 ? 7 : daysSinceSunday);
} }
} }
if (value >= 2000) { if (value >= 2000) {
@@ -422,10 +418,10 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
break; break;
case 1: // time only case 1: // time only
if (input.eof() || !getline(input, token, LENGTH_SEPARATOR)) { if (input->eof() || !getline(*input, token, LENGTH_SEPARATOR)) {
return RESULT_ERR_EOF; // incomplete return RESULT_ERR_EOF; // incomplete
} }
if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) { if (!hasFlag(REQ) && token == NULL_VALUE) {
value = m_replacement; value = m_replacement;
if (length == 1) { // truncated time if (length == 1) { // truncated time
if (i == 0) { if (i == 0) {
@@ -439,7 +435,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
} }
break; break;
} }
value = parseInt(token.c_str(), 10, 0, 59, result); value = parseInt(token.c_str(), 10, 0, 59, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; // invalid time part return result; // invalid time part
} }
@@ -452,7 +448,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
break; break;
} }
value += last*60; value += last*60;
output.dataAt(offset + index) = (symbol_t)(value&0xff); output->dataAt(offset + index) = (symbol_t)(value&0xff);
value >>= 8; value >>= 8;
index += incr; index += incr;
} else if (length == 1) { // truncated time } else if (length == 1) { // truncated time
@@ -480,7 +476,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
if (value > 0xff) { if (value > 0xff) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
output.dataAt(offset + index) = (symbol_t)value; output->dataAt(offset + index) = (symbol_t)value;
} }
} }
@@ -494,7 +490,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input,
} }
size_t NumberDataType::calcPrecision(const int divisor) { size_t NumberDataType::calcPrecision(int divisor) {
size_t precision = 0; size_t precision = 0;
if (divisor > 1) { if (divisor > 1) {
for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, precision++) { for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, precision++) {
@@ -506,28 +502,28 @@ size_t NumberDataType::calcPrecision(const int divisor) {
return precision; return precision;
} }
bool NumberDataType::dump(ostream& output, size_t length, const bool appendSeparatorDivisor) const { bool NumberDataType::dump(size_t length, bool appendSeparatorDivisor, ostream* output) const {
if (m_bitCount < 8) { if (m_bitCount < 8) {
DataType::dump(output, m_bitCount, appendSeparatorDivisor); DataType::dump(m_bitCount, appendSeparatorDivisor, output);
} else { } else {
DataType::dump(output, length, appendSeparatorDivisor); DataType::dump(length, appendSeparatorDivisor, output);
} }
if (!appendSeparatorDivisor) { if (!appendSeparatorDivisor) {
return false; return false;
} }
if (m_baseType) { if (m_baseType) {
if (m_baseType->m_divisor != m_divisor) { if (m_baseType->m_divisor != m_divisor) {
output << static_cast<int>(m_divisor / m_baseType->m_divisor); *output << static_cast<int>(m_divisor / m_baseType->m_divisor);
return true; return true;
} }
} else if (m_divisor != 1) { } else if (m_divisor != 1) {
output << static_cast<int>(m_divisor); *output << static_cast<int>(m_divisor);
return true; return true;
} }
return false; return false;
} }
result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataType* &derived) const { result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataType** derived) const {
if (divisor == 0) { if (divisor == 0) {
divisor = 1; divisor = 1;
} }
@@ -549,7 +545,7 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
} }
} }
if (divisor == m_divisor && bitCount == m_bitCount) { if (divisor == m_divisor && bitCount == m_bitCount) {
derived = this; *derived = this;
return RESULT_OK; return RESULT_OK;
} }
if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) { if (-MAX_DIVISOR > divisor || divisor > MAX_DIVISOR) {
@@ -569,19 +565,18 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
if (m_bitCount < 8) { if (m_bitCount < 8) {
derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement, *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_firstBit, divisor, m_baseType ? m_baseType : this); m_firstBit, divisor, m_baseType ? m_baseType : this);
} else { } else {
derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement, *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this); m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
} }
DataTypeList::getInstance()->addCleanup(derived); DataTypeList::getInstance()->addCleanup(*derived);
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::readRawValue(const SymbolString& input, result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
size_t offset, const size_t length, unsigned int* value) const {
unsigned int& value) const {
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
symbol_t symbol; symbol_t symbol;
@@ -594,13 +589,13 @@ result_t NumberDataType::readRawValue(const SymbolString& input,
incr = -1; incr = -1;
} }
value = 0; *value = 0;
unsigned int exp = 1; unsigned int exp = 1;
for (size_t index = start, i = 0; i < count; index += incr, i++) { for (size_t index = start, i = 0; i < count; index += incr, i++) {
symbol = input.dataAt(offset + index); symbol = input.dataAt(offset + index);
if (hasFlag(BCD)) { if (hasFlag(BCD)) {
if (!hasFlag(REQ) && symbol == (m_replacement & 0xff)) { if (!hasFlag(REQ) && symbol == (m_replacement & 0xff)) {
value = m_replacement; *value = m_replacement;
return RESULT_OK; return RESULT_OK;
} }
if (!hasFlag(HCD)) { if (!hasFlag(HCD)) {
@@ -611,40 +606,39 @@ result_t NumberDataType::readRawValue(const SymbolString& input,
} else if (symbol > 0x63) { } else if (symbol > 0x63) {
return RESULT_ERR_OUT_OF_RANGE; // invalid HCD return RESULT_ERR_OUT_OF_RANGE; // invalid HCD
} }
value += symbol * exp; *value += symbol * exp;
exp *= 100; exp *= 100;
} else { } else {
value |= symbol * exp; *value |= symbol * exp;
exp <<= 8; exp <<= 8;
} }
} }
if (m_firstBit > 0) { if (m_firstBit > 0) {
value >>= m_firstBit; *value >>= m_firstBit;
} }
if (m_bitCount < 8) { if (m_bitCount < 8) {
value &= (1 << m_bitCount) - 1; *value &= (1 << m_bitCount) - 1;
} }
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::readSymbols(const SymbolString& input, result_t NumberDataType::readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const {
ostringstream& output, OutputFormat outputFormat) const {
unsigned int value = 0; unsigned int value = 0;
int signedValue; int signedValue;
result_t result = readRawValue(input, offset, length, value); result_t result = readRawValue(offset, length, input, &value);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
output << setw(0) << dec; // initialize output *output << setw(0) << dec; // initialize output
if (!hasFlag(REQ) && value == m_replacement) { if (!hasFlag(REQ) && value == m_replacement) {
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << "null"; *output << "null";
} else { } else {
output << NULL_VALUE; *output << NULL_VALUE;
} }
return RESULT_OK; return RESULT_OK;
} }
@@ -694,20 +688,20 @@ result_t NumberDataType::readSymbols(const SymbolString& input,
} }
} }
if (m_precision != 0) { if (m_precision != 0) {
output << fixed << setprecision(static_cast<int>(m_precision+6)); *output << fixed << setprecision(static_cast<int>(m_precision+6));
} else if (val == 0) { } else if (val == 0) {
output << fixed << setprecision(1); *output << fixed << setprecision(1);
} }
output << static_cast<double>(val); *output << static_cast<double>(val);
return RESULT_OK; return RESULT_OK;
} }
if (!negative) { if (!negative) {
if (m_divisor < 0) { if (m_divisor < 0) {
output << (static_cast<float>(value) * static_cast<float>(-m_divisor)); *output << (static_cast<float>(value) * static_cast<float>(-m_divisor));
} else if (m_divisor <= 1) { } else if (m_divisor <= 1) {
output << static_cast<unsigned>(value); *output << static_cast<unsigned>(value);
} else { } else {
output << setprecision(static_cast<int>(m_precision)) *output << setprecision(static_cast<int>(m_precision))
<< fixed << (static_cast<float>(value) / static_cast<float>(m_divisor)); << fixed << (static_cast<float>(value) / static_cast<float>(m_divisor));
} }
return RESULT_OK; return RESULT_OK;
@@ -719,30 +713,27 @@ result_t NumberDataType::readSymbols(const SymbolString& input,
signedValue = static_cast<int>(value); signedValue = static_cast<int>(value);
} }
if (m_divisor < 0) { if (m_divisor < 0) {
output << fixed << setprecision(0) *output << fixed << setprecision(0)
<< (static_cast<float>(signedValue) * static_cast<float>(-m_divisor)); << (static_cast<float>(signedValue) * static_cast<float>(-m_divisor));
} else if (m_divisor <= 1) { } else if (m_divisor <= 1) {
if (hasFlag(FIX) && hasFlag(BCD)) { if (hasFlag(FIX) && hasFlag(BCD)) {
if (outputFormat & OF_JSON) { if (outputFormat & OF_JSON) {
output << '"'; *output << '"' << setw(static_cast<int>(length * 2))
output << setw(static_cast<int>(length * 2)) << setfill('0'); << setfill('0') << static_cast<signed>(signedValue) << setw(0) << '"';
output << static_cast<signed>(signedValue) << setw(0);
output << '"';
return RESULT_OK; return RESULT_OK;
} }
output << setw(static_cast<int>(length * 2)) << setfill('0'); *output << setw(static_cast<int>(length * 2)) << setfill('0');
} }
output << static_cast<signed>(signedValue) << setw(0); *output << static_cast<signed>(signedValue) << setw(0);
} else { } else {
output << setprecision(static_cast<int>(m_precision)) *output << setprecision(static_cast<int>(m_precision))
<< fixed << (static_cast<float>(signedValue) / static_cast<float>(m_divisor)); << fixed << (static_cast<float>(signedValue) / static_cast<float>(m_divisor));
} }
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::writeRawValue(unsigned int value, result_t NumberDataType::writeRawValue(unsigned int value, size_t offset, size_t length,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const {
SymbolString& output, size_t* usedLength) const {
size_t start = 0, count = length; size_t start = 0, count = length;
int incr = 1; int incr = 1;
symbol_t symbol; symbol_t symbol;
@@ -774,10 +765,10 @@ result_t NumberDataType::writeRawValue(unsigned int value,
symbol = (value / exp) & 0xff; symbol = (value / exp) & 0xff;
exp <<= 8; exp <<= 8;
} }
if (index == start && (m_bitCount % 8) != 0 && offset + index < output.getDataSize()) { if (index == start && (m_bitCount % 8) != 0 && offset + index < output->getDataSize()) {
output.dataAt(offset + index) |= symbol; output->dataAt(offset + index) |= symbol;
} else { } else {
output.dataAt(offset + index) = symbol; output->dataAt(offset + index) = symbol;
} }
} }
if (usedLength != NULL) { if (usedLength != NULL) {
@@ -786,17 +777,16 @@ result_t NumberDataType::writeRawValue(unsigned int value,
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::writeSymbols(istringstream& input, result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const {
SymbolString& output, size_t* usedLength) const {
unsigned int value; unsigned int value;
const char* str = input.str().c_str(); if (!hasFlag(REQ) && (isIgnored() || input->str() == NULL_VALUE)) {
if (!hasFlag(REQ) && (isIgnored() || strcmp(str, NULL_VALUE) == 0)) {
value = m_replacement; // replacement value value = m_replacement; // replacement value
} else if (str == NULL || *str == 0) { } else if (input->str().empty()) {
return RESULT_ERR_EOF; // input too short return RESULT_ERR_EOF; // input too short
} else if (hasFlag(EXP)) { // IEEE 754 binary32 } else if (hasFlag(EXP)) { // IEEE 754 binary32
const char* str = input->str().c_str();
char* strEnd = NULL; char* strEnd = NULL;
double dvalue = strtod(str, &strEnd); double dvalue = strtod(str, &strEnd);
if (strEnd == NULL || strEnd == str || *strEnd != 0) { if (strEnd == NULL || strEnd == str || *strEnd != 0) {
@@ -835,6 +825,7 @@ result_t NumberDataType::writeSymbols(istringstream& input,
} }
#endif #endif
} else { } else {
const char* str = input->str().c_str();
char* strEnd = NULL; char* strEnd = NULL;
if (m_divisor == 1) { if (m_divisor == 1) {
if (hasFlag(SIG)) { if (hasFlag(SIG)) {
@@ -1038,7 +1029,7 @@ result_t DataTypeList::add(const DataType* dataType) {
return RESULT_OK; return RESULT_OK;
} }
const DataType* DataTypeList::get(const string id, const size_t length) const { const DataType* DataTypeList::get(const string& id, size_t length) const {
if (length > 0) { if (length > 0) {
ostringstream str; ostringstream str;
str << id << LENGTH_SEPARATOR << static_cast<unsigned>(length); str << id << LENGTH_SEPARATOR << static_cast<unsigned>(length);
+46 -59
View File
@@ -167,7 +167,7 @@ class DataType {
* @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to * @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to
* @a NumberDataType#minValue). * @a NumberDataType#minValue).
*/ */
DataType(const string id, const size_t bitCount, const uint16_t flags, const unsigned int replacement) DataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement)
: m_id(id), m_bitCount(bitCount), m_flags(flags), m_replacement(replacement) {} : m_id(id), m_bitCount(bitCount), m_flags(flags), m_replacement(replacement) {}
/** /**
@@ -190,7 +190,7 @@ class DataType {
* @param flag the flag to check (like #BCD). * @param flag the flag to check (like #BCD).
* @return whether the flag is set. * @return whether the flag is set.
*/ */
bool hasFlag(const unsigned int flag) const { return (m_flags & flag) != 0; } bool hasFlag(unsigned int flag) const { return (m_flags & flag) != 0; }
/** /**
* @return whether this type is ignored. * @return whether this type is ignored.
@@ -216,50 +216,47 @@ class DataType {
/** /**
* Dump the type identifier with the specified length and optionally the * Dump the type identifier with the specified length and optionally the
* divisor to the output. * divisor to the output.
* @param output the @a ostream to dump to.
* @param length the number of symbols to read/write. * @param length the number of symbols to read/write.
* @param appendSeparatorDivisor whether to append a @a FIELD_SEPARATOR followed by the divisor (if available). * @param appendSeparatorDivisor whether to append a @a FIELD_SEPARATOR followed by the divisor (if available).
* @param output the @a ostream to dump to.
* @return true when a non-default divisor was written to the output. * @return true when a non-default divisor was written to the output.
*/ */
virtual bool dump(ostream& output, const size_t length, const bool appendSeparatorDivisor = true) const; virtual bool dump(size_t length, bool appendSeparatorDivisor, ostream* output) const;
/** /**
* Internal method for reading the numeric raw value from a @a SymbolString. * Internal method for reading the numeric raw value from a @a SymbolString.
* @param input the @a SymbolString to read the binary value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to read. * @param length the number of symbols to read.
* @param input the @a SymbolString to read the binary value from.
* @param value the variable in which to store the numeric raw value. * @param value the variable in which to store the numeric raw value.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readRawValue(const SymbolString& input, virtual result_t readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, unsigned int* value) const = 0;
unsigned int& value) const = 0;
/** /**
* Internal method for reading the field from a @a SymbolString. * Internal method for reading the field from a @a SymbolString.
* @param input the @a SymbolString to read the binary value from.
* @param offset the offset in the data of the @a SymbolString. * @param offset the offset in the data of the @a SymbolString.
* @param length the number of symbols to read. * @param length the number of symbols to read.
* @param output the ostringstream to append the formatted value to. * @param input the @a SymbolString to read the binary value from.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param output the ostream to append the formatted value to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t readSymbols(const SymbolString& input, virtual result_t readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const = 0;
ostringstream& output, OutputFormat outputFormat) const = 0;
/** /**
* Internal method for writing the field to a @a SymbolString. * Internal method for writing the field to a @a SymbolString.
* @param input the @a istringstream to parse the formatted value from.
* @param offset the offset in the @a SymbolString. * @param offset the offset in the @a SymbolString.
* @param length the number of symbols to write, or @a REMAIN_LEN. * @param length the number of symbols to write, or @a REMAIN_LEN.
* @param input the @a istringstream to parse the formatted value from.
* @param output the @a SymbolString to write the binary value to. * @param output the @a SymbolString to write the binary value to.
* @param usedLength the variable in which to store the used length in bytes, or NULL. * @param usedLength the variable in which to store the used length in bytes, 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 writeSymbols(istringstream& input, virtual result_t writeSymbols(size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const = 0;
SymbolString& output, size_t* usedLength) const = 0;
protected: protected:
@@ -291,8 +288,8 @@ class StringDataType : public DataType {
* @param replacement the replacement value (fill-up value). * @param replacement the replacement value (fill-up value).
* @param isHex true for hex digits instead of characters. * @param isHex true for hex digits instead of characters.
*/ */
StringDataType(const string id, const size_t bitCount, const uint16_t flags, StringDataType(const string& id, size_t bitCount, uint16_t flags,
const unsigned int replacement, bool isHex = false) unsigned int replacement, bool isHex = false)
: DataType(id, bitCount, flags, replacement), m_isHex(isHex) {} : DataType(id, bitCount, flags, replacement), m_isHex(isHex) {}
/** /**
@@ -301,19 +298,16 @@ class StringDataType : public DataType {
virtual ~StringDataType() {} virtual ~StringDataType() {}
// @copydoc // @copydoc
result_t readRawValue(const SymbolString& input, result_t readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, unsigned int* value) const override;
unsigned int& value) const override;
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, result_t readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const override;
ostringstream& output, OutputFormat outputFormat) const override;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, result_t writeSymbols(size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const override;
SymbolString& output, size_t* usedLength) const override;
private: private:
@@ -337,8 +331,8 @@ class DateTimeDataType : public DataType {
* @param hasTime true if time part is present. * @param hasTime true if time part is present.
* @param resolution the the resolution in minutes for time types, or 1. * @param resolution the the resolution in minutes for time types, or 1.
*/ */
DateTimeDataType(const string id, const size_t bitCount, const uint16_t flags, const unsigned int replacement, DateTimeDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
const bool hasDate, const bool hasTime, const int16_t resolution) bool hasDate, bool hasTime, int16_t resolution)
: DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime), : DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime),
m_resolution(resolution == 0 ? 1 : resolution) {} m_resolution(resolution == 0 ? 1 : resolution) {}
@@ -363,19 +357,16 @@ class DateTimeDataType : public DataType {
int16_t getResolution() const { return m_resolution; } int16_t getResolution() const { return m_resolution; }
// @copydoc // @copydoc
result_t readRawValue(const SymbolString& input, result_t readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, unsigned int* value) const override;
unsigned int& value) const override;
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, result_t readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, OutputFormat outputFormat, ostream* output) const override;
ostringstream& output, OutputFormat outputFormat) const override;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, result_t writeSymbols(const size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const override;
SymbolString& output, size_t* usedLength) const override;
private: private:
@@ -406,8 +397,8 @@ class NumberDataType : public DataType {
* @param divisor the divisor (negative for reciprocal). * @param divisor the divisor (negative for reciprocal).
* @param baseType the base @a NumberDataType for derived instances, or NULL. * @param baseType the base @a NumberDataType for derived instances, or NULL.
*/ */
NumberDataType(const string id, const size_t bitCount, const uint16_t flags, const unsigned int replacement, NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
const unsigned int minValue, const unsigned int maxValue, const int divisor, unsigned int minValue, unsigned int maxValue, int divisor,
const NumberDataType* baseType) const NumberDataType* baseType)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor), : DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_divisor(divisor),
m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {} m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {}
@@ -422,8 +413,8 @@ class NumberDataType : public DataType {
* @param divisor the divisor (negative for reciprocal). * @param divisor the divisor (negative for reciprocal).
* @param baseType the base @a NumberDataType for derived instances, or NULL. * @param baseType the base @a NumberDataType for derived instances, or NULL.
*/ */
NumberDataType(const string id, const size_t bitCount, const uint16_t flags, const unsigned int replacement, NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
const int16_t firstBit, const int divisor, const NumberDataType* baseType = NULL) int16_t firstBit, int divisor, const NumberDataType* baseType = NULL)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor), : DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_divisor(divisor),
m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {} m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {}
@@ -438,10 +429,10 @@ class NumberDataType : public DataType {
* @param divisor the divisor (negative for reciprocal). * @param divisor the divisor (negative for reciprocal).
* @return the precision for formatting the value. * @return the precision for formatting the value.
*/ */
static size_t calcPrecision(const int divisor); static size_t calcPrecision(int divisor);
// @copydoc // @copydoc
bool dump(ostream& output, const size_t length, const bool appendSeparatorDivisor = true) const override; bool dump(size_t length, bool appendSeparatorDivisor, ostream* output) const override;
/** /**
* Derive a new @a NumberDataType from this. * Derive a new @a NumberDataType from this.
@@ -453,7 +444,7 @@ class NumberDataType : public DataType {
* not necessary. * not necessary.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t derive(int divisor, size_t bitCount, const NumberDataType* &derived) const; virtual result_t derive(int divisor, size_t bitCount, const NumberDataType** derived) const;
/** /**
* @return the minimum raw value. * @return the minimum raw value.
@@ -481,14 +472,12 @@ class NumberDataType : public DataType {
int16_t getFirstBit() const { return m_firstBit; } int16_t getFirstBit() const { return m_firstBit; }
// @copydoc // @copydoc
result_t readRawValue(const SymbolString& input, result_t readRawValue(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, unsigned int* value) const override;
unsigned int& value) const override;
// @copydoc // @copydoc
result_t readSymbols(const SymbolString& input, result_t readSymbols(size_t offset, size_t length, const SymbolString& input,
const size_t offset, const size_t length, const OutputFormat outputFormat, ostream* output) const override;
ostringstream& output, OutputFormat outputFormat) const override;
/** /**
* Internal method for writing the numeric raw value to a @a SymbolString. * Internal method for writing the numeric raw value to a @a SymbolString.
@@ -500,14 +489,12 @@ class NumberDataType : public DataType {
* or NULL. * or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t writeRawValue(unsigned int value, result_t writeRawValue(unsigned int value, size_t offset, size_t length,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const;
SymbolString& output, size_t* usedLength = NULL) const;
// @copydoc // @copydoc
result_t writeSymbols(istringstream& input, result_t writeSymbols(size_t offset, size_t length, istringstream* input,
const size_t offset, const size_t length, SymbolString* output, size_t* usedLength) const override;
SymbolString& output, size_t* usedLength) const override;
private: private:
@@ -580,7 +567,7 @@ class DataTypeList {
* @return the @a DataType instance, or NULL if not available. * @return the @a DataType instance, or NULL if not available.
* Note: the caller may not free the instance. * Note: the caller may not free the instance.
*/ */
const DataType* get(const string id, const size_t length = 0) const; const DataType* get(const string& id, size_t length = 0) const;
/** /**
* Returns an iterator pointing to the first ID/@a DataType pair. * Returns an iterator pointing to the first ID/@a DataType pair.
+9 -9
View File
@@ -42,7 +42,7 @@ Device::~Device() {
close(); close();
} }
Device* Device::create(const char* name, const bool checkDevice, const bool readOnly, const bool initialSend) { Device* Device::create(const char* name, bool checkDevice, bool readOnly, bool initialSend) {
if (strchr(name, '/') == NULL && strchr(name, ':') != NULL) { if (strchr(name, '/') == NULL && strchr(name, ':') != NULL) {
char* in = strdup(name); char* in = strdup(name);
bool udp = false; bool udp = false;
@@ -57,7 +57,7 @@ Device* Device::create(const char* name, const bool checkDevice, const bool read
return NULL; // invalid protocol or missing port return NULL; // invalid protocol or missing port
} }
result_t result = RESULT_OK; result_t result = RESULT_OK;
unsigned int port = parseInt(portpos+1, 10, 1, 65535, result); unsigned int port = parseInt(portpos+1, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
free(in); free(in);
return NULL; // invalid port return NULL; // invalid port
@@ -98,7 +98,7 @@ bool Device::isValid() {
return m_fd != -1; return m_fd != -1;
} }
result_t Device::send(const symbol_t value) { result_t Device::send(symbol_t value) {
if (!isValid()) { if (!isValid()) {
return RESULT_ERR_DEVICE; return RESULT_ERR_DEVICE;
} }
@@ -111,7 +111,7 @@ result_t Device::send(const symbol_t value) {
return RESULT_OK; return RESULT_OK;
} }
result_t Device::recv(const unsigned int timeout, symbol_t& value) { result_t Device::recv(unsigned int timeout, symbol_t* value) {
if (!isValid()) { if (!isValid()) {
return RESULT_ERR_DEVICE; return RESULT_ERR_DEVICE;
} }
@@ -162,7 +162,7 @@ result_t Device::recv(const unsigned int timeout, symbol_t& value) {
return RESULT_ERR_DEVICE; return RESULT_ERR_DEVICE;
} }
if (m_listener != NULL) { if (m_listener != NULL) {
m_listener->notifyDeviceData(value, true); m_listener->notifyDeviceData(*value, true);
} }
return RESULT_OK; return RESULT_OK;
} }
@@ -299,14 +299,14 @@ bool NetworkDevice::available() {
return m_buffer && m_bufLen > 0; return m_buffer && m_bufLen > 0;
} }
ssize_t NetworkDevice::write(const symbol_t value) { ssize_t NetworkDevice::write(symbol_t value) {
m_bufLen = 0; // flush read buffer m_bufLen = 0; // flush read buffer
return Device::write(value); return Device::write(value);
} }
ssize_t NetworkDevice::read(symbol_t& value) { ssize_t NetworkDevice::read(symbol_t* value) {
if (available()) { if (available()) {
value = m_buffer[m_bufPos]; *value = m_buffer[m_bufPos];
m_bufPos = (m_bufPos+1)%m_bufSize; m_bufPos = (m_bufPos+1)%m_bufSize;
m_bufLen--; m_bufLen--;
return 1; return 1;
@@ -316,7 +316,7 @@ ssize_t NetworkDevice::read(symbol_t& value) {
if (size <= 0) { if (size <= 0) {
return size; return size;
} }
value = m_buffer[0]; *value = m_buffer[0];
m_bufPos = 1; m_bufPos = 1;
m_bufLen = size-1; m_bufLen = size-1;
return size; return size;
+13 -13
View File
@@ -54,7 +54,7 @@ class DeviceListener {
* @param symbol the received/sent symbol. * @param symbol the received/sent symbol.
* @param received @a true on reception, @a false on sending. * @param received @a true on reception, @a false on sending.
*/ */
virtual void notifyDeviceData(const symbol_t symbol, bool received) = 0; // abstract virtual void notifyDeviceData(symbol_t symbol, bool received) = 0; // abstract
}; };
@@ -70,7 +70,7 @@ class Device {
* @param readOnly whether to allow read access to the device only. * @param readOnly whether to allow read access to the device only.
* @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param initialSend whether to send an initial @a ESC symbol in @a open().
*/ */
Device(const char* name, const bool checkDevice, const bool readOnly, const bool initialSend) Device(const char* name, bool checkDevice, bool readOnly, bool initialSend)
: m_name(name), m_checkDevice(checkDevice), m_readOnly(readOnly), m_initialSend(initialSend), m_fd(-1), : m_name(name), m_checkDevice(checkDevice), m_readOnly(readOnly), m_initialSend(initialSend), m_fd(-1),
m_listener(NULL) {} m_listener(NULL) {}
@@ -88,8 +88,8 @@ class Device {
* @return the new @a Device, or NULL on error. * @return the new @a Device, or NULL on error.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, static Device* create(const char* name, bool checkDevice = true, bool readOnly = false,
const bool initialSend = false); bool initialSend = false);
/** /**
* Get the transfer latency of this device. * Get the transfer latency of this device.
@@ -113,7 +113,7 @@ class Device {
* @param value the byte value to write. * @param value the byte value to write.
* @return the @a result_t code. * @return the @a result_t code.
*/ */
result_t send(const symbol_t value); result_t send(symbol_t value);
/** /**
* Read a single byte from the device. * Read a single byte from the device.
@@ -121,7 +121,7 @@ class Device {
* @param value the reference in which the received byte value is stored. * @param value the reference in which the received byte value is stored.
* @return the result_t code. * @return the result_t code.
*/ */
result_t recv(const unsigned int timeout, symbol_t& value); result_t recv(unsigned int timeout, symbol_t* value);
/** /**
* Return the device name. * Return the device name.
@@ -165,14 +165,14 @@ class Device {
* @param value the byte value to write. * @param value the byte value to write.
* @return the number of bytes written, or -1 on error. * @return the number of bytes written, or -1 on error.
*/ */
virtual ssize_t write(const symbol_t value) { return ::write(m_fd, &value, 1); } virtual ssize_t write(symbol_t value) { return ::write(m_fd, &value, 1); }
/** /**
* Read a single byte. * Read a single byte.
* @param value the reference in which the read byte value is stored. * @param value the reference in which the read byte value is stored.
* @return the number of bytes read, or -1 on error. * @return the number of bytes read, or -1 on error.
*/ */
virtual ssize_t read(symbol_t& value) { return ::read(m_fd, &value, 1); } virtual ssize_t read(symbol_t* value) { return ::read(m_fd, value, 1); }
/** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */ /** the device name (e.g. "/dev/ttyUSB0" for serial, "127.0.0.1:1234" for network). */
const char* m_name; const char* m_name;
@@ -207,7 +207,7 @@ class SerialDevice : public Device {
* @param readOnly whether to allow read access to the device only. * @param readOnly whether to allow read access to the device only.
* @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param initialSend whether to send an initial @a ESC symbol in @a open().
*/ */
SerialDevice(const char* name, const bool checkDevice, const bool readOnly, const bool initialSend) SerialDevice(const char* name, bool checkDevice, bool readOnly, bool initialSend)
: Device(name, checkDevice, readOnly, initialSend) {} : Device(name, checkDevice, readOnly, initialSend) {}
// @copydoc // @copydoc
@@ -240,8 +240,8 @@ class NetworkDevice : public Device {
* @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param initialSend whether to send an initial @a ESC symbol in @a open().
* @param udp true for UDP, false to TCP. * @param udp true for UDP, false to TCP.
*/ */
NetworkDevice(const char* name, const struct sockaddr_in address, const bool readOnly, const bool initialSend, NetworkDevice(const char* name, const struct sockaddr_in& address, bool readOnly, bool initialSend,
const bool udp) bool udp)
: Device(name, true, readOnly, initialSend), m_address(address), m_udp(udp), : Device(name, true, readOnly, initialSend), m_address(address), m_udp(udp),
m_buffer(NULL), m_bufSize(0), m_bufLen(0), m_bufPos(0) {} m_buffer(NULL), m_bufSize(0), m_bufLen(0), m_bufPos(0) {}
@@ -269,10 +269,10 @@ class NetworkDevice : public Device {
bool available() override; bool available() override;
// @copydoc // @copydoc
ssize_t write(const symbol_t value) override; ssize_t write(symbol_t value) override;
// @copydoc // @copydoc
ssize_t read(symbol_t& value) override; ssize_t read(symbol_t* value) override;
private: private:
+91 -80
View File
@@ -36,21 +36,21 @@ using std::setw;
using std::dec; using std::dec;
result_t FileReader::readFromFile(const string filename, string& errorDescription, bool verbose, result_t FileReader::readFromFile(const string& filename, bool verbose, map<string, string>* defaults,
map<string, string>* defaults, size_t* hash, size_t* size, 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 RESULT_ERR_NOTFOUND;
} }
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 RESULT_ERR_NOTFOUND;
} }
ifstream ifs; ifstream stream;
ifs.open(filename.c_str(), ifstream::in); stream.open(filename.c_str(), ifstream::in);
if (!ifs.is_open()) { if (!stream.is_open()) {
errorDescription = filename; *errorDescription = filename;
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
if (hash) { if (hash) {
@@ -65,60 +65,56 @@ result_t FileReader::readFromFile(const string filename, string& errorDescriptio
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 (ifs.peek() != EOF && result == RESULT_OK) { while (stream.peek() != EOF && result == RESULT_OK) {
result = readLineFromStream(ifs, errorDescription, filename, lineNo, row, verbose, hash, size); result = readLineFromStream(filename, verbose, &stream, &lineNo, &row, errorDescription, hash, size);
} }
ifs.close(); stream.close();
return result; return result;
} }
result_t FileReader::readLineFromStream(istream& stream, string& errorDescription, result_t FileReader::readLineFromStream(const string& filename, bool verbose, istream* stream,
const string filename, unsigned int& lineNo, vector<string>& row, bool verbose, unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size) {
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)) {
errorDescription = "blank line"; *errorDescription = "blank line";
result = RESULT_ERR_EOF; result = RESULT_ERR_EOF;
} else { } else {
errorDescription = ""; *errorDescription = "";
result = addFromFile(row, errorDescription, filename, lineNo); result = addFromFile(filename, *lineNo, row, errorDescription);
} }
if (result != RESULT_OK) { if (result != RESULT_OK) {
if (!verbose) { if (!errorDescription->empty()) {
ostringstream error; string error;
error << filename << ":" << lineNo; formatError(filename, *lineNo, result, *errorDescription, &error);
if (errorDescription.length() > 0) { *errorDescription = error;
error << ": " << errorDescription; if (verbose) {
} cout << error << endl;
errorDescription = error.str();
return result;
}
if (!errorDescription.empty()) {
cout << "error reading " << filename << ":" << lineNo << ": " << getResultCode(result) << ", "
<< errorDescription << endl;
} }
} else if (!verbose) { } else if (!verbose) {
errorDescription = ""; return formatError(filename, *lineNo, result, "", errorDescription);
}
} else if (!verbose) {
*errorDescription = "";
} }
return result; return result;
} }
void FileReader::trim(string& str) { void FileReader::trim(string* str) {
size_t pos = str.find_first_not_of(" \t"); size_t pos = str->find_first_not_of(" \t");
if (pos != string::npos) { if (pos != string::npos) {
str.erase(0, pos); str->erase(0, pos);
} }
pos = str.find_last_not_of(" \t"); pos = str->find_last_not_of(" \t");
if (pos != string::npos) { if (pos != string::npos) {
str.erase(pos+1); str->erase(pos+1);
} }
} }
void FileReader::tolower(string& str) { void FileReader::tolower(string* str) {
transform(str.begin(), str.end(), str.begin(), ::tolower); transform(str->begin(), str->end(), str->begin(), ::tolower);
} }
static size_t hashFunction(const string str) { static size_t hashFunction(const string& str) {
size_t hash = 0; size_t hash = 0;
for (char c : str) { for (char c : str) {
hash = (31 * hash) ^ c; hash = (31 * hash) ^ c;
@@ -126,27 +122,27 @@ static size_t hashFunction(const string str) {
return hash; return hash;
} }
bool FileReader::splitFields(istream& ifs, vector<string>& row, unsigned int& lineNo, bool FileReader::splitFields(istream* stream, vector<string>* row, unsigned int* lineNo,
size_t* hash, size_t* size) { size_t* hash, size_t* size) {
row.clear(); row->clear();
string line; string line;
bool quotedText = false, wasQuoted = false; bool quotedText = false, wasQuoted = false;
ostringstream field; ostringstream field;
char prev = FIELD_SEPARATOR; char prev = FIELD_SEPARATOR;
bool empty = true, read = false; bool empty = true, read = false;
while (getline(ifs, line)) { while (getline(*stream, line)) {
read = true; read = true;
lineNo++; ++(*lineNo);
trim(line); trim(&line);
size_t length = line.size(); size_t length = line.size();
if (size) { if (size) {
*size += length + 1; // normalized with trailing endl *size += length + 1; // normalized with trailing endl
} }
if (hash) { if (hash) {
*hash ^= (hashFunction(line) ^ (length << (7 * (lineNo % 5)))) & 0xffffffff; *hash ^= (hashFunction(line) ^ (length << (7 * (*lineNo % 5)))) & 0xffffffff;
} }
if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) { if (!quotedText && (length == 0 || line[0] == '#' || (line.length() > 1 && line[0] == '/' && line[1] == '/'))) {
if (lineNo == 1) { if (*lineNo == 1) {
break; // keep empty first line for applying default header break; // keep empty first line for applying default header
} }
continue; // skip empty lines and comments continue; // skip empty lines and comments
@@ -159,9 +155,9 @@ bool FileReader::splitFields(istream& ifs, vector<string>& row, unsigned int& li
field << ch; field << ch;
} else { } else {
string str = field.str(); string str = field.str();
trim(str); trim(&str);
empty &= str.empty(); empty &= str.empty();
row.push_back(str); row->push_back(str);
field.str(""); field.str("");
wasQuoted = false; wasQuoted = false;
} }
@@ -197,37 +193,52 @@ bool FileReader::splitFields(istream& ifs, vector<string>& row, unsigned int& li
} }
} }
string str = field.str(); string str = field.str();
trim(str); trim(&str);
if (empty && str.empty()) { if (empty && str.empty()) {
row.clear(); row->clear();
return read; return read;
} }
row.push_back(str); row->push_back(str);
return true; return true;
} }
result_t FileReader::formatError(const string& filename, unsigned int lineNo, result_t result,
string MappedFileReader::normalizeLanguage(string lang) { const string& error, string* errorDescription) {
tolower(lang); ostringstream str;
if (lang.size() > 2) { if (!errorDescription->empty()) {
size_t pos = lang.find('.'); str << *errorDescription << ", ";
if (pos == string::npos) {
pos = lang.size();
} }
size_t strip = lang.find('_'); str << filename << ":" << static_cast<unsigned>(lineNo) << ": " << getResultCode(result);
if (!error.empty()) {
str << ", " << error;
}
*errorDescription = str.str();
return result;
}
const string MappedFileReader::normalizeLanguage(const string& lang) {
string normLang = lang;
tolower(&normLang);
if (normLang.size() > 2) {
size_t pos = normLang.find('.');
if (pos == string::npos) {
pos = normLang.size();
}
size_t strip = normLang.find('_');
if (strip == string::npos || strip > pos) { if (strip == string::npos || strip > pos) {
strip = pos; strip = pos;
} }
if (strip > 2) { if (strip > 2) {
strip = 2; strip = 2;
} }
lang = lang.substr(0, strip); return normLang.substr(0, strip);
} }
return lang; return normLang;
} }
result_t MappedFileReader::readFromFile(const string filename, string& errorDescription, bool verbose, result_t MappedFileReader::readFromFile(const string& filename, bool verbose, map<string, string>* defaults,
map<string, string>* defaults, size_t* hash, size_t* size, time_t* time) { string* errorDescription, size_t* hash, size_t* size, time_t* time) {
m_mutex.lock(); m_mutex.lock();
m_columnNames.clear(); m_columnNames.clear();
m_lastDefaults.clear(); m_lastDefaults.clear();
@@ -237,47 +248,47 @@ result_t MappedFileReader::readFromFile(const string filename, string& errorDesc
} }
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[""]); extractDefaultsFromFilename(defaultsPart, &m_lastDefaults[""], NULL, NULL, NULL);
result_t result = FileReader::readFromFile(filename, errorDescription, verbose, defaults, hash, size, time); result_t result = FileReader::readFromFile(filename, verbose, defaults, errorDescription, hash, size, time);
m_mutex.unlock(); m_mutex.unlock();
return result; return result;
} }
result_t MappedFileReader::addFromFile(vector<string>& row, string& errorDescription, result_t MappedFileReader::addFromFile(const string& filename, unsigned int lineNo, vector<string>* row,
const string filename, unsigned int lineNo) { string* errorDescription) {
result_t result; result_t result;
if (lineNo == 1) { // first line defines column names if (lineNo == 1) { // first line defines column names
result = getFieldMap(row, errorDescription, m_preferLanguage); result = getFieldMap(m_preferLanguage, row, errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
if (row.empty()) { if (row->empty()) {
errorDescription = "missing field map"; *errorDescription = "missing field map";
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
} }
m_columnNames = row; m_columnNames = *row;
return RESULT_OK; return RESULT_OK;
} }
if (row.empty()) { if (row->empty()) {
return RESULT_OK; return RESULT_OK;
} }
if (m_columnNames.empty()) { if (m_columnNames.empty()) {
errorDescription = "missing field map"; *errorDescription = "missing field map";
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
map<string, string> rowMapped; map<string, string> rowMapped;
vector< map<string, string> > subRowsMapped; vector< map<string, string> > subRowsMapped;
bool isDefault = m_supportsDefaults && !row[0].empty() && row[0][0] == '*'; bool isDefault = m_supportsDefaults && !(*row)[0].empty() && (*row)[0][0] == '*';
if (isDefault) { if (isDefault) {
row[0] = row[0].substr(1); (*row)[0].erase(0, 1);
} }
size_t lastRepeatStart = UINT_MAX; size_t lastRepeatStart = UINT_MAX;
map<string, string>* lastMappedRow = &rowMapped; map<string, string>* lastMappedRow = &rowMapped;
bool empty = true; bool empty = true;
for (size_t colIdx = 0, colNameIdx = 0; colIdx < row.size(); colIdx++, colNameIdx++) { for (size_t colIdx = 0, colNameIdx = 0; colIdx < row->size(); colIdx++, colNameIdx++) {
if (colNameIdx >= m_columnNames.size()) { if (colNameIdx >= m_columnNames.size()) {
if (lastRepeatStart == UINT_MAX) { if (lastRepeatStart == UINT_MAX) {
errorDescription = "named columns exceeded"; *errorDescription = "named columns exceeded";
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
colNameIdx = lastRepeatStart; colNameIdx = lastRepeatStart;
@@ -297,7 +308,7 @@ result_t MappedFileReader::addFromFile(vector<string>& row, string& errorDescrip
} else if (columnName == SKIP_COLUMN) { } else if (columnName == SKIP_COLUMN) {
continue; continue;
} }
string value = row[colIdx]; string value = (*row)[colIdx];
empty &= value.empty(); empty &= value.empty();
(*lastMappedRow)[columnName] = value; (*lastMappedRow)[columnName] = value;
} }
@@ -308,12 +319,12 @@ result_t MappedFileReader::addFromFile(vector<string>& row, string& errorDescrip
} }
} }
if (isDefault) { if (isDefault) {
return addDefaultFromFile(rowMapped, subRowsMapped, errorDescription, filename, lineNo); return addDefaultFromFile(filename, lineNo, &rowMapped, &subRowsMapped, errorDescription);
} }
return addFromFile(rowMapped, subRowsMapped, errorDescription, filename, lineNo); return addFromFile(filename, lineNo, &rowMapped, &subRowsMapped, errorDescription);
} }
string MappedFileReader::combineRow(const map<string, string>& row) { const string MappedFileReader::combineRow(const map<string, string>& row) {
ostringstream ostream; ostringstream ostream;
bool first = true; bool first = true;
for (auto entry : row) { for (auto entry : row) {
+50 -38
View File
@@ -79,76 +79,88 @@ class FileReader {
/** /**
* Read the definitions from a file. * Read the definitions from a file.
* @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 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 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. * @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, string& errorDescription, bool verbose = false, virtual result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults,
map<string, string>* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL); string* errorDescription, size_t* hash, size_t* size, time_t* time);
/** /**
* 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 errorDescription a string in which to store the error description in case of error.
* @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 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 verbose whether to verbosely log problems. * @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 updating with the hash of the line, or NULL. * @param hash optional pointer to a @a size_t value for updating with the hash 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. * @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(istream& stream, string& errorDescription, virtual result_t readLineFromStream(const string& filename, bool verbose, istream* stream,
const string filename, unsigned int& lineNo, vector<string>& row, bool verbose = false, unsigned int* lineNo, vector<string>* row, string* errorDescription, size_t* hash, size_t* size);
size_t* hash = NULL, size_t* size = NULL);
/** /**
* Add a definition that was read from a file. * Add a definition that was read from a file.
* @param row the definition row.
* @param errorDescription a string in which to store the error description in case of error.
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param lineNo the current line number in the file being read. * @param lineNo the current line number in the file being read.
* @param row the definition row (allowed to be modified).
* @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. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t addFromFile(vector<string>& row, string& errorDescription, virtual result_t addFromFile(const string& filename, unsigned int lineNo, vector<string>* row,
const string filename, unsigned int lineNo) = 0; string* errorDescription) = 0;
/** /**
* Left and right trim the string. * Left and right trim the string.
* @param str the @a string to trim. * @param str the @a string to trim.
*/ */
static void trim(string& str); static void trim(string* str);
/** /**
* Convert all upper case characters in the string to lower case. * Convert all upper case characters in the string to lower case.
* @param str the @a string to convert. * @param str the @a string to convert.
*/ */
static void tolower(string& str); static void tolower(string* str);
/** /**
* Split the next line(s) from the @a istream into fields. * Split the next line(s) from the @a istream into fields.
* @param ifs the @a istream to read from. * @param stream the @a istream to read from.
* @param row the @a vector to which to add the fields. This will be empty for completely empty and comment lines. * @param row the @a vector to which to add the fields. This will be empty for completely empty and comment lines.
* @param lineNo the current line number (incremented with each line read). * @param lineNo the current line number (incremented with each line read).
* @param hash optional pointer to a @a size_t value for combining the hash of the line with, or NULL. * @param hash optional pointer to a @a size_t value for combining the hash of the line with, or NULL.
* @param size optional pointer to a @a size_t value to add the trimmed line length to, or NULL. * @param size optional pointer to a @a size_t value to add the trimmed line length to, or NULL.
* @return true if there are more lines to read, false when there are no more lines left. * @return true if there are more lines to read, false when there are no more lines left.
*/ */
static bool splitFields(istream& ifs, vector<string>& row, unsigned int& lineNo, static bool splitFields(istream* stream, vector<string>* row, unsigned int* lineNo,
size_t* hash = NULL, size_t* size = NULL); size_t* hash = NULL, size_t* size = NULL);
/** /**
* Format the specified hash as 8 hex digits to the output stream. * Format the specified hash as 8 hex digits to the output stream.
* @param hash the hash code. * @param hash the hash code.
* @param str the @a ostream to write to. * @param stream the @a ostream to write to.
*/ */
static void formatHash(size_t hash, ostream& str) { static void formatHash(size_t hash, ostream* stream) {
str << std::hex << std::setw(8) << std::setfill('0') << (hash & 0xffffffff) << std::dec << std::setw(0); *stream << std::hex << std::setw(8) << std::setfill('0') << (hash & 0xffffffff) << std::dec << std::setw(0);
} }
/**
* Format the error description with the input data.
* @param filename the name of the file.
* @param lineNo the line number in the file.
* @param row the definition row.
* @param result the result code.
* @param error the error message.
* @param errorDescription a string in which to store the error description.
* @return the result code.
*/
static result_t formatError(const string& filename, unsigned int lineNo, result_t result,
const string& error, string* errorDescription);
}; };
@@ -163,7 +175,7 @@ class MappedFileReader : public FileReader {
* @param supportsDefaults whether this instance supports rows with defaults (starting with a star). * @param supportsDefaults whether this instance supports rows with defaults (starting with a star).
* @param preferLanguage the preferred language code, or empty. * @param preferLanguage the preferred language code, or empty.
*/ */
explicit MappedFileReader(bool supportsDefaults, const string preferLanguage = "") explicit MappedFileReader(bool supportsDefaults, const string& preferLanguage = "")
: FileReader(), m_supportsDefaults(supportsDefaults), m_preferLanguage(normalizeLanguage(preferLanguage)) { : FileReader(), m_supportsDefaults(supportsDefaults), m_preferLanguage(normalizeLanguage(preferLanguage)) {
} }
@@ -181,11 +193,11 @@ class MappedFileReader : public FileReader {
* @param lang the language string to normalize. * @param lang the language string to normalize.
* @return the normalized language code. * @return the normalized language code.
*/ */
static string normalizeLanguage(string lang); static const string normalizeLanguage(const string& lang);
// @copydoc // @copydoc
result_t readFromFile(const string filename, string& errorDescription, bool verbose = false, result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults,
map<string, string>* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL) override; string* errorDescription, size_t* hash, size_t* size, time_t* time) override;
/** /**
* Extract default values from the file name. * Extract default values from the file name.
@@ -196,14 +208,14 @@ class MappedFileReader : public FileReader {
* @param hardware a pointer to a in which to store the numeric hardware version, or NULL. * @param hardware a 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(string filename, map<string, string>& defaults, virtual bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults,
symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const { symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const {
return false; return false;
} }
// @copydoc // @copydoc
result_t addFromFile(vector<string>& row, string& errorDescription, result_t addFromFile(const string& filename, unsigned int lineNo, vector<string>* row,
const string filename, unsigned int lineNo) override; string* errorDescription) override;
/** /**
* Get the field mapping from the given first line. * Get the field mapping from the given first line.
@@ -214,7 +226,7 @@ class MappedFileReader : public FileReader {
* @param preferLanguage the preferred language code (up to 2 characters), or empty. * @param preferLanguage the preferred language code (up to 2 characters), or empty.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const = 0; virtual result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const = 0;
/** /**
* Add a default row that was read from a file. * Add a default row that was read from a file.
@@ -225,23 +237,23 @@ class MappedFileReader : public FileReader {
* @param lineNo the current line number in the file being read. * @param lineNo the current line number in the file being read.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t addDefaultFromFile(map<string, string>& row, vector< map<string, string> >& subRows, virtual result_t addDefaultFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) { vector< map<string, string> >* subRows, string* errorDescription) {
errorDescription = "defaults not supported"; *errorDescription = "defaults not supported";
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
/** /**
* Add a definition that was read from a file. * Add a definition that was read from a file.
* @param row the main definition row by field name.
* @param subRows the sub definition rows, each by field name.
* @param errorDescription a string in which to store the error description in case of error.
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param lineNo the current line number in the file being read. * @param lineNo the current line number in the file being read.
* @param row the main definition row by field name (may be modified).
* @param subRows the sub definition rows, each by field name (may be modified).
* @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. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, virtual result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) = 0; vector< map<string, string> >* subRows, string* errorDescription) = 0;
/** /**
* @return a reference to all previously extracted default values by type and field name. * @return a reference to all previously extracted default values by type and field name.
@@ -262,7 +274,7 @@ class MappedFileReader : public FileReader {
* @param row the mapped row. * @param row the mapped row.
* @return the combined string. * @return the combined string.
*/ */
static string combineRow(const map<string, string>& row); static const string combineRow(const map<string, string>& row);
private: private:
/** whether this instance supports rows with defaults (starting with a star). */ /** whether this instance supports rows with defaults (starting with a star). */
+434 -429
View File
File diff suppressed because it is too large Load Diff
+165 -180
View File
@@ -92,12 +92,12 @@ class Message : public AttributedItem {
* @param pollPriority the priority for polling, or 0 for no polling at all. * @param pollPriority the priority for polling, or 0 for no polling at all.
* @param condition the @a Condition for this message, or NULL. * @param condition the @a Condition for this message, or NULL.
*/ */
Message(const string circuit, const string level, const string name, Message(const string& circuit, const string& level, const string& name,
const bool isWrite, const bool isPassive, const map<string, string>& attributes, bool isWrite, bool isPassive, const map<string, string>& attributes,
const symbol_t srcAddress, const symbol_t dstAddress, symbol_t srcAddress, symbol_t dstAddress,
const vector<symbol_t> id, const vector<symbol_t>& id,
const DataField* data, const bool deleteData, const DataField* data, bool deleteData,
const size_t pollPriority = 0, size_t pollPriority = 0,
Condition* condition = NULL); Condition* condition = NULL);
@@ -113,9 +113,9 @@ class Message : public AttributedItem {
* @param data the @a DataField for encoding/decoding the message. * @param data the @a DataField for encoding/decoding the message.
* @param deleteData whether to delete the @a DataField during destruction. * @param deleteData whether to delete the @a DataField during destruction.
*/ */
Message(const string circuit, const string level, const string name, Message(const string& circuit, const string& level, const string& name,
const symbol_t pb, const symbol_t sb, symbol_t pb, symbol_t sb,
const bool broadcast, const DataField* data, const bool deleteData); bool broadcast, const DataField* data, bool deleteData);
public: public:
@@ -134,9 +134,8 @@ class Message : public AttributedItem {
* @param dstAddress the destination address, or @a SYN for any (set later). * @param dstAddress the destination address, or @a SYN for any (set later).
* @return the key for the ID. * @return the key for the ID.
*/ */
static uint64_t createKey(const vector<symbol_t> id, static uint64_t createKey(const vector<symbol_t>& id, bool isWrite, bool isPassive, symbol_t srcAddress,
const bool isWrite, const bool isPassive, symbol_t dstAddress);
const symbol_t srcAddress, const symbol_t dstAddress);
/** /**
* Calculate the key for the @a MasterSymbolString. * Calculate the key for the @a MasterSymbolString.
@@ -154,7 +153,7 @@ class Message : public AttributedItem {
* @param broadcast true for broadcast scan message, false for scan message to be sent to a slave address. * @param broadcast true for broadcast scan message, false for scan message to be sent to a slave address.
* @return the key for the scan message. * @return the key for the scan message.
*/ */
static uint64_t createKey(const symbol_t pb, const symbol_t sb, const bool broadcast); static uint64_t createKey(symbol_t pb, symbol_t sb, bool broadcast);
/** /**
* Get the length field from the key. * Get the length field from the key.
@@ -169,26 +168,29 @@ class Message : public AttributedItem {
* @param id the vector to which to add the parsed values. * @param id the vector to which to add the parsed values.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
static result_t parseId(string input, vector<symbol_t>& id); static result_t parseId(const string& input, vector<symbol_t>* id);
/** /**
* Factory method for creating new instances. * Factory method for creating new instances.
* @param row the mapped message definition row.
* @param subRows the mapped field definition rows.
* @param rowDefaults the mapped message definition defaults.
* @param subRowDefaults the mapped field definition defaults.
* @param errorDescription a string in which to store the error description in case of error.
* @param condition the @a Condition instance for the message, or NULL.
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param templates the @a DataFieldTemplates to be referenced by name, or NULL. * @param templates the @a DataFieldTemplates to be referenced by name, or NULL.
* @param rowDefaults the mapped message definition defaults.
* @param subRowDefaults the mapped field definition defaults.
* @param typeStr the single type of message to create.
* @param condition the @a Condition instance for the message, or NULL.
* @param row the mapped message definition row (may be modified).
* @param subRows the mapped field definition rows (may be modified).
* @param errorDescription a string in which to store the error description in case of error.
* @param messages the @a vector to which to add created instances. * @param messages the @a vector to which to add created instances.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller needs to free the created instances. * Note: the caller needs to free the created instances.
*/ */
static result_t create(map<string, string> row, vector< map<string, string> > subRows, static result_t create(const string& filename, const DataFieldTemplates* templates,
map<string, map<string, string> >& rowDefaults, map<string, vector< map<string, string> > >& subRowDefaults, const map<string, map<string, string> >& rowDefaults,
string& errorDescription, Condition* condition, const string filename, DataFieldTemplates* templates, const map<string, vector< map<string, string> > >& subRowDefaults,
vector<Message*>& messages); const string& typeStr, Condition* condition,
map<string, string>* row, vector< map<string, string> >* subRows,
string* errorDescription, vector<Message*>* messages);
/** /**
* Create a new scan @a Message instance. * Create a new scan @a Message instance.
@@ -200,11 +202,11 @@ class Message : public AttributedItem {
/** /**
* Extract the known field names from the input string. * Extract the known field names from the input string.
* @param str the input string with the field names separated by @a FIELD_SEPARATOR. * @param str the input string with the field names separated by @a FIELD_SEPARATOR.
* @param fields the vector to update with the extracted normalized field names with.
* @param checkAbbreviated true to also check for abbreviated field names. * @param checkAbbreviated true to also check for abbreviated field names.
* @param fields the vector to update with the extracted normalized field names with.
* @return true when all fields are valid. * @return true when all fields are valid.
*/ */
static bool extractFieldNames(string str, vector<string>& fields, bool checkAbbreviated = true); static bool extractFieldNames(const string& str, bool checkAbbreviated, vector<string>* fields);
/** /**
* Set that this is a special scanning @a Message instance. * Set that this is a special scanning @a Message instance.
@@ -224,8 +226,7 @@ class Message : public AttributedItem {
* @param circuit the new circuit name, or empty to use the current circuit name. * @param circuit the new circuit name, or empty to use the current circuit name.
* @return the derived @a Message instance. * @return the derived @a Message instance.
*/ */
virtual Message* derive(const symbol_t dstAddress, const symbol_t srcAddress = SYN, virtual Message* derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const;
const string circuit = "") const;
/** /**
* Derive a new @a Message from this message. * Derive a new @a Message from this message.
@@ -233,7 +234,7 @@ class Message : public AttributedItem {
* @param extendCircuit whether to extend the current circuit name with a dot and the new destination address in hex. * @param extendCircuit whether to extend the current circuit name with a dot and the new destination address in hex.
* @return the derived @a ScanMessage instance. * @return the derived @a ScanMessage instance.
*/ */
Message* derive(const symbol_t dstAddress, const bool extendCircuit) const; Message* derive(symbol_t dstAddress, bool extendCircuit) const;
/** /**
* Get the optional circuit name. * Get the optional circuit name.
@@ -254,7 +255,7 @@ class Message : public AttributedItem {
* level to check. * level to check.
* @return true when access is granted. * @return true when access is granted.
*/ */
bool hasLevel(const string levels, bool includeEmpty = true) const { bool hasLevel(const string& levels, bool includeEmpty = true) const {
return m_level.empty() ? (includeEmpty || levels.empty()) : checkLevel(m_level, levels); return m_level.empty() ? (includeEmpty || levels.empty()) : checkLevel(m_level, levels);
} }
@@ -264,14 +265,14 @@ class Message : public AttributedItem {
* @param checkLevels the access levels to check against, separated by semicolon. * @param checkLevels the access levels to check against, separated by semicolon.
* @return whether the access level matches. * @return whether the access level matches.
*/ */
static bool checkLevel(const string level, const string checkLevels); static bool checkLevel(const string& level, const string& checkLevels);
/** /**
* Get the specified field name. * Get the specified field name.
* @param fieldIndex the index of the field. * @param fieldIndex the index of the field.
* @return the field name, or the index as string if not unique or not available. * @return the field name, or the index as string if not unique or not available.
*/ */
virtual string getFieldName(const ssize_t fieldIndex) const { return m_data->getName(fieldIndex); } virtual string getFieldName(ssize_t fieldIndex) const { return m_data->getName(fieldIndex); }
/** /**
* Get whether this is a write message. * Get whether this is a write message.
@@ -329,14 +330,14 @@ class Message : public AttributedItem {
* @param index the variable in which to store the message part index, or NULL to ignore. * @param index the variable in which to store the message part index, or NULL to ignore.
* @return true if the ID matches, false otherwise. * @return true if the ID matches, false otherwise.
*/ */
virtual bool checkId(const MasterSymbolString& master, size_t* index = NULL) const; virtual bool checkId(const MasterSymbolString& master, size_t* index) const;
/** /**
* Check the ID against the other @a Message. * Check the ID against the other @a Message.
* @param other the other @a Message to check against. * @param other the other @a Message to check against.
* @return true if the ID matches, false otherwise. * @return true if the ID matches, false otherwise.
*/ */
virtual bool checkId(Message& other) const; virtual bool checkId(const Message& other) const;
/** /**
* Return the key for storing in @a MessageMap. * Return the key for storing in @a MessageMap.
@@ -349,7 +350,7 @@ class Message : public AttributedItem {
* @param dstAddress the destination address for the derivation. * @param dstAddress the destination address for the derivation.
* @return the derived key for storing in @a MessageMap. * @return the derived key for storing in @a MessageMap.
*/ */
uint64_t getDerivedKey(const symbol_t dstAddress) const; uint64_t getDerivedKey(symbol_t dstAddress) const;
/** /**
* Get the polling priority, or 0 for no polling at all. * Get the polling priority, or 0 for no polling at all.
@@ -362,7 +363,7 @@ class Message : public AttributedItem {
* @param priority the polling priority, or 0 for no polling at all. * @param priority the polling priority, or 0 for no polling at all.
* @return true when the priority was changed and polling was not enabled before, false otherwise. * @return true when the priority was changed and polling was not enabled before, false otherwise.
*/ */
bool setPollPriority(size_t priority); bool setPollPriority(const size_t priority);
/** /**
* Set the poll priority suitable for resolving a @a Condition. * Set the poll priority suitable for resolving a @a Condition.
@@ -396,30 +397,28 @@ class Message : public AttributedItem {
/** /**
* Prepare the master @a SymbolString for sending a query or command to the bus. * Prepare the master @a SymbolString for sending a query or command to the bus.
* @param srcAddress the source address to set.
* @param master the @a MasterSymbolString for writing symbols to.
* @param input the @a istringstream to parse the formatted value(s) from.
* @param separator the separator character between multiple fields.
* @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction.
* @param index the index of the part to prepare. * @param index the index of the part to prepare.
* @param srcAddress the source address to set.
* @param dstAddress the destination address to set, or @a SYN to keep the address defined during construction.
* @param separator the separator character between multiple fields (e.g. @a UI_FIELD_SEPARATOR).
* @param input the @a istringstream to parse the formatted value(s) from.
* @param master the @a MasterSymbolString for writing symbols to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t prepareMaster(const symbol_t srcAddress, MasterSymbolString& master, result_t prepareMaster(size_t index, symbol_t srcAddress, symbol_t dstAddress,
istringstream& input, char separator = UI_FIELD_SEPARATOR, char separator, istringstream* input, MasterSymbolString* master);
const symbol_t dstAddress = SYN, size_t index = 0);
protected: protected:
/** /**
* Prepare a part of the master data @a SymbolString for sending (everything including NN). * Prepare a part of the master data @a SymbolString for sending (everything including NN).
* @param master the @a MasterSymbolString for writing symbols to.
* @param input the @a istringstream to parse the formatted value(s) from.
* @param separator the separator character between multiple fields.
* @param index the index of the part to prepare. * @param index the index of the part to prepare.
* @param separator the separator character between multiple fields.
* @param input the @a istringstream to parse the formatted value(s) from.
* @param master the @a MasterSymbolString for writing symbols to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, virtual result_t prepareMasterPart(size_t index, char separator, istringstream* input, MasterSymbolString* master);
size_t index);
public: public:
@@ -429,7 +428,7 @@ class Message : public AttributedItem {
* @param slave the @a SlaveSymbolString for writing symbols to. * @param slave the @a SlaveSymbolString for writing symbols to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t prepareSlave(istringstream& input, SlaveSymbolString& slave); virtual result_t prepareSlave(istringstream* input, SlaveSymbolString* slave);
/** /**
* Store the last seen master and slave data. * Store the last seen master and slave data.
@@ -437,68 +436,57 @@ class Message : public AttributedItem {
* @param slave the last seen @a SlaveSymbolString. * @param slave the last seen @a SlaveSymbolString.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t storeLastData(MasterSymbolString& master, SlaveSymbolString& slave); virtual result_t storeLastData(const MasterSymbolString& master, const SlaveSymbolString& slave);
/** /**
* Store last seen master data. * Store last seen master data.
* @param data the last @a MasterSymbolString.
* @param index the index of the part to store. * @param index the index of the part to store.
* @param data the last @a MasterSymbolString.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t storeLastData(MasterSymbolString& data, size_t index); virtual result_t storeLastData(size_t index, const MasterSymbolString& data);
/** /**
* Store last seen slave data. * Store last seen slave data.
* @param data the last seen @a SlaveSymbolString.
* @param index the index of the part to store. * @param index the index of the part to store.
* @param data the last seen @a SlaveSymbolString.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t storeLastData(SlaveSymbolString& data, size_t index); virtual result_t storeLastData(size_t index, const SlaveSymbolString& data);
/** /**
* Decode the value from the last stored master data. * Decode the value from the last stored master or slave data.
* @param output the @a ostringstream to append the formatted value to. * @param master true for deocding the master data, false for slave.
* @param outputFormat the @a OutputFormat options to use.
* @param leadingSeparator whether to prepend a separator before the formatted value. * @param leadingSeparator whether to prepend a separator before the formatted value.
* @param fieldName the optional name of a field to limit the output to. * @param fieldName the optional name of a field to limit the output to.
* @param fieldIndex the optional index of the named field to limit the output to, or -1. * @param fieldIndex the optional index of the named field to limit the output to, or -1.
* @param outputFormat the @a OutputFormat options to use.
* @param output the @a ostream to append the formatted value to.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastMasterData(ostringstream& output, OutputFormat outputFormat = 0, virtual result_t decodeLastData(bool master, bool leadingSeparator, const char* fieldName,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const; ssize_t fieldIndex, OutputFormat outputFormat, ostream* output) const;
/** /**
* Decode the value from the last stored slave data. * Decode the value from the last stored master and slave data.
* @param output the @a ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use.
* @param leadingSeparator whether to prepend a separator before the formatted value. * @param leadingSeparator whether to prepend a separator before the formatted value.
* @param fieldName the optional name of a field to limit the output to. * @param fieldName the optional name of a field to limit the output to.
* @param fieldIndex the optional index of the named field to limit the output to, or -1. * @param fieldIndex the optional index of the named field to limit the output to, or -1.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t decodeLastSlaveData(ostringstream& output, OutputFormat outputFormat = 0,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const;
/**
* Decode the value from the last stored data.
* @param output the @a ostringstream to append the formatted value to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param leadingSeparator whether to prepend a separator before the formatted value. * @param output the @a ostream to append the formatted value to.
* @param fieldName the optional name of a field to limit the output to.
* @param fieldIndex the optional index of the named field to limit the output to, or -1.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat = 0, virtual result_t decodeLastData(bool leadingSeparator, const char* fieldName,
bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const; ssize_t fieldIndex, OutputFormat outputFormat, ostream* output) const;
/** /**
* Decode a particular numeric field value from the last stored data. * Decode a particular numeric field value from the last stored data.
* @param output the variable in which to store the value.
* @param fieldName the name of the field to decode, or NULL for the first field. * @param fieldName the name of the field to decode, or NULL for the first field.
* @param fieldIndex the optional index of the named field, or -1. * @param fieldIndex the optional index of the named field, or -1.
* @param output the variable in which to store the value.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t decodeLastDataNumField(unsigned int& output, const char* fieldName, ssize_t fieldIndex = -1) const; virtual result_t decodeLastDataNumField(const char* fieldName, ssize_t fieldIndex, unsigned int* output) const;
/** /**
* Get the last seen master data. * Get the last seen master data.
@@ -539,36 +527,36 @@ class Message : public AttributedItem {
/** /**
* Write the message definition header or parts of it to the @a ostream. * Write the message definition header or parts of it to the @a ostream.
* @param output the @a ostream to append the formatted value to.
* @param fieldNames the list of field names to write, or NULL for all. * @param fieldNames the list of field names to write, or NULL for all.
* @param output the @a ostream to append the formatted value to.
*/ */
static void dumpHeader(ostream& output, vector<string>* fieldNames = NULL); static void dumpHeader(const vector<string>* fieldNames, ostream* output);
/** /**
* Write the message definition or parts of it to the @a ostream. * Write the message definition or parts of it to the @a ostream.
* @param output the @a ostream to append the formatted value to.
* @param fieldNames the list of field names to write, or NULL for all. * @param fieldNames the list of field names to write, or NULL for all.
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
* @param output the @a ostream to append the formatted value to.
*/ */
void dump(ostream& output, vector<string>* fieldNames = NULL, bool withConditions = false) const; void dump(const vector<string>* fieldNames, bool withConditions, ostream* output) const;
/** /**
* Write the specified field to the @a ostream. * Write the specified field to the @a ostream.
* @param output the @a ostream to append the formatted value to.
* @param fieldName the field name to write. * @param fieldName the field name to write.
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
* @param output the @a ostream to append the formatted value to.
*/ */
virtual void dumpField(ostream& output, string fieldName, bool withConditions = false) const; virtual void dumpField(const string& fieldName, bool withConditions, ostream* output) const;
/** /**
* Decode the message from the last stored data. * Decode the message from the last stored data.
* @param output the @a ostringstream to append the decoded value(s) to.
* @param outputFormat the @a OutputFormat options to use.
* @param leadingSeparator whether to prepend a separator before the first value. * @param leadingSeparator whether to prepend a separator before the first value.
* @param fields the list of message and/or data field fields to write, or NULL for all. * @param fields the list of message and/or data field fields to write, or NULL for all.
* @param outputFormat the @a OutputFormat options to use.
* @param output the @a ostringstream to append the decoded value(s) to.
*/ */
virtual void decode(ostringstream& output, OutputFormat outputFormat = 0, bool leadingSeparator = false, virtual void decode(bool leadingSeparator, const vector<string>* fields,
vector<string>* fields = NULL) const; OutputFormat outputFormat, ostringstream* output) const;
protected: protected:
/** the optional circuit name. */ /** the optional circuit name. */
@@ -676,29 +664,28 @@ class ChainedMessage : public Message {
* @param pollPriority the priority for polling, or 0 for no polling at all. * @param pollPriority the priority for polling, or 0 for no polling at all.
* @param condition the @a Condition for this message, or NULL. * @param condition the @a Condition for this message, or NULL.
*/ */
ChainedMessage(const string circuit, const string level, const string name, ChainedMessage(const string& circuit, const string& level, const string& name,
const bool isWrite, const map<string, string>& attributes, bool isWrite, const map<string, string>& attributes,
const symbol_t srcAddress, const symbol_t dstAddress, symbol_t srcAddress, symbol_t dstAddress,
const vector<symbol_t> id, const vector<symbol_t>& id,
vector< vector<symbol_t> > ids, vector<size_t> lengths, const vector< vector<symbol_t> >& ids, const vector<size_t>& lengths,
const DataField* data, const bool deleteData, const DataField* data, bool deleteData,
const size_t pollPriority, size_t pollPriority = 0,
Condition* condition = NULL); Condition* condition = NULL);
virtual ~ChainedMessage(); virtual ~ChainedMessage();
// @copydoc // @copydoc
Message* derive(const symbol_t dstAddress, const symbol_t srcAddress = SYN, Message* derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const override;
const string circuit = "") const override;
// @copydoc // @copydoc
size_t getIdLength() const override { return m_ids[0].size() - 2; } size_t getIdLength() const override { return m_ids[0].size() - 2; }
// @copydoc // @copydoc
bool checkId(const MasterSymbolString& master, size_t* index = NULL) const override; bool checkId(const MasterSymbolString& master, size_t* index) const override;
// @copydoc // @copydoc
bool checkId(Message& other) const override; bool checkId(const Message& other) const override;
// @copydoc // @copydoc
size_t getCount() const override { return m_ids.size(); } size_t getCount() const override { return m_ids.size(); }
@@ -706,19 +693,19 @@ class ChainedMessage : public Message {
protected: protected:
// @copydoc // @copydoc
result_t prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, result_t prepareMasterPart(size_t index, const char separator, istringstream* input,
size_t index) override; MasterSymbolString* master) override;
public: public:
// @copydoc // @copydoc
result_t storeLastData(MasterSymbolString& master, SlaveSymbolString& slave) override; result_t storeLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) override;
// @copydoc // @copydoc
result_t storeLastData(MasterSymbolString& data, size_t index) override; result_t storeLastData(size_t index, const MasterSymbolString& data) override;
// @copydoc // @copydoc
result_t storeLastData(SlaveSymbolString& data, size_t index) override; result_t storeLastData(size_t index, const SlaveSymbolString& data) override;
/** /**
* Combine all last stored data. * Combine all last stored data.
@@ -728,7 +715,7 @@ class ChainedMessage : public Message {
protected: protected:
// @copydoc // @copydoc
void dumpField(ostream& output, string fieldName, bool withConditions = false) const override; void dumpField(const string& fieldName, bool withConditions, ostream* output) const override;
private: private:
@@ -810,27 +797,27 @@ class Condition {
/** /**
* Factory method for creating a new instance. * Factory method for creating a new instance.
* @param condName the name of the condition. * @param condName the name of the condition.
* @param row the mapped definition row.
* @param rowDefaults the mapped definition defaults. * @param rowDefaults the mapped definition defaults.
* @param row the mapped definition row.
* @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 condName, map<string, string> row, map<string, string> rowDefaults, static result_t create(const string& condName, const map<string, string>& rowDefaults,
SimpleCondition*& returnValue); map<string, string>* row, SimpleCondition** returnValue);
/** /**
* Derive a new @a SimpleCondition from this condition. * Derive a new @a SimpleCondition from this condition.
* @param valueList the @a string with the new list of values. * @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. * @return the derived @a SimpleCondition instance, or NULL if the value list is invalid.
*/ */
virtual SimpleCondition* derive(string valueList) const { return NULL; } virtual SimpleCondition* derive(const string& valueList) const { return NULL; }
/** /**
* Write the condition definition or resolved expression to the @a ostream. * Write the condition definition or resolved expression to the @a ostream.
* @param output the @a ostream to append to.
* @param matched true for dumping the matched value if the condition is true, false for dumping the definition. * @param matched true for dumping the matched value if the condition is true, false for dumping the definition.
* @param output the @a ostream to append to.
*/ */
virtual void dump(ostream& output, bool matched = false) const = 0; virtual void dump(bool matched, ostream* output) const = 0;
/** /**
* Combine this condition with another instance using a logical and. * Combine this condition with another instance using a logical and.
@@ -842,12 +829,12 @@ class Condition {
/** /**
* Resolve the referred @a Message instance(s) and field index(es). * Resolve the referred @a Message instance(s) and field index(es).
* @param messages the @a MessageMap instance for resolving. * @param messages the @a MessageMap instance for resolving.
* @param errorMessage a @a ostringstream to which to add optional error messages.
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL. * @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @param errorMessage a @a ostringstream to which to add optional error messages.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, virtual result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages,
void (*readMessageFunc)(Message* message) = NULL) = 0; ostringstream* errorMessage) = 0;
/** /**
* Check and return whether this condition is fulfilled. * Check and return whether this condition is fulfilled.
@@ -882,8 +869,8 @@ class SimpleCondition : public Condition {
* @param field the field name. * @param field the field name.
* @param hasValues whether a value has to be checked against. * @param hasValues whether a value has to be checked against.
*/ */
SimpleCondition(const string condName, const string refName, const string circuit, const string level, SimpleCondition(const string& condName, const string& refName, const string& circuit, const string& level,
const string name, const symbol_t dstAddress, const string field, const bool hasValues = false) const string& name, symbol_t dstAddress, const string& field, bool hasValues = false)
: Condition(), : Condition(),
m_condName(condName), m_refName(refName), m_circuit(circuit), m_level(level), m_name(name), m_condName(condName), m_refName(refName), m_circuit(circuit), m_level(level), m_name(name),
m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { } m_dstAddress(dstAddress), m_field(field), m_hasValues(hasValues), m_message(NULL) { }
@@ -894,17 +881,17 @@ class SimpleCondition : public Condition {
virtual ~SimpleCondition() {} virtual ~SimpleCondition() {}
// @copydoc // @copydoc
SimpleCondition* derive(string valueList) const override; SimpleCondition* derive(const string& valueList) const override;
// @copydoc // @copydoc
void dump(ostream& output, bool matched = false) const override; void dump(bool matched, ostream* output) const override;
// @copydoc // @copydoc
CombinedCondition* combineAnd(Condition* other) override; CombinedCondition* combineAnd(Condition* other) override;
// @copydoc // @copydoc
result_t resolve(MessageMap* messages, ostringstream& errorMessage, result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages,
void (*readMessageFunc)(Message* message) = NULL) override; ostringstream* errorMessage) override;
// @copydoc // @copydoc
bool isTrue() override; bool isTrue() override;
@@ -923,7 +910,7 @@ class SimpleCondition : public Condition {
* @param field the field name to check against, or empty for first field. * @param field the field name to check against, or empty for first field.
* @return whether the field matches one of the valid values. * @return whether the field matches one of the valid values.
*/ */
virtual bool checkValue(Message* message, const string field) { return true; } virtual bool checkValue(const Message* message, const string& field) { return true; }
/** the value that matched in @a checkValue. */ /** the value that matched in @a checkValue. */
string m_matchedValue; string m_matchedValue;
@@ -976,8 +963,8 @@ class SimpleNumericCondition : public SimpleCondition {
* @param field the field name. * @param field the field name.
* @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. * @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check.
*/ */
SimpleNumericCondition(const string condName, const string refName, const string circuit, const string level, SimpleNumericCondition(const string& condName, const string& refName, const string& circuit, const string& level,
const string name, const symbol_t dstAddress, const string field, const vector<unsigned int> valueRanges) const string& name, symbol_t dstAddress, const string& field, const vector<unsigned int>& valueRanges)
: SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true), : SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true),
m_valueRanges(valueRanges) { } m_valueRanges(valueRanges) { }
@@ -989,7 +976,7 @@ class SimpleNumericCondition : public SimpleCondition {
protected: protected:
// @copydoc // @copydoc
bool checkValue(Message* message, const string field) override; bool checkValue(const Message* message, const string& field) override;
private: private:
@@ -1014,8 +1001,8 @@ class SimpleStringCondition : public SimpleCondition {
* @param field the field name. * @param field the field name.
* @param values the valid values. * @param values the valid values.
*/ */
SimpleStringCondition(const string condName, const string refName, const string circuit, const string level, SimpleStringCondition(const string& condName, const string& refName, const string& circuit, const string& level,
const string name, const symbol_t dstAddress, const string field, const vector<string> values) const string& name, symbol_t dstAddress, const string& field, const vector<string>& values)
: SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true), : SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true),
m_values(values) { } m_values(values) { }
@@ -1030,7 +1017,7 @@ class SimpleStringCondition : public SimpleCondition {
protected: protected:
// @copydoc // @copydoc
bool checkValue(Message* message, const string field) override; bool checkValue(const Message* message, const string& field) override;
private: private:
@@ -1056,14 +1043,14 @@ class CombinedCondition : public Condition {
virtual ~CombinedCondition() {} virtual ~CombinedCondition() {}
// @copydoc // @copydoc
void dump(ostream& output, bool matched = false) const override; void dump(bool matched, ostream* output) const override;
// @copydoc // @copydoc
CombinedCondition* combineAnd(Condition* other) override { m_conditions.push_back(other); return this; } CombinedCondition* combineAnd(Condition* other) override { m_conditions.push_back(other); return this; }
// @copydoc // @copydoc
result_t resolve(MessageMap* messages, ostringstream& errorMessage, result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages,
void (*readMessageFunc)(Message* message) = NULL) override; ostringstream* errorMessage) override;
// @copydoc // @copydoc
bool isTrue() override; bool isTrue() override;
@@ -1087,7 +1074,7 @@ class Instruction {
* executed for the same source file. * executed for the same source file.
* @param defaults the mapped definition defaults. * @param defaults the mapped definition defaults.
*/ */
Instruction(Condition* condition, const bool singleton, const map<string, string>& defaults) Instruction(bool singleton, const map<string, string>& defaults, Condition* condition)
: m_condition(condition), m_singleton(singleton), m_defaults(defaults) { } : m_condition(condition), m_singleton(singleton), m_defaults(defaults) { }
/** /**
@@ -1105,9 +1092,9 @@ 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& contextPath, const string& type,
Condition* condition, map<string, string>& row, map<string, string>& defaults, Condition* condition, const map<string, string>& row, const map<string, string>& defaults,
Instruction*& returnValue); Instruction** returnValue);
/** /**
* Return the @a Condition this instruction requires. * Return the @a Condition this instruction requires.
@@ -1133,13 +1120,12 @@ class Instruction {
* Execute the instruction. * Execute the instruction.
* @param messages the @a MessageMap. * @param messages the @a MessageMap.
* @param log the @a ostringstream to log success messages to (if necessary). * @param log the @a ostringstream to log success messages to (if necessary).
* @param condition the @a Condition that was successfully evaluated for execution, 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 execute(MessageMap* messages, ostringstream& log, Condition* condition) = 0; virtual result_t execute(MessageMap* messages, ostringstream* log) = 0;
private: protected:
/** the @a Condition this instruction requires, or null. */ /** the @a Condition this instruction requires, or null. */
Condition* m_condition; Condition* m_condition;
@@ -1147,8 +1133,6 @@ class Instruction {
* same source file. */ * same source file. */
const bool m_singleton; const bool m_singleton;
protected:
/** the defaults by field name. */ /** the defaults by field name. */
map<string, string> m_defaults; map<string, string> m_defaults;
}; };
@@ -1167,8 +1151,9 @@ class LoadInstruction : public Instruction {
* @param defaults the mapped definition defaults. * @param defaults the mapped definition defaults.
* @param filename the name of the file to load. * @param filename the name of the file to load.
*/ */
LoadInstruction(Condition* condition, const bool singleton, map<string, string>& defaults, const string filename) LoadInstruction(bool singleton, const map<string, string>& defaults, const string& filename,
: Instruction(condition, singleton, defaults), m_filename(filename) { } Condition* condition)
: Instruction(singleton, defaults, condition), m_filename(filename) { }
/** /**
* Destructor. * Destructor.
@@ -1176,7 +1161,7 @@ class LoadInstruction : public Instruction {
virtual ~LoadInstruction() { } virtual ~LoadInstruction() { }
// @copydoc // @copydoc
result_t execute(MessageMap* messages, ostringstream& log, Condition* condition) override; result_t execute(MessageMap* messages, ostringstream* log) override;
private: private:
@@ -1215,7 +1200,7 @@ 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, const bool addAll = false, const string preferLanguage = "") explicit MessageMap(const string& configPath, bool addAll = false, const string& preferLanguage = "")
: MappedFileReader::MappedFileReader(true), : MappedFileReader::MappedFileReader(true),
m_configPath(configPath), 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),
@@ -1244,7 +1229,7 @@ class MessageMap : public MappedFileReader {
* @param filename the name of the configuration file (including relative path). * @param filename the name of the configuration file (including relative path).
* @return the relative file name. * @return the relative file name.
*/ */
const string getRelativePath(const string filename) const; const string getRelativePath(const string& filename) const;
/** /**
* Add a @a Message instance to this set. * Add a @a Message instance to this set.
@@ -1253,36 +1238,36 @@ class MessageMap : public MappedFileReader {
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success. * Note: the caller may not free the added instance on success.
*/ */
result_t add(Message* message, bool storeByName = true); result_t add(bool storeByName, Message* message);
// @copydoc // @copydoc
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override; result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override;
// @copydoc // @copydoc
result_t addDefaultFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addDefaultFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override; vector< map<string, string> >* subRows, string* errorDescription) override;
/** /**
* Read the @a Condition instance(s) from the types field. * Read the @a Condition instance(s) from the types field.
* @param types the field from which to read the @a Condition instance(s).
* @param filename the name of the file being read. * @param filename the name of the file being read.
* @param types the field from which to read the @a Condition instance(s) and remove the definition prefix.
* @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 condition the variable in which to store the result. * @param condition the variable in which to store the result.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t readConditions(string& types, const string filename, string& errorDescription, Condition*& condition); result_t readConditions(const string& filename, string* types, string* errorDescription, Condition** condition);
// @copydoc // @copydoc
bool extractDefaultsFromFilename(string filename, map<string, string>& defaults, bool extractDefaultsFromFilename(const string& filename, map<string, string>* defaults,
symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const override; symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const override;
// @copydoc // @copydoc
result_t readFromFile(const string filename, string& errorDescription, bool verbose = false, result_t readFromFile(const string& filename, bool verbose, map<string, string>* defaults,
map<string, string>* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL) override; string* errorDescription, size_t* hash, size_t* size, time_t* time) override;
// @copydoc // @copydoc
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override; vector< map<string, string> >* subRows, string* errorDescription) override;
/** /**
* Get the scan @a Message instance for the specified address. * Get the scan @a Message instance for the specified address.
@@ -1299,30 +1284,30 @@ class MessageMap : public MappedFileReader {
/** /**
* Resolve all @a Condition instances. * Resolve all @a Condition instances.
* @param errorDescription a string in which to store the error description in case of error.
* @param verbose whether to verbosely add all problems to the error message. * @param verbose whether to verbosely add all problems to the error message.
* @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. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t resolveConditions(string& errorDescription, bool verbose = false); result_t resolveConditions(bool verbose, string* errorDescription);
/** /**
* Resolve a @a Condition. * Resolve a @a Condition.
* @param readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @param condition the @a Condition to resolve. * @param condition the @a Condition to resolve.
* @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 readMessageFunc the function to call for immediate reading of a @a Message from the bus, or NULL.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t resolveCondition(Condition* condition, string& errorDescription, result_t resolveCondition(void (*readMessageFunc)(Message* message), Condition* condition,
void (*readMessageFunc)(Message* message) = NULL); string* errorDescription);
/** /**
* Run all executable @a Instruction instances. * Run all executable @a Instruction instances.
* @param log the @a ostringstream to log success messages to (if necessary).
* @param readMessageFunc the function to call for immediate reading of a * @param readMessageFunc the function to call for immediate reading of a
* @a Message values from the bus required for singleton instructions, or NULL. * @a Message values from the bus required for singleton instructions, or NULL.
* @param log the @a ostringstream to log success messages to (if necessary).
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t executeInstructions(ostringstream& log, void (*readMessageFunc)(Message* message) = NULL); result_t executeInstructions(void (*readMessageFunc)(Message* message), ostringstream* log);
/** /**
* Add a loaded file to a participant. * Add a loaded file to a participant.
@@ -1330,14 +1315,14 @@ class MessageMap : public MappedFileReader {
* @param filename the name of the configuration file (including relative path). * @param filename the name of the configuration file (including relative path).
* @param comment an optional comment. * @param comment an optional comment.
*/ */
void addLoadedFile(const symbol_t address, const string filename, const string comment = ""); void addLoadedFile(symbol_t address, const string& filename, const string& comment = "");
/** /**
* Get the loaded files for a participant. * Get the loaded files for a participant.
* @param address the slave address. * @param address the slave address.
* @return the loaded configuration files (list of file names with relative path). * @return the loaded configuration files (list of file names with relative path).
*/ */
const vector<string>& getLoadedFiles(const symbol_t address) const; const vector<string>& getLoadedFiles(symbol_t address) const;
/** /**
* Get all loaded files. * Get all loaded files.
@@ -1354,7 +1339,7 @@ class MessageMap : public MappedFileReader {
* @param time optional pointer to a @a time_t value for storing the modification time 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 true if the file info was found, false otherwise. * @return true if the file info was found, false otherwise.
*/ */
bool getLoadedFileInfo(const string filename, string& comment, size_t* hash = NULL, size_t* size = NULL, bool getLoadedFileInfo(const string& filename, string* comment, size_t* hash = NULL, size_t* size = NULL,
time_t* time = NULL) const; time_t* time = NULL) const;
/** /**
@@ -1363,7 +1348,7 @@ class MessageMap : public MappedFileReader {
* @return the found @a Message instances, or NULL. * @return the found @a Message instances, or NULL.
* Note: the caller may not free the returned instances. * Note: the caller may not free the returned instances.
*/ */
const vector<Message*>* getByKey(const uint64_t key) const; const vector<Message*>* getByKey(uint64_t key) const;
/** /**
* Find the @a Message instance for the specified circuit and name. * Find the @a Message instance for the specified circuit and name.
@@ -1375,8 +1360,8 @@ class MessageMap : public MappedFileReader {
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
Message* find(const string& circuit, const string& name, const string& levels, const bool isWrite, Message* find(const string& circuit, const string& name, const string& levels, bool isWrite,
const bool isPassive = false) const; bool isPassive = false) const;
/** /**
* Find all active get @a Message instances for the specified circuit and name. * Find all active get @a Message instances for the specified circuit and name.
@@ -1400,9 +1385,9 @@ class MessageMap : public MappedFileReader {
* Note: the caller may not free the returned instances. * Note: the caller may not free the returned instances.
*/ */
deque<Message*> findAll(const string& circuit, const string& name, const string& levels, deque<Message*> findAll(const string& circuit, const string& name, const string& levels,
const bool completeMatch = true, const bool withRead = true, const bool withWrite = false, bool completeMatch = true, bool withRead = true, bool withWrite = false,
const bool withPassive = false, const bool includeEmptyLevel = true, const bool onlyAvailable = true, bool withPassive = false, bool includeEmptyLevel = true, bool onlyAvailable = true,
const time_t since = 0, const time_t until = 0) const; time_t since = 0, time_t until = 0) const;
/** /**
* Find the @a Message instance for the specified master data. * Find the @a Message instance for the specified master data.
@@ -1416,8 +1401,8 @@ class MessageMap : public MappedFileReader {
* @return the @a Message instance, or NULL. * @return the @a Message instance, or NULL.
* Note: the caller may not free the returned instance. * Note: the caller may not free the returned instance.
*/ */
Message* find(const MasterSymbolString& master, const bool anyDestination = false, const bool withRead = true, Message* find(const MasterSymbolString& master, bool anyDestination = false, bool withRead = true,
const bool withWrite = true, const bool withPassive = true, const bool onlyAvailable = true) const; bool withWrite = true, bool withPassive = true, bool onlyAvailable = true) const;
/** /**
* Invalidate cached data of the @a Message and all other instances with a matching name key. * Invalidate cached data of the @a Message and all other instances with a matching name key.
@@ -1427,19 +1412,19 @@ class MessageMap : public MappedFileReader {
/** /**
* Add a @a Message to the list of instances to poll. * Add a @a Message to the list of instances to poll.
* @param message the @a Message to poll.
* @param toFront whether to add the @a Message to the very front of the poll queue. * @param toFront whether to add the @a Message to the very front of the poll queue.
* @param message the @a Message to poll.
*/ */
void addPollMessage(Message* message, bool toFront = false); void addPollMessage(bool toFront, Message* message);
/** /**
* Decode circuit specific data. * Decode circuit specific data.
* @param circuit the name of the circuit. * @param circuit the name of the circuit.
* @param output the @a ostringstream to append the decoded value(s) to.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param output the @a ostringstream to append the decoded value(s) to.
* @return true if data was added, false otherwise. * @return true if data was added, false otherwise.
*/ */
bool decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const; bool decodeCircuit(const string& circuit, OutputFormat outputFormat, ostringstream* output) const;
/** /**
* Removes all @a Message instances. * Removes all @a Message instances.
@@ -1491,10 +1476,10 @@ class MessageMap : public MappedFileReader {
/** /**
* Write the message definitions to the @a ostream. * Write the message definitions to the @a ostream.
* @param output the @a ostream to append the formatted messages to.
* @param withConditions whether to include the optional conditions prefix. * @param withConditions whether to include the optional conditions prefix.
* @param output the @a ostream to append the formatted messages to.
*/ */
void dump(ostream& output, const bool withConditions = false) const; void dump(bool withConditions, ostream* output) const;
private: private:
+19 -19
View File
@@ -54,59 +54,59 @@ static const symbol_t CRC_LOOKUP_TABLE[] = {
}; };
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, unsigned int parseInt(const char* str, int base, unsigned int minValue, unsigned int maxValue,
result_t& result, size_t* length) { result_t* result, size_t* length) {
char* strEnd = NULL; char* strEnd = NULL;
unsigned long ret = strtoul(str, &strEnd, base); unsigned long ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || strEnd == str || *strEnd != 0) { if (strEnd == NULL || strEnd == str || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value *result = RESULT_ERR_INVALID_NUM; // invalid value
return 0; return 0;
} }
if (minValue > ret || ret > maxValue) { if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value *result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0; return 0;
} }
if (length != NULL) { if (length != NULL) {
*length = (unsigned int)(strEnd - str); *length = (unsigned int)(strEnd - str);
} }
result = RESULT_OK; *result = RESULT_OK;
return (unsigned int)ret; return (unsigned int)ret;
} }
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, int parseSignedInt(const char* str, int base, int minValue, int maxValue,
size_t* length) { result_t* result, size_t* length) {
char* strEnd = NULL; char* strEnd = NULL;
long ret = strtol(str, &strEnd, base); long ret = strtol(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) { if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_NUM; // invalid value *result = RESULT_ERR_INVALID_NUM; // invalid value
return 0; return 0;
} }
if (minValue > ret || ret > maxValue) { if (minValue > ret || ret > maxValue) {
result = RESULT_ERR_OUT_OF_RANGE; // invalid value *result = RESULT_ERR_OUT_OF_RANGE; // invalid value
return 0; return 0;
} }
if (length != NULL) { if (length != NULL) {
*length = (unsigned int)(strEnd - str); *length = (unsigned int)(strEnd - str);
} }
result = RESULT_OK; *result = RESULT_OK;
return static_cast<int>(ret); return static_cast<int>(ret);
} }
void SymbolString::updateCrc(symbol_t& crc, const symbol_t value) { void SymbolString::updateCrc(symbol_t value, symbol_t* crc) {
crc = CRC_LOOKUP_TABLE[crc]^value; *crc = CRC_LOOKUP_TABLE[*crc]^value;
} }
result_t SymbolString::parseHex(const string& str) { result_t SymbolString::parseHex(const string& str) {
result_t result; result_t result;
for (size_t i = 0; i < str.size(); i += 2) { for (size_t i = 0; i < str.size(); i += 2) {
symbol_t value = (symbol_t)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, result); symbol_t value = (symbol_t)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -119,7 +119,7 @@ result_t SymbolString::parseHexEscaped(const string& str) {
result_t result; result_t result;
bool inEscape = false; bool inEscape = false;
for (size_t i = 0; i < str.size(); i += 2) { for (size_t i = 0; i < str.size(); i += 2) {
symbol_t value = (symbol_t)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, result); symbol_t value = (symbol_t)parseInt(str.substr(i, 2).c_str(), 16, 0, 0xff, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -162,13 +162,13 @@ symbol_t SymbolString::calcCrc() const {
for (size_t i = 0; i < m_data.size(); i++) { for (size_t i = 0; i < m_data.size(); i++) {
symbol_t value = m_data[i]; symbol_t value = m_data[i];
if (value == ESC) { if (value == ESC) {
updateCrc(crc, ESC); updateCrc(ESC, &crc);
updateCrc(crc, 0x00); updateCrc(0x00, &crc);
} else if (value == SYN) { } else if (value == SYN) {
updateCrc(crc, ESC); updateCrc(ESC, &crc);
updateCrc(crc, 0x01); updateCrc(0x01, &crc);
} else { } else {
updateCrc(crc, value); updateCrc(value, &crc);
} }
} }
return crc; return crc;
+14 -14
View File
@@ -96,8 +96,8 @@ typedef unsigned char symbol_t;
* @param length the optional variable in which to store the number of read characters. * @param length the optional variable in which to store the number of read characters.
* @return the parsed value. * @return the parsed value.
*/ */
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, unsigned int parseInt(const char* str, int base, unsigned int minValue, unsigned int maxValue,
result_t& result, size_t* length = NULL); result_t* result, size_t* length = NULL);
/** /**
* Parse a signed int value. * Parse a signed int value.
@@ -109,8 +109,8 @@ unsigned int parseInt(const char* str, int base, const unsigned int minValue, co
* @param length the optional variable in which to store the number of read characters. * @param length the optional variable in which to store the number of read characters.
* @return the parsed value. * @return the parsed value.
*/ */
int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, int parseSignedInt(const char* str, int base, int minValue, int maxValue,
size_t* length = NULL); result_t* result, size_t* length = NULL);
/** /**
* A string of unescaped bus symbols. * A string of unescaped bus symbols.
@@ -121,15 +121,15 @@ class SymbolString {
* Creates a new empty instance. * Creates a new empty instance.
* @param isMaster whether this instance if for the master part. * @param isMaster whether this instance if for the master part.
*/ */
explicit SymbolString(const bool isMaster = false) { m_isMaster = isMaster; } explicit SymbolString(bool isMaster = false) { m_isMaster = isMaster; }
public: public:
/** /**
* Update the CRC by adding a value. * Update the CRC by adding a value.
* @param crc the current CRC to update.
* @param value the escaped value to add to the current CRC. * @param value the escaped value to add to the current CRC.
* @param crc the current CRC to update.
*/ */
static void updateCrc(symbol_t& crc, const symbol_t value); static void updateCrc(symbol_t value, symbol_t* crc);
/** /**
* Return whether this instance if for the master part. * Return whether this instance if for the master part.
@@ -175,7 +175,7 @@ class SymbolString {
* @param index the index of the symbol to return. * @param index the index of the symbol to return.
* @return the reference to the symbol at the specified index, or SYN if not available. * @return the reference to the symbol at the specified index, or SYN if not available.
*/ */
symbol_t operator[](const size_t index) const { symbol_t operator[](size_t index) const {
if (index >= m_data.size()) { if (index >= m_data.size()) {
return SYN; return SYN;
} }
@@ -187,7 +187,7 @@ class SymbolString {
* @param other the other instance. * @param other the other instance.
* @return true if this instance is equal to the other instance. * @return true if this instance is equal to the other instance.
*/ */
bool operator == (SymbolString& other) { bool operator == (const SymbolString& other) {
return m_isMaster == other.m_isMaster && m_data == other.m_data; return m_isMaster == other.m_isMaster && m_data == other.m_data;
} }
@@ -196,7 +196,7 @@ class SymbolString {
* @param other the other instance. * @param other the other instance.
* @return true if this instance is different from the other instance. * @return true if this instance is different from the other instance.
*/ */
bool operator != (SymbolString& other) { bool operator != (const SymbolString& other) {
return m_isMaster != other.m_isMaster || m_data != other.m_data; return m_isMaster != other.m_isMaster || m_data != other.m_data;
} }
@@ -207,7 +207,7 @@ class SymbolString {
* 1 if the data is completely different, * 1 if the data is completely different,
* 2 if both instances are a master part and the data only differs in the first byte (the master address). * 2 if both instances are a master part and the data only differs in the first byte (the master address).
*/ */
int compareTo(SymbolString& other) { int compareTo(const SymbolString& other) const {
if (m_data.size() != other.m_data.size() || m_isMaster != other.m_isMaster) { if (m_data.size() != other.m_data.size() || m_isMaster != other.m_isMaster) {
return 1; return 1;
} }
@@ -230,7 +230,7 @@ class SymbolString {
* Append a symbol to the end of the symbol string. * Append a symbol to the end of the symbol string.
* @param value the symbol to append. * @param value the symbol to append.
*/ */
void push_back(const symbol_t value) { m_data.push_back(value); } void push_back(symbol_t value) { m_data.push_back(value); }
/** /**
* Return the number of symbols in this symbol string. * Return the number of symbols in this symbol string.
@@ -277,7 +277,7 @@ class SymbolString {
* @param index the index of the data byte (within DD) to return. * @param index the index of the data byte (within DD) to return.
* @return the data byte at the specified index, or 0 if not available. * @return the data byte at the specified index, or 0 if not available.
*/ */
symbol_t dataAt(const size_t index) const { symbol_t dataAt(size_t index) const {
size_t offset = (m_isMaster ? 5 : 1) + index; size_t offset = (m_isMaster ? 5 : 1) + index;
if (offset < m_data.size()) { if (offset < m_data.size()) {
return m_data[offset]; return m_data[offset];
@@ -290,7 +290,7 @@ class SymbolString {
* @param index the index of the data byte (within DD) to return. * @param index the index of the data byte (within DD) to return.
* @return the reference to the data byte at the specified index. * @return the reference to the data byte at the specified index.
*/ */
symbol_t& dataAt(const size_t index) { symbol_t& dataAt(size_t index) {
size_t offset = (m_isMaster ? 5 : 1) + index; size_t offset = (m_isMaster ? 5 : 1) + index;
if (offset >= m_data.size()) { if (offset >= m_data.size()) {
m_data.resize(offset+1, 0); m_data.resize(offset+1, 0);
+30 -31
View File
@@ -53,34 +53,34 @@ class TestReader : public MappedFileReader {
TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest) TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest)
: MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest), : MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest),
m_fields(NULL) {} m_fields(NULL) {}
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override { result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override {
if (row.empty()) { if (row->empty()) {
row.push_back("*name"); row->push_back("*name");
row.push_back("part"); row->push_back("part");
row.push_back("type"); row->push_back("type");
row.push_back("divisor/values"); row->push_back("divisor/values");
row.push_back("unit"); row->push_back("unit");
row.push_back("comment"); row->push_back("comment");
return RESULT_OK; return RESULT_OK;
} }
if (row[0][0] != '*') { if ((*row)[0][0] != '*') {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
return RESULT_OK; // leave it to DataField::create return RESULT_OK; // leave it to DataField::create
} }
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override { vector< map<string, string> >* subRows, string* errorDescription) override {
if (!row.empty() || subRows.empty()) { if (!row->empty() || subRows->empty()) {
cout << "read line " << static_cast<unsigned>(lineNo) << ": read error: got " cout << "read line " << static_cast<unsigned>(lineNo) << ": read error: got "
<< static_cast<unsigned>(row.size()) << "/0 main, " << static_cast<unsigned>(subRows.size()) << static_cast<unsigned>(row->size()) << "/0 main, " << static_cast<unsigned>(subRows->size())
<< "/>=3 sub" << endl; << "/>=3 sub" << endl;
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
} }
cout << "read line " << static_cast<unsigned>(lineNo) << ": read OK" << endl; cout << "read line " << static_cast<unsigned>(lineNo) << ": read OK" << endl;
return DataField::create(subRows, errorDescription, m_templates, m_fields, m_isSet, false, m_isMasterDest); return DataField::create(m_isSet, false, m_isMasterDest, MAX_POS, m_templates, subRows, errorDescription, &m_fields);
} }
private: private:
DataFieldTemplates* m_templates; const DataFieldTemplates* m_templates;
const bool m_isSet; const bool m_isSet;
const bool m_isMasterDest; const bool m_isMasterDest;
public: public:
@@ -508,7 +508,7 @@ int main() {
istringstream dummystr("#"); istringstream dummystr("#");
string errorDescription; string errorDescription;
vector<string> row; vector<string> row;
templates->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row); templates->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
const DataField* fields = NULL; const DataField* fields = NULL;
for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) {
string check[5] = checks[i]; string check[5] = checks[i];
@@ -558,7 +558,7 @@ int main() {
} }
if (isTemplate) { if (isTemplate) {
lineNo = baseLine + i; lineNo = baseLine + i;
result = templates->readLineFromStream(isstr, errorDescription, __FILE__, lineNo, row, false); result = templates->readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", " cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", "
<< errorDescription << endl; << errorDescription << endl;
@@ -570,7 +570,7 @@ int main() {
lineNo = 0; lineNo = 0;
dummystr.clear(); dummystr.clear();
dummystr.str("#"); dummystr.str("#");
result = reader.readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row); result = reader.readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription
<< endl; << endl;
@@ -578,7 +578,7 @@ int main() {
continue; continue;
} }
lineNo = baseLine + i; lineNo = baseLine + i;
result = reader.readLineFromStream(isstr, errorDescription, "", lineNo, row); result = reader.readLineFromStream("", false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
fields = reader.m_fields; fields = reader.m_fields;
if (failedCreate) { if (failedCreate) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
@@ -600,7 +600,7 @@ int main() {
continue; continue;
} }
cout << "\"" << check[0] << "\"=\""; cout << "\"" << check[0] << "\"=\"";
fields->dump(cout); fields->dump(&cout);
cout << "\": create OK" << endl; cout << "\": create OK" << endl;
ostringstream output; ostringstream output;
@@ -616,22 +616,21 @@ int main() {
cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl;
error = true; error = true;
} }
result = fields->read(mstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, false); result = fields->read(mstr, 0, false, NULL, -1, verbosity|(numeric?OF_NUMERIC:0), -1, &output);
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->read(sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, result = fields->read(sstr, 0, !output.str().empty(), NULL, -1, verbosity|(numeric?OF_NUMERIC:0), -1, &output);
!output.str().empty());
} }
if (failedRead) { if (failedRead) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else { } else {
cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< OK" << endl; << "< OK" << endl;
} }
} else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " read " << fields->getName() << " >" << check[2] << " " << check[3] cout << " read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
@@ -641,21 +640,21 @@ int main() {
if (verbosity == 0) { if (verbosity == 0) {
istringstream input(expectStr); istringstream input(expectStr);
result = fields->write(input, writeMstr, 0); result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeMstr, NULL);
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
result = fields->write(input, writeSstr, 0); result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeSstr, NULL);
} }
if (failedWrite) { if (failedWrite) {
if (result >= RESULT_OK) { if (result >= RESULT_OK) {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< error: unexpectedly succeeded" << endl; << expectStr << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else { } else {
cout << " failed write " << fields->getName() << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< OK" << endl; << expectStr << "< OK" << endl;
} }
} else if (result < RESULT_OK) { } else if (result < RESULT_OK) {
cout << " write " << fields->getName() << " >" << expectStr cout << " write " << fields->getName(-1) << " >" << expectStr
<< "< error: " << getResultCode(result) << endl; << "< error: " << getResultCode(result) << endl;
error = true; error = true;
} else { } else {
+1 -1
View File
@@ -40,7 +40,7 @@ int main() {
while (1) { while (1) {
symbol_t byte = 0; symbol_t byte = 0;
result = device->recv(0, byte); result = device->recv(0, &byte);
if (result == RESULT_OK) { if (result == RESULT_OK) {
cout << hex << setw(2) << setfill('0') cout << hex << setw(2) << setfill('0')
+24 -24
View File
@@ -73,8 +73,8 @@ static unsigned int baseLine = 0;
class NoopReader : public FileReader { class NoopReader : public FileReader {
public: public:
result_t addFromFile(vector<string>& row, string& errorDescription, result_t addFromFile(const string& filename, unsigned int lineNo, vector<string>* row,
const string filename, unsigned int lineNo) override { string* errorDescription) override {
return RESULT_OK; return RESULT_OK;
} }
}; };
@@ -83,25 +83,25 @@ class TestReader : public MappedFileReader {
public: public:
TestReader(size_t expectedCols, size_t langCols) TestReader(size_t expectedCols, size_t langCols)
: MappedFileReader::MappedFileReader(false, ""), m_expectedCols(expectedCols), m_langCols(langCols) {} : MappedFileReader::MappedFileReader(false, ""), m_expectedCols(expectedCols), m_langCols(langCols) {}
result_t getFieldMap(vector<string>& row, string& errorDescription, const string preferLanguage) const override { result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override {
if (row.size() == m_expectedCols+m_langCols) { if (row->size() == m_expectedCols+m_langCols) {
cout << "get field map: split OK" << endl; cout << "get field map: split OK" << endl;
if (m_langCols == 1) { if (m_langCols == 1) {
row[0] = SKIP_COLUMN; (*row)[0] = SKIP_COLUMN;
size_t pos = row[1].find_last_of('.'); size_t pos = (*row)[1].find_last_of('.');
row[1] = row[1].substr(0, pos); (*row)[1] = (*row)[1].substr(0, pos);
} }
return RESULT_OK; return RESULT_OK;
} }
cout << "get field map: error got " << static_cast<unsigned>(row.size()) << " columns, expected " << cout << "get field map: error got " << static_cast<unsigned>(row->size()) << " columns, expected " <<
static_cast<unsigned>(m_expectedCols+m_langCols) << endl; static_cast<unsigned>(m_expectedCols+m_langCols) << endl;
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
} }
result_t addFromFile(map<string, string>& row, vector< map<string, string> >& subRows, result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
string& errorDescription, const string filename, unsigned int lineNo) override { vector< map<string, string> >* subRows, string* errorDescription) override {
if (row.empty() || (m_expectedCols == 3) != subRows.empty()) { if (row->empty() || (m_expectedCols == 3) != subRows->empty()) {
cout << "read line " << static_cast<unsigned>(baseLine + lineNo) << ": read error: got " cout << "read line " << static_cast<unsigned>(baseLine + lineNo) << ": read error: got "
<< static_cast<unsigned>(row.size()) << "/3 main, " << static_cast<unsigned>(subRows.size()) << static_cast<unsigned>(row->size()) << "/3 main, " << static_cast<unsigned>(subRows->size())
<< (m_expectedCols == 3 ? "/0 sub" : "/>0 sub") << endl; << (m_expectedCols == 3 ? "/0 sub" : "/>0 sub") << endl;
return RESULT_ERR_EOF; return RESULT_ERR_EOF;
} }
@@ -111,7 +111,7 @@ class TestReader : public MappedFileReader {
} }
cout << "read line " << static_cast<unsigned>(baseLine + lineNo) << ": split OK" << endl; cout << "read line " << static_cast<unsigned>(baseLine + lineNo) << ": split OK" << endl;
string resultline[3] = resultlines[lineNo - 1]; string resultline[3] = resultlines[lineNo - 1];
if (row.empty()) { if (row->empty()) {
cout << " result empty"; cout << " result empty";
if (resultline[0] == "") { if (resultline[0] == "") {
cout << ": OK" << endl; cout << ": OK" << endl;
@@ -127,7 +127,7 @@ class TestReader : public MappedFileReader {
map<string, string>& defaults = getDefaults()[""]; map<string, string>& defaults = getDefaults()[""];
for (size_t colIdx = 0; colIdx < 3; colIdx++) { for (size_t colIdx = 0; colIdx < 3; colIdx++) {
string col = colnames[colIdx]; string col = colnames[colIdx];
string got = row[col] + defaults[col]; string got = (*row)[col] + defaults[col];
string expect = resultline[colIdx]; string expect = resultline[colIdx];
ostringstream type; ostringstream type;
type << "line " << static_cast<unsigned>(baseLine + lineNo) << " column \"" << col << "\""; type << "line " << static_cast<unsigned>(baseLine + lineNo) << " column \"" << col << "\"";
@@ -137,17 +137,17 @@ class TestReader : public MappedFileReader {
error = true; error = true;
} }
} }
if (row.size() > 3) { if (row->size() > 3) {
ostringstream type; ostringstream type;
type << "line " << static_cast<unsigned>(baseLine + lineNo); type << "line " << static_cast<unsigned>(baseLine + lineNo);
verify(false, type.str(), "", false, "", "extra column"); verify(false, type.str(), "", false, "", "extra column");
error = true; error = true;
} }
for (size_t subIdx = 0; subIdx < subRows.size(); subIdx++) { for (size_t subIdx = 0; subIdx < subRows->size(); subIdx++) {
string resultsubline[4] = resultsublines[lineNo - 1][subIdx]; string resultsubline[4] = resultsublines[lineNo - 1][subIdx];
row = subRows[subIdx]; *row = (*subRows)[subIdx];
if (row.empty()) { if (row->empty()) {
cout << " sub " << subIdx << " result empty"; cout << " sub " << subIdx << " result empty";
if (resultline[0] == "") { if (resultline[0] == "") {
cout << ": OK" << endl; cout << ": OK" << endl;
@@ -161,7 +161,7 @@ class TestReader : public MappedFileReader {
vector< map<string, string> >& subDefaults = getSubDefaults()[""]; vector< map<string, string> >& subDefaults = getSubDefaults()[""];
for (size_t colIdx = 0; colIdx < 2; colIdx++) { for (size_t colIdx = 0; colIdx < 2; colIdx++) {
string col = resultsubline[colIdx*2]; string col = resultsubline[colIdx*2];
string got = row[col]; string got = (*row)[col];
if (subIdx < subDefaults.size()) { if (subIdx < subDefaults.size()) {
got += subDefaults[subIdx][col]; got += subDefaults[subIdx][col];
} }
@@ -174,7 +174,7 @@ class TestReader : public MappedFileReader {
error = true; error = true;
} }
} }
if (row.size() > 2) { if (row->size() > 2) {
ostringstream type; ostringstream type;
type << "line " << static_cast<unsigned>(baseLine + lineNo) << " sub " << subIdx; type << "line " << static_cast<unsigned>(baseLine + lineNo) << " sub " << subIdx;
verify(false, type.str(), "", false, "", "extra sub column"); verify(false, type.str(), "", false, "", "extra sub column");
@@ -196,14 +196,14 @@ int main(int argc, char** argv) {
size_t hash = 0, size = 0; size_t hash = 0, size = 0;
time_t time = 0; time_t time = 0;
string errorDescription; string errorDescription;
result_t result = reader.readFromFile(argv[argpos], errorDescription, false, NULL, &hash, &size, &time); result_t result = reader.readFromFile(argv[argpos], false, NULL, &errorDescription, &hash, &size, &time);
cout << argv[argpos] << " "; cout << argv[argpos] << " ";
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << getResultCode(result) << ", " << errorDescription << endl; cout << getResultCode(result) << ", " << errorDescription << endl;
error = true; error = true;
continue; continue;
} }
FileReader::formatHash(hash, cout); FileReader::formatHash(hash, &cout);
cout << " " << size << " " << time << endl; cout << " " << size << " " << time << endl;
} }
return error ? 1 : 0; return error ? 1 : 0;
@@ -226,7 +226,7 @@ int main(int argc, char** argv) {
string errorDescription; string errorDescription;
while (ifs.peek() != EOF) { while (ifs.peek() != EOF) {
istringstream str; istringstream str;
result_t result = reader.readLineFromStream(ifs, errorDescription, "", lineNo, row, true, &hash, &size); result_t result = reader.readLineFromStream("", true, &ifs, &lineNo, &row, &errorDescription, &hash, &size);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " error " << getResultCode(result) << endl; cout << " error " << getResultCode(result) << endl;
error = true; error = true;
@@ -267,7 +267,7 @@ int main(int argc, char** argv) {
subDefaults[0]["subcol 2"] = ";default of sub 0 subcol 2"; subDefaults[0]["subcol 2"] = ";default of sub 0 subcol 2";
while (ifs.peek() != EOF) { while (ifs.peek() != EOF) {
istringstream str; istringstream str;
result_t result = reader2.readLineFromStream(ifs, errorDescription, "", lineNo, row, true, &hash, &size); result_t result = reader2.readLineFromStream("", true, &ifs, &lineNo, &row, &errorDescription, &hash, &size);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " error " << getResultCode(result) << endl; cout << " error " << getResultCode(result) << endl;
error = true; error = true;
+14 -10
View File
@@ -54,7 +54,7 @@ DataFieldTemplates* templates = NULL;
namespace ebusd { namespace ebusd {
DataFieldTemplates* getTemplates(const string filename) { DataFieldTemplates* getTemplates(const string& filename) {
if (filename == "") { // avoid compiler warning if (filename == "") { // avoid compiler warning
return templates; return templates;
} }
@@ -71,7 +71,9 @@ int main() {
unsigned int baseLine = __LINE__+1; unsigned int baseLine = __LINE__+1;
string checks[][5] = { string checks[][5] = {
{"date,HDA:3,,,Datum", "", "", "", "template"}, {"date,HDA:3,,,Datum", "", "", "", "template"},
{"bdate:date,BDA,,,Datum", "", "", "", "template"},
{"time,VTI,,,", "", "", "", "template"}, {"time,VTI,,,", "", "", "", "template"},
{"btime:time,BTI,,,Uhrzeit", "", "", "", "template"},
{"dcfstate,UCH,0=nosignal;1=ok;2=sync;3=valid,,", "", "", "", "template"}, {"dcfstate,UCH,0=nosignal;1=ok;2=sync;3=valid,,", "", "", "", "template"},
{"temp,D2C,,°C,Temperatur", "", "", "", "template"}, {"temp,D2C,,°C,Temperatur", "", "", "", "template"},
{"temp1,D1C,,°C,Temperatur", "", "", "", "template"}, {"temp1,D1C,,°C,Temperatur", "", "", "", "template"},
@@ -93,6 +95,8 @@ int main() {
{"r,cir,name,,,25,B509,0d28,,m,sensorc,,,,,,temp", "-14.00", "ff25b509030d2855", "0220ff", ""}, {"r,cir,name,,,25,B509,0d28,,m,sensorc,,,,,,temp", "-14.00", "ff25b509030d2855", "0220ff", ""},
{"u,cir,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"}, {"u,cir,first,,,fe,0700,,x,,bda", "26.10.2014", "fffe07000426100614", "00", "p"},
{"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""}, {"u,broadcast,hwStatus,,,fe,b505,27,,,UCH,,,,,,UCH,,,,,,UCH,,,", "0;19;0", "10feb505042700130097", "00", ""},
{"u,broadcast,datetime,Datum/Uhrzeit,,fe,0700,,outsidetemp,,temp2,,°C,Aussentemperatur,time,,btime,,,,date,,BDA,,,Datum", "outsidetemp=14.500 °C [Aussentemperatur];time=12:25:01 [Uhrzeit];date=01.05.2017 [Datum]", "10fe070009800e01251201050017", "", "D"},
{"u,broadcast,datetime,Datum Uhrzeit,,fe,0700,,,,temp2;btime;bdate", "temp2=14.500 °C [Temperatur];time=12:25:01 [Uhrzeit];date=01.05.2017 [Datum]", "10fe070009800e01251201050017", "", "D"},
{"w,cir,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", ""}, {"w,cir,first,,,15,b509,0400,date,,bda", "26.10.2014", "ff15b50906040026100614", "00", ""},
{"w,cir,first,,,15,b509", "", "ff15b50900", "00", ""}, {"w,cir,first,,,15,b509", "", "ff15b50900", "00", ""},
{"*w,,,,,,b505,2d", "", "", "", ""}, {"*w,,,,,,b505,2d", "", "", "", ""},
@@ -147,12 +151,12 @@ int main() {
istringstream dummystr("#"); istringstream dummystr("#");
string errorDescription; string errorDescription;
vector<string> row; vector<string> row;
templates->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row, false); templates->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
lineNo = 0; lineNo = 0;
MessageMap* messages = new MessageMap(""); MessageMap* messages = new MessageMap("");
dummystr.clear(); dummystr.clear();
dummystr.str("#"); dummystr.str("#");
messages->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row, false); messages->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL);
vector< vector<string> > defaultsRows; vector< vector<string> > defaultsRows;
Message* message = NULL; Message* message = NULL;
vector<MasterSymbolString*> mstrs; vector<MasterSymbolString*> mstrs;
@@ -183,7 +187,7 @@ int main() {
lineNo = baseLine + i; lineNo = baseLine + i;
cout << "line " << (lineNo+1) << " "; cout << "line " << (lineNo+1) << " ";
if (isTemplate) { if (isTemplate) {
result = templates->readLineFromStream(isstr, errorDescription, __FILE__, lineNo, row); result = templates->readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", " << errorDescription cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", " << errorDescription
<< endl; << endl;
@@ -197,7 +201,7 @@ int main() {
} }
if (isstr.peek() == '*') { if (isstr.peek() == '*') {
// store defaults or condition // store defaults or condition
result = messages->readLineFromStream(isstr, errorDescription, __FILE__, lineNo, row); result = messages->readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << "\"" << check[0] << "\": default read error: " << getResultCode(result) << ", " << errorDescription << endl; cout << "\"" << check[0] << "\": default read error: " << getResultCode(result) << ", " << errorDescription << endl;
error = true; error = true;
@@ -279,7 +283,7 @@ int main() {
} }
cout << "\"" << check[2] << "\": find OK" << endl; cout << "\"" << check[2] << "\": find OK" << endl;
} else { } else {
result = messages->readLineFromStream(isstr, errorDescription, __FILE__, lineNo, row); result = messages->readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL);
if (failedCreate) { if (failedCreate) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
@@ -345,11 +349,11 @@ int main() {
} }
ostringstream output; ostringstream output;
if (withMessageDump && !decodeJson) { if (withMessageDump && !decodeJson) {
message->dump(output, NULL, true); message->dump(NULL, true, &output);
output << ": "; output << ": ";
} }
result = message->decodeLastData(output, result = message->decodeLastData(false, NULL, -1,
(decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false); (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), &output);
if (result != RESULT_OK) { if (result != RESULT_OK) {
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: " cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: "
<< getResultCode(result) << endl; << getResultCode(result) << endl;
@@ -385,7 +389,7 @@ int main() {
if (!message->isPassive() && (withInput || !decode)) { if (!message->isPassive() && (withInput || !decode)) {
istringstream input(inputStr); istringstream input(inputStr);
MasterSymbolString writeMstr; MasterSymbolString writeMstr;
result = message->prepareMaster(0xff, writeMstr, input); result = message->prepareMaster(0, 0xff, SYN, UI_FIELD_SEPARATOR, &input, &writeMstr);
if (failedPrepare) { if (failedPrepare) {
if (result == RESULT_OK) { if (result == RESULT_OK) {
cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl;
+1 -1
View File
@@ -120,7 +120,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
return 0; return 0;
} }
string fetchData(ebusd::TCPSocket* socket, bool& listening) { string fetchData(ebusd::TCPSocket* socket, bool listening) {
char data[1024]; char data[1024];
ssize_t datalen; ssize_t datalen;
ostringstream ostream; ostringstream ostream;