diff --git a/src/ebusd/bushandler.cpp b/src/ebusd/bushandler.cpp index de535fd8..fb27ad88 100644 --- a/src/ebusd/bushandler.cpp +++ b/src/ebusd/bushandler.cpp @@ -65,16 +65,16 @@ const char* getStateCode(BusState state) { result_t PollRequest::prepare(symbol_t ownMasterAddress) { 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) { logInfo(lf_bus, "poll cmd: %s", m_master.getStr().c_str()); } return result; } -bool PollRequest::notify(result_t result, SlaveSymbolString& slave) { +bool PollRequest::notify(result_t result, const SlaveSymbolString& slave) { 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()) { m_index++; result = prepare(m_master[0]); @@ -85,7 +85,7 @@ bool PollRequest::notify(result_t result, SlaveSymbolString& slave) { } ostringstream output; 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) { 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(); 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) { logInfo(lf_bus, "scan %2.2x cmd: %s", dstAddress, m_master.getStr().c_str()); } 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]; if (result == RESULT_OK) { if (m_message == m_messageMap->getScanMessage()) { Message* message = m_messageMap->getScanMessage(dstAddress); if (message != NULL) { 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) { m_message = m_message->derive(dstAddress, true); - m_messageMap->add(m_message); - m_message->storeLastData(m_master, m_index); // expected to work since this is a clone + m_messageMap->add(true, m_message); + 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()) { m_index++; result = prepare(m_master[0]); @@ -135,7 +135,7 @@ bool ScanRequest::notify(result_t result, SlaveSymbolString& slave) { } if (result == RESULT_OK) { 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(); 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) { logDebug(lf_bus, "read res: %s", slave.getStr().c_str()); } m_result = result; - m_slave = slave; + *m_slave = slave; return false; } -void GrabbedMessage::setLastData(MasterSymbolString& master, SlaveSymbolString& slave) { + +void GrabbedMessage::setLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) { m_lastMaster = master; m_lastSlave = slave; m_count++; } + /** * Decode the input @a SymbolString with the specified @a DataType and length. * @param type the @a DataType. * @param input the @a SymbolString to read the binary value from. * @param length the number of symbols 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 output the ostringstream to append the formatted value to. * @return @a RESULT_OK on success, or an error code. */ -bool decodeType(const DataType* type, const SymbolString *input, size_t length, - size_t offsets, ostringstream& output, bool firstOnly = false) { +bool decodeType(const DataType* type, const SymbolString& input, size_t length, + size_t offsets, bool firstOnly, ostringstream* output) { bool first = true; - string in = input->getStr(input->getDataOffset()); + string in = input.getStr(input.getDataOffset()); for (size_t offset = 0; offset <= offsets; offset++) { 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) { continue; } if (type->isNumeric() && type->hasFlag(DAY)) { 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 << DataField::getDayName(reinterpret_cast(type)->getMinValue()+value); } } if (first) { first = false; - output << endl << " "; - ostringstream::pos_type cnt = output.tellp(); - type->dump(output, length, false); - cnt = output.tellp() - cnt; + *output << endl << " "; + ostringstream::pos_type cnt = output->tellp(); + type->dump(length, false, output); + cnt = output->tellp() - cnt; while (cnt < 5) { - output << " "; + *output << " "; cnt += 1; } } else { - output << ","; + *output << ","; } - output << " " << in.substr(offset*2, length*2); + *output << " " << in.substr(offset*2, length*2); if (type->isNumeric()) { - output << "=" << out.str(); + *output << "=" << out.str(); } else { - output << "=\"" << out.str() << "\""; + *output << "=\"" << out.str() << "\""; } if (firstOnly) { 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; } -bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output, - const bool decode) const { +bool GrabbedMessage::dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output) const { Message* message = messages->find(m_lastMaster); if (unknown && message) { return false; } if (!first) { - output << endl; + *output << endl; } symbol_t dstAddress = m_lastMaster[1]; - output << m_lastMaster.getStr(); + *output << m_lastMaster.getStr(); if (dstAddress != BROADCAST && !isMaster(dstAddress)) { - output << " / " << m_lastSlave.getStr(); + *output << " / " << m_lastSlave.getStr(); } - output << " = " << static_cast(m_count); + *output << " = " << static_cast(m_count); if (message) { - output << ": " << message->getCircuit() << " " << message->getName(); + *output << ": " << message->getCircuit() << " " << message->getName(); } if (decode) { DataTypeList *types = DataTypeList::getInstance(); @@ -278,13 +279,7 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, return true; } bool master = isMaster(dstAddress) || dstAddress == BROADCAST || m_lastSlave.getDataSize() <= 0; - const SymbolString *input; - if (master) { - input = &m_lastMaster; - } else { - input = &m_lastSlave; - } - size_t remain = input->getDataSize(); + size_t remain = master ? m_lastMaster.getDataSize() : m_lastSlave.getDataSize(); if (remain == 0) { return true; } @@ -301,14 +296,22 @@ bool GrabbedMessage::dump(const bool unknown, MessageMap* messages, bool first, if (baseType->isAdjustableLength()) { for (size_t length = maxLength; length >= 1; length--) { const DataType* type = types->get(baseType->getId(), length); - if (decodeType(type, input, length, remain-length, output, firstOnly)) { - if (firstOnly) { - break; // only a single offset with maximum length when adjustable maximum size is at least 8 bytes - } + bool decoded; + 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 } } } 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(); } -result_t BusHandler::sendAndWait(MasterSymbolString& master, SlaveSymbolString& slave) { +result_t BusHandler::sendAndWait(const MasterSymbolString& master, SlaveSymbolString* slave) { result_t result = RESULT_ERR_NO_SIGNAL; - slave.clear(); + slave->clear(); ActiveBusRequest request(master, slave); logInfo(lf_bus, "send message: %s", master.getStr().c_str()); @@ -349,26 +352,26 @@ result_t BusHandler::sendAndWait(MasterSymbolString& master, SlaveSymbolString& return result; } -result_t BusHandler::readFromBus(Message* message, string inputStr, const symbol_t dstAddress, - const symbol_t srcAddress) { +result_t BusHandler::readFromBus(Message* message, const string& inputStr, symbol_t dstAddress, + symbol_t srcAddress) { symbol_t masterAddress = srcAddress == SYN ? m_ownMasterAddress : srcAddress; result_t ret = RESULT_EMPTY; MasterSymbolString master; SlaveSymbolString slave; for (size_t index = 0; index < message->getCount(); index++) { 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) { logError(lf_bus, "prepare message part %d: %s", index, getResultCode(ret)); break; } // send message - ret = sendAndWait(master, slave); + ret = sendAndWait(master, &slave); if (ret != RESULT_OK) { logError(lf_bus, "send message part %d: %s", index, getResultCode(ret)); break; } - ret = message->storeLastData(slave, index); + ret = message->storeLastData(index, slave); if (ret < RESULT_OK) { logError(lf_bus, "store message part %d: %s", index, getResultCode(ret)); break; @@ -569,14 +572,14 @@ result_t BusHandler::handleSymbol() { // receive next symbol (optionally check reception of sent symbol) 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 && timeout >= m_generateSynInterval && (m_state == bs_noSignal || m_state == bs_skip)) { // check if acting as AUTO-SYN generator is required result = m_device->send(SYN); if (result == RESULT_OK) { recvSymbol = ESC; - result = m_device->recv(SEND_TIMEOUT, recvSymbol); + result = m_device->recv(SEND_TIMEOUT, &recvSymbol); if (result == RESULT_ERR_TIMEOUT) { return setState(bs_noSignal, result); } @@ -626,7 +629,7 @@ result_t BusHandler::handleSymbol() { case bs_recvRes: case bs_sendCmd: case bs_sendRes: - SymbolString::updateCrc(m_crc, recvSymbol); + SymbolString::updateCrc(recvSymbol, &m_crc); break; default: break; @@ -883,7 +886,7 @@ result_t BusHandler::handleSymbol() { } // build response and store in m_response for sending back to requesting master m_response.clear(); - result = message->prepareSlave(input, m_response); + result = message->prepareSlave(&input, &m_response); if (result != RESULT_OK) { return setState(bs_skip, result); } @@ -1060,17 +1063,18 @@ void BusHandler::receiveCompleted() { // e.g. 10fe07040a b5564149303001248901 MasterSymbolString dummyMaster; 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) { SlaveSymbolString idData; idData.push_back(10); for (size_t i = 0; i < 10; i++) { idData.push_back(m_command.dataAt(i)); } - result = message->storeLastData(idData, 0); + result = message->storeLastData(0, idData); if (result == RESULT_OK) { ostringstream output; - result = message->decodeLastData(output, 0, true); + result = message->decodeLastData(true, NULL, -1, 0, &output); if (result == RESULT_OK) { string str = output.str(); setScanResult(slaveAddress, 0, str); @@ -1108,7 +1112,7 @@ void BusHandler::receiveCompleted() { result_t result = message->storeLastData(m_command, m_response); if (result == RESULT_OK) { ostringstream output; - result = message->decodeLastData(output, 0, true); + result = message->decodeLastData(true, NULL, -1, 0, &output); if (result == RESULT_OK) { string str = output.str(); setScanResult(dstAddress, 0, str); @@ -1125,7 +1129,7 @@ void BusHandler::receiveCompleted() { result_t result = message->storeLastData(m_command, m_response); ostringstream output; if (result == RESULT_OK) { - result = message->decodeLastData(output); + result = message->decodeLastData(false, NULL, -1, 0, &output); } if (result < RESULT_OK) { 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(); if (scanMessage == NULL) { return RESULT_ERR_NOTFOUND; @@ -1173,14 +1178,14 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool& deque slaves; if (slave != SYN) { slaves.push_back(slave); - if (!reload) { + if (!*reload) { Message* message = m_messages->getScanMessage(slave); if (message == NULL || message->getLastChangeTime() == 0) { - reload = true; + *reload = true; } } } else { - reload = true; + *reload = true; for (slave = 1; slave != 0; slave++) { // 0 is known to be a master if (!isValidAddress(slave, false) || isMaster(slave)) { continue; @@ -1194,29 +1199,29 @@ result_t BusHandler::prepareScan(symbol_t slave, bool full, string levels, bool& slaves.push_back(slave); } } - if (reload) { + if (*reload) { messages.push_front(scanMessage); } if (messages.empty()) { return RESULT_OK; } - request = new ScanRequest(slave == SYN, m_messages, messages, slaves, this, reload ? 0 : 1); - result_t result = request->prepare(m_ownMasterAddress); + *request = new ScanRequest(slave == SYN, m_messages, messages, slaves, this, *reload ? 0 : 1); + result_t result = (*request)->prepare(m_ownMasterAddress); if (result < RESULT_OK) { - delete request; - request = NULL; + delete *request; + *request = NULL; return result == RESULT_ERR_EOF ? RESULT_EMPTY : result; } return RESULT_OK; } -result_t BusHandler::startScan(bool full, string levels) { +result_t BusHandler::startScan(bool full, const string& levels) { if (m_runningScans > 0) { return RESULT_ERR_DUPLICATE; } ScanRequest* request = NULL; 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) { return result; } @@ -1229,7 +1234,7 @@ result_t BusHandler::startScan(bool full, string levels) { 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; if (str.length() > 0) { 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); if (it == m_scanResults.end()) { return false; } if (leadingNewline) { - output << endl; + *output << endl; } - output << hex << setw(2) << setfill('0') << static_cast(slave); + *output << hex << setw(2) << setfill('0') << static_cast(slave); for (const auto result : it->second) { - output << result; + *output << result; } return true; } -void BusHandler::formatScanResult(ostringstream& output) { +void BusHandler::formatScanResult(ostringstream* output) const { if (m_runningScans > 0) { - output << m_runningScans << " scan(s) still running" << endl; + *output << m_runningScans << " scan(s) still running" << endl; } bool first = true; 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; } } @@ -1282,55 +1287,55 @@ void BusHandler::formatScanResult(ostringstream& output) { if (first) { first = false; } else { - output << endl; + *output << endl; } - output << hex << setw(2) << setfill('0') << static_cast(slave); - message->decodeLastData(output, 0, true); + *output << hex << setw(2) << setfill('0') << static_cast(slave); + message->decodeLastData(true, NULL, -1, 0, output); } } } } } -void BusHandler::formatSeenInfo(ostringstream& output) { +void BusHandler::formatSeenInfo(ostringstream* output) const { symbol_t address = 0; for (int index = 0; index < 256; index++, address++) { bool ownAddress = !m_device->isReadOnly() && (address == m_ownMasterAddress || address == m_ownSlaveAddress); if (!isValidAddress(address, false) || ((m_seenAddresses[address]&SEEN) == 0 && !ownAddress)) { continue; } - output << endl << "address " << setfill('0') << setw(2) << hex << static_cast(address); + *output << endl << "address " << setfill('0') << setw(2) << hex << static_cast(address); symbol_t master; if (isMaster(address)) { - output << ": master"; + *output << ": master"; master = address; } else { - output << ": slave"; + *output << ": slave"; master = getMasterAddress(address); } if (master != SYN) { - output << " #" << setw(0) << dec << static_cast(getMasterNumber(master)); + *output << " #" << setw(0) << dec << static_cast(getMasterNumber(master)); } if (ownAddress) { - output << ", ebusd"; + *output << ", ebusd"; if (m_answer) { - output << " (answering)"; + *output << " (answering)"; } if (m_addressConflict && (m_seenAddresses[address]&SEEN) != 0) { - output << ", conflict"; + *output << ", conflict"; } } if ((m_seenAddresses[address]&SCAN_DONE) != 0) { - output << ", scanned"; + *output << ", scanned"; Message* message = m_messages->getScanMessage(address); if (message != NULL && message->getLastUpdateTime() > 0) { // add detailed scan info: Manufacturer ID SW HW - output << " \""; - result_t result = message->decodeLastData(output, OF_NAMES); + *output << " \""; + result_t result = message->decodeLastData(false, NULL, -1, OF_NAMES, output); if (result != RESULT_OK) { - output << "\" error: " << getResultCode(result); + *output << "\" error: " << getResultCode(result); } else { - output << "\""; + *output << "\""; } } } @@ -1340,15 +1345,15 @@ void BusHandler::formatSeenInfo(ostringstream& output) { for (const auto& loadedFile : loadedFiles) { if (first) { first = false; - output << ", loaded \""; + *output << ", loaded \""; } else { - output << ", \""; + *output << ", \""; } - output << loadedFile << "\""; + *output << loadedFile << "\""; string comment; - if (m_messages->getLoadedFileInfo(loadedFile, comment)) { + if (m_messages->getLoadedFileInfo(loadedFile, &comment)) { 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()) { - output << ",\"s\":" << m_maxSymPerSec; + *output << ",\"s\":" << m_maxSymPerSec; } - output << ",\"c\":" << m_masterCount; - output << ",\"m\":" << m_messages->size(); - output << ",\"ro\":" << (m_device->isReadOnly() ? 1 : 0); - output << ",\"an\":" << (m_answer ? 1 : 0); - output << ",\"co\":" << (m_addressConflict ? 1 : 0); + *output << ",\"c\":" << m_masterCount + << ",\"m\":" << m_messages->size() + << ",\"ro\":" << (m_device->isReadOnly() ? 1 : 0) + << ",\"an\":" << (m_answer ? 1 : 0) + << ",\"co\":" << (m_addressConflict ? 1 : 0); if (m_grabMessages) { size_t unknownCnt = 0; for (auto it : m_grabbedMessages) { @@ -1373,7 +1378,7 @@ void BusHandler::formatUpdateInfo(ostringstream& output) { unknownCnt++; } } - output << ",\"gu\":" << unknownCnt; + *output << ",\"gu\":" << unknownCnt; } unsigned char address = 0; 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)) { continue; } - output << ",\"" << setfill('0') << setw(2) << hex << static_cast(address) << dec << setw(0); - output << "\":{\"o\":" << (ownAddress ? 1 : 0); + *output << ",\"" << setfill('0') << setw(2) << hex << static_cast(address) << dec << setw(0) + << "\":{\"o\":" << (ownAddress ? 1 : 0); const auto it = m_scanResults.find(address); if (it != m_scanResults.end()) { - output << ",\"s\":\""; + *output << ",\"s\":\""; for (const auto result : it->second) { - output << result; + *output << result; } - output << "\""; + *output << "\""; } if ((m_seenAddresses[address]&SCAN_DONE) != 0) { Message* message = m_messages->getScanMessage(address); if (message != NULL && message->getLastUpdateTime() > 0) { // 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& loadedFiles = m_messages->getLoadedFiles(address); if (!loadedFiles.empty()) { - output << ",\"f\":["; + *output << ",\"f\":["; bool first = true; for (const auto loadedFile : loadedFiles) { if (first) { first = false; } else { - output << ","; + *output << ","; } - output << "{\"f\":\"" << loadedFile << "\""; + *output << "{\"f\":\"" << loadedFile << "\""; string comment; - if (m_messages->getLoadedFileInfo(loadedFile, comment)) { + if (m_messages->getLoadedFileInfo(loadedFile, &comment)) { if (!comment.empty()) { - output << ",\"c\":\"" << comment << "\""; + *output << ",\"c\":\"" << comment << "\""; } } - output << "}"; + *output << "}"; } - output << "]"; + *output << "]"; } - output << "}"; + *output << "}"; } vector loadedFiles = m_messages->getLoadedFiles(); if (!loadedFiles.empty()) { - output << ",\"l\":{"; + *output << ",\"l\":{"; bool first = true; for (const auto& loadedFile : loadedFiles) { if (first) { first = false; } else { - output << ","; + *output << ","; } - output << "\"" << loadedFile << "\":{"; + *output << "\"" << loadedFile << "\":{"; string comment; size_t hash, size; time_t time; - if (m_messages->getLoadedFileInfo(loadedFile, comment, &hash, &size, &time)) { - output << "\"h\":\""; + if (m_messages->getLoadedFileInfo(loadedFile, &comment, &hash, &size, &time)) { + *output << "\"h\":\""; 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; 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) { return result; } @@ -1473,7 +1478,7 @@ result_t BusHandler::scanAndWait(symbol_t dstAddress, bool loadScanConfig, bool string file; bool timedOut = result == RESULT_ERR_TIMEOUT; 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) { result = RESULT_ERR_TIMEOUT; // back to previous result } @@ -1503,20 +1508,20 @@ bool BusHandler::enableGrab(bool enable) { 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) { - output << "grab disabled"; + *output << "grab disabled"; } else { bool first = true; 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; } } } } -symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) { +symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) const { if (lastAddress == SYN) { return SYN; } @@ -1538,7 +1543,7 @@ symbol_t BusHandler::getNextScanAddress(symbol_t lastAddress) { return SYN; } -void BusHandler::setScanConfigLoaded(symbol_t address, string file) { +void BusHandler::setScanConfigLoaded(symbol_t address, const string& file) { m_seenAddresses[address] |= LOAD_INIT; if (!file.empty()) { m_seenAddresses[address] |= LOAD_DONE; diff --git a/src/ebusd/bushandler.h b/src/ebusd/bushandler.h index f05bc6aa..b441b8f9 100644 --- a/src/ebusd/bushandler.h +++ b/src/ebusd/bushandler.h @@ -109,7 +109,7 @@ class BusRequest { * @param master the master data @a MasterSymbolString to send. * @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_deleteOnFinish(deleteOnFinish) {} @@ -124,12 +124,12 @@ class BusRequest { * @param slave the @a SlaveSymbolString received. * @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: /** 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. */ unsigned int m_busLostRetries; @@ -166,7 +166,7 @@ class PollRequest : public BusRequest { result_t prepare(symbol_t masterAddress); // @copydoc - bool notify(result_t result, SlaveSymbolString& slave) override; + bool notify(result_t result, const SlaveSymbolString& slave) override; private: @@ -197,8 +197,8 @@ class ScanRequest : public BusRequest { * @param busHandler the @a BusHandler instance to notify of final scan result. * @param notifyIndex the offset to the index for notifying the scan result. */ - ScanRequest(bool deleteOnFinish, MessageMap* messageMap, deque messages, deque slaves, - BusHandler* busHandler, size_t notifyIndex = 0) + ScanRequest(bool deleteOnFinish, MessageMap* messageMap, const deque& messages, + const deque& slaves, BusHandler* busHandler, size_t notifyIndex = 0) : 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_result(RESULT_ERR_NO_SIGNAL) { @@ -219,7 +219,7 @@ class ScanRequest : public BusRequest { result_t prepare(symbol_t masterAddress); // @copydoc - bool notify(result_t result, SlaveSymbolString& slave) override; + bool notify(result_t result, const SlaveSymbolString& slave) override; private: @@ -267,7 +267,7 @@ class ActiveBusRequest : public BusRequest { * @param master the master data @a MasterSymbolString to send. * @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) {} /** @@ -276,7 +276,7 @@ class ActiveBusRequest : public BusRequest { virtual ~ActiveBusRequest() {} // @copydoc - bool notify(result_t result, SlaveSymbolString& slave) override; + bool notify(result_t result, const SlaveSymbolString& slave) override; private: @@ -284,7 +284,7 @@ class ActiveBusRequest : public BusRequest { result_t m_result; /** 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 slave the last @a SymbolString. */ - void setLastData(MasterSymbolString& master, SlaveSymbolString& slave); + void setLastData(const MasterSymbolString& master, const SlaveSymbolString& slave); /** * Get the last @a MasterSymbolString. @@ -325,12 +325,11 @@ class GrabbedMessage { * @param unknown whether to dump only if this message is unknown. * @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 output the @a ostringstream to format the messages to. * @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. */ - bool dump(const bool unknown, MessageMap* messages, bool first, ostringstream& output, - const bool decode = false) const; + bool dump(bool unknown, MessageMap* messages, bool first, bool decode, ostringstream* output) const; 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. */ BusHandler(Device* device, MessageMap* messages, - const symbol_t ownAddress, const bool answer, - const unsigned int busLostRetries, const unsigned int failedSendRetries, - const unsigned int transferLatency, const unsigned int busAcquireTimeout, const unsigned int slaveRecvTimeout, - const unsigned int lockCount, const bool generateSyn, - const unsigned int pollInterval) + symbol_t ownAddress, bool answer, + unsigned int busLostRetries, unsigned int failedSendRetries, + unsigned int transferLatency, unsigned int busAcquireTimeout, unsigned int slaveRecvTimeout, + unsigned int lockCount, bool generateSyn, + unsigned int pollInterval) : WaitThread(), m_device(device), m_reconnect(false), m_messages(messages), m_ownMasterAddress(ownAddress), m_ownSlaveAddress(getSlaveAddress(ownAddress)), m_answer(answer), m_addressConflict(false), @@ -418,7 +417,7 @@ class BusHandler : public WaitThread { * @param master the @a MasterSymbolString with the master 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_response = slave; 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. * @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. @@ -442,8 +441,8 @@ class BusHandler : public WaitThread { * @param srcAddress the source address to set, or @a SYN for the own master address. * @return the result code. */ - result_t readFromBus(Message* message, string inputStr, const symbol_t dstAddress = SYN, - const symbol_t srcAddress = SYN); + result_t readFromBus(Message* message, const string& inputStr, symbol_t dstAddress = SYN, + symbol_t srcAddress = SYN); /** * Main thread entry. @@ -456,7 +455,7 @@ class BusHandler : public WaitThread { * @param levels the current user's access levels. * @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. @@ -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 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. @@ -478,25 +477,25 @@ class BusHandler : public WaitThread { * @param output the @a ostringstream to format the scan result to. * @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. * @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. * @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. * @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. @@ -517,16 +516,16 @@ class BusHandler : public WaitThread { /** * Format the grabbed messages to the @a ostringstream. * @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 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. */ - bool hasSignal() { return m_state != bs_noSignal; } + bool hasSignal() const { return m_state != bs_noSignal; } /** * Reconnect the device. @@ -537,33 +536,33 @@ class BusHandler : public WaitThread { * Return the current symbol rate. * @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 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 (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. * @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. */ - symbol_t getNextScanAddress(symbol_t lastAddress); + symbol_t getNextScanAddress(symbol_t lastAddress) const; /** * Set the state of the participant to configuration @a LOADED. * @param address the slave address. * @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: @@ -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). * @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. */ Device* m_device; diff --git a/src/ebusd/datahandler.cpp b/src/ebusd/datahandler.cpp index 9648f6ed..8da17654 100644 --- a/src/ebusd/datahandler.cpp +++ b/src/ebusd/datahandler.cpp @@ -51,12 +51,12 @@ const struct argp_child* datahandler_getargs() { } bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, - list& handlers) { + list* handlers) { bool success = true; #ifdef HAVE_MQTT DataHandler* handler = mqtthandler_register(userInfo, busHandler, messages); if (handler) { - handlers.push_back(handler); + handlers->push_back(handler); } else { success = false; } diff --git a/src/ebusd/datahandler.h b/src/ebusd/datahandler.h index bee9b353..b43ccd8f 100644 --- a/src/ebusd/datahandler.h +++ b/src/ebusd/datahandler.h @@ -55,7 +55,7 @@ const struct argp_child* datahandler_getargs(); * @return true if registration was successful. */ bool datahandler_register(UserInfo* userInfo, BusHandler* busHandler, MessageMap* messages, - list& handlers); + list* handlers); /** @@ -73,7 +73,7 @@ class UserInfo { * @param user the user name. * @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. @@ -81,14 +81,14 @@ class UserInfo { * @param secret the secret to check. * @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. * @param user the user name, or empty for default levels. * @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 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 : ""); } @@ -158,7 +158,7 @@ class DataSink : virtual public DataHandler { * Notify the sink of the latest update check result. * @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: /** the allowed access levels. */ diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index dea0e5b7..7864b882 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -178,9 +178,8 @@ static const struct argp_option argpoptions[] = { {"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=" "\"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 " - "data as arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", - 0 }, + "default is broadcast ident message). If combined with --checkconfig, you can add scan message data as " + "arguments for checking a particular scan configuration, e.g. \"FF08070400/0AB5454850303003277201\".", 0 }, {"configlang", O_CFGLNG, "LANG", 0, "Prefer LANG in multilingual configuration files [system default language]", 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; break; 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) { argp_error(state, "invalid latency"); return EINVAL; @@ -307,7 +306,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { } else if (strcmp("full", arg) == 0) { opt->initialScan = SYN; } 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)) { argp_error(state, "invalid initial scan address"); return EINVAL; @@ -333,7 +332,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->dumpConfig = true; break; 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) { argp_error(state, "invalid pollinterval"); return EINVAL; @@ -349,7 +348,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { // eBUS options: 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)) { argp_error(state, "invalid address"); return EINVAL; @@ -363,35 +362,35 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->answer = true; break; 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) { argp_error(state, "invalid acquiretimeout"); return EINVAL; } break; 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) { argp_error(state, "invalid acquireretries"); return EINVAL; } break; 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) { argp_error(state, "invalid sendretries"); return EINVAL; } break; 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) { argp_error(state, "invalid receivetimeout"); return EINVAL; } break; 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) { argp_error(state, "invalid numbermasters"); return EINVAL; @@ -434,7 +433,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->pidFile = arg; break; 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) { argp_error(state, "invalid port"); return EINVAL; @@ -444,7 +443,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->localOnly = true; break; 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) { argp_error(state, "invalid httpport"); return EINVAL; @@ -527,7 +526,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->logRawFile = arg; break; 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) { argp_error(state, "invalid lograwdatasize"); return EINVAL; @@ -547,7 +546,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { opt->dumpFile = arg; break; 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) { argp_error(state, "invalid dumpsize"); return EINVAL; @@ -555,11 +554,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { break; case ARGP_KEY_ARG: - if (!opt->injectMessages) { - argp_error(state, "invalid arguments starting with \"%s\"", arg); - return EINVAL; + if (opt->injectMessages || (opt->checkConfig && opt->scanConfig)) { + return ARGP_ERR_UNKNOWN; } - return ARGP_ERR_UNKNOWN; + argp_error(state, "invalid arguments starting with \"%s\"", arg); + return EINVAL; default: return ARGP_ERR_UNKNOWN; } @@ -704,7 +703,7 @@ void signalHandler(int sig) { * @return the result code. */ static result_t collectConfigFiles(const string path, const string prefix, const string extension, - vector& files, vector* dirs = NULL, bool* hasTemplates = NULL) { + vector* files, vector* dirs = NULL, bool* hasTemplates = NULL) { DIR* dir = opendir(path.c_str()); if (dir == NULL) { @@ -735,7 +734,7 @@ static result_t collectConfigFiles(const string path, const string prefix, const } } else if (prefix.length() == 0 || (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; } -DataFieldTemplates* getTemplates(const string filename) { +DataFieldTemplates* getTemplates(const string& filename) { string path; size_t pos = filename.find_last_of('/'); if (pos != string::npos) { @@ -783,7 +782,8 @@ static bool readTemplates(const string path, const string extension, bool availa return true; } 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) { logInfo(lf_main, "read templates in %s", path.c_str()); return true; @@ -802,18 +802,18 @@ static bool readTemplates(const string path, const string extension, bool availa * @param verbose whether to verbosely log problems. * @return the result code. */ -static result_t readConfigFiles(const string path, const string extension, MessageMap* messages, bool recursive, - bool verbose, string& errorDescription) { +static result_t readConfigFiles(const string& path, const string& extension, const bool recursive, + const bool verbose, string* errorDescription, MessageMap* messages) { vector files, dirs; 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) { return result; } readTemplates(path, extension, hasTemplates, verbose); for (const auto& name : files) { 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) { return result; } @@ -821,7 +821,7 @@ static result_t readConfigFiles(const string path, const string extension, Messa if (recursive) { for (const auto& name : dirs) { 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) { return result; } @@ -848,13 +848,13 @@ void readMessage(Message* message) { void executeInstructions(MessageMap* messages, bool verbose) { string errorDescription; - result_t result = messages->resolveConditions(errorDescription, verbose); + result_t result = messages->resolveConditions(verbose, &errorDescription); if (result != RESULT_OK) { logError(lf_main, "error resolving conditions: %s, last error: %s", getResultCode(result), errorDescription.c_str()); } ostringstream log; - result = messages->executeInstructions(log, readMessage); + result = messages->executeInstructions(readMessage, &log); if (result != RESULT_OK) { logError(lf_main, "error executing instructions: %s, last error: %s", getResultCode(result), log.str().c_str()); @@ -878,8 +878,8 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) s_templatesByPath.clear(); string errorDescription; - result_t result = readConfigFiles(string(opt.configPath), ".csv", messages, - (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, errorDescription); + result_t result = readConfigFiles(string(opt.configPath), ".csv", + (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages); if (result == RESULT_OK) { logInfo(lf_main, "read config files"); } else { @@ -889,7 +889,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) 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); if (!message || message->getLastUpdateTime() == 0) { return RESULT_ERR_NOTFOUND; @@ -905,9 +905,9 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela ostringstream out; size_t offset = 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) { - 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) { path = out.str(); @@ -918,22 +918,22 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela prefix = out.str(); out.str(""); out.clear(); - offset += (*identFields)[field++]->getLength(pt_slaveData); - result = (*identFields)[field]->read(data, offset, out, 0); // identification string + offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); + result = (*identFields)[field]->read(data, offset, false, NULL, -1, 0, -1, &out); // identification string } if (result == RESULT_OK) { ident = out.str(); out.str(""); - offset += (*identFields)[field++]->getLength(pt_slaveData); - result = (*identFields)[field]->read(data, offset, sw, 0); // software version number + offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); + result = (*identFields)[field]->read(data, offset, NULL, -1, &sw); // software version number if (result == RESULT_ERR_OUT_OF_RANGE) { sw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead result = RESULT_OK; } } if (result == RESULT_OK) { - offset += (*identFields)[field++]->getLength(pt_slaveData); - result = (*identFields)[field]->read(data, offset, hw, 0); // hardware version number + offset += (*identFields)[field++]->getLength(pt_slaveData, MAX_LEN); + result = (*identFields)[field]->read(data, offset, NULL, -1, &hw); // hardware version number if (result == RESULT_ERR_OUT_OF_RANGE) { hw = (data.dataAt(offset) << 16) | data.dataAt(offset+1); // use hex value instead result = RESULT_OK; @@ -947,7 +947,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela vector files; bool hasTemplates = false; // 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) { logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, path.c_str(), getResultCode(result)); @@ -978,7 +978,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela unsigned int checkSw, checkHw; map defaults; 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; } 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 bool readCommon = readTemplates(path, ".csv", hasTemplates, opt.checkConfig); if (readCommon) { - result = collectConfigFiles(path, "", ".csv", files); + result = collectConfigFiles(path, "", ".csv", &files); if (result == RESULT_OK && !files.empty()) { for (const auto& name : files) { 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." string errorDescription; - result = messages->readFromFile(name, errorDescription, opt.checkConfig); + result = messages->readFromFile(name, opt.checkConfig, NULL, &errorDescription, NULL, NULL, NULL); if (result == RESULT_OK) { logNotice(lf_main, "read common config file %s", name.c_str()); } else { @@ -1044,39 +1044,51 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, string& rela } string errorDescription; 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) { - logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s", best.c_str(), - ident.c_str(), sw, hw, getResultCode(result)); + logError(lf_main, "error reading scan config file %s for ID \"%s\", SW%4.4d, HW%4.4d: %s, %s", best.c_str(), + ident.c_str(), sw, hw, getResultCode(result), errorDescription.c_str()); 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); - relativeFile = best.substr(strlen(opt.configPath)+1); + *relativeFile = best.substr(strlen(opt.configPath)+1); 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('/'); if (pos == string::npos) { logError(lf_main, "invalid message %s: missing \"/\"", arg.c_str()); return false; } - result_t result = master.parseHex(arg.substr(0, pos)); + result_t result = master->parseHex(arg.substr(0, pos)); if (result == RESULT_OK) { - result = slave.parseHex(arg.substr(pos+1)); + result = slave->parseHex(arg.substr(pos+1)); } if (result != RESULT_OK) { logError(lf_main, "invalid message %s: %s", arg.c_str(), getResultCode(result)); 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()); return false; } - if (!isMaster(master[0])) { + if (!isMaster((*master)[0])) { logError(lf_main, "invalid message %s: QQ is no master", arg.c_str()); 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; } @@ -1114,7 +1126,7 @@ int main(int argc, char* argv[]) { SlaveSymbolString slave; while (result == RESULT_OK && opt.scanConfig && arg_index < argc) { // 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; } symbol_t address = master[1]; @@ -1124,7 +1136,7 @@ int main(int argc, char* argv[]) { } else { message->storeLastData(master, slave); string file; - result_t res = loadScanConfigFile(s_messageMap, address, file, true); + result_t res = loadScanConfigFile(s_messageMap, address, true, &file); executeInstructions(s_messageMap, true); if (res == RESULT_OK) { 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) { logNotice(lf_main, "configuration dump:"); - s_messageMap->dump(cout, true); + s_messageMap->dump(true, &cout); } shutdown(); return 0; @@ -1170,7 +1182,7 @@ int main(int argc, char* argv[]) { SlaveSymbolString slave; while (arg_index < argc) { // add each passed message - if (!parseMessage(argv[arg_index++], master, slave, false)) { + if (!parseMessage(argv[arg_index++], false, &master, &slave)) { continue; } busHandler->injectMessage(master, slave); diff --git a/src/ebusd/main.h b/src/ebusd/main.h index 21826b4e..624294fd 100644 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -89,7 +89,7 @@ struct options { * @param filename the full name of the configuration file. * @return the @a DataFieldTemplates. */ -DataFieldTemplates* getTemplates(const string filename); +DataFieldTemplates* getTemplates(const string& filename); /** * 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 * (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 relativeFile the string in which the name of the configuration file is stored on success. * @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. */ -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. diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index a447b1ed..1b14ff74 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -41,26 +41,26 @@ using std::ifstream; #define RECONNECT_MISSING_SIGNAL 60 -result_t UserList::getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const { +result_t UserList::getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const { // name,secret,level[,level]* - if (row.empty()) { - row.push_back("name"); - row.push_back("secret"); - row.push_back("*level"); + if (row->empty()) { + row->push_back("name"); + row->push_back("secret"); + row->push_back("*level"); return RESULT_OK; } map seen; - for (auto& name : row) { - tolower(name); + for (auto& name : *row) { + tolower(&name); if (name == "name" || name == "secret") { if (seen.find(name) != seen.end()) { - errorDescription = "duplicate field " + name; + *errorDescription = "duplicate field " + name; return RESULT_ERR_INVALID_ARG; } } else if (name == "level") { name = "*level"; } else { - errorDescription = "unknown field " + name; + *errorDescription = "unknown field " + name; return RESULT_ERR_INVALID_ARG; } seen[name] = name; @@ -71,10 +71,10 @@ result_t UserList::getFieldMap(vector& row, string& errorDescription, co return RESULT_OK; } -result_t UserList::addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) { - string name = row["name"]; - string secret = row["secret"]; +result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) { + string name = (*row)["name"]; + string secret = (*row)["secret"]; if (name.empty()) { return RESULT_ERR_INVALID_ARG; } @@ -82,7 +82,7 @@ result_t UserList::addFromFile(map& row, vector< mapsecond.empty()) { if (!levels.empty()) { @@ -97,10 +97,10 @@ result_t UserList::addFromFile(map& row, vector< map0), m_enableHex(opt.enableHex), m_shutdown(false) { + m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex), m_shutdown(false) { // open Device result_t result = m_device->open(); if (result != RESULT_OK) { @@ -125,7 +125,7 @@ MainLoop::MainLoop(const struct options opt, Device *device, MessageMap* message m_logRawLastSymbol = SYN; if (opt.aclFile[0]) { 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) { 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_network = new Network(opt.localOnly, opt.port, opt.httpPort, &m_netQueue); 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"); } } @@ -247,9 +247,9 @@ void MainLoop::run() { MasterSymbolString master; SlaveSymbolString slave; 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) { - result = m_busHandler->sendAndWait(master, slave); + result = m_busHandler->sendAndWait(master, &slave); } } else { result = RESULT_ERR_NOTFOUND; @@ -259,7 +259,7 @@ void MainLoop::run() { result = m_busHandler->scanAndWait(m_initialScan, true); if (result == RESULT_OK) { 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()); } } @@ -301,37 +301,37 @@ void MainLoop::run() { if (socket) { socket->setTimeout(5); ostringstream ostr; - ostr << "{\"v\":\"" << PACKAGE_VERSION "\""; - ostr << ",\"r\":\"" << REVISION << "\""; + ostr << "{\"v\":\"" << PACKAGE_VERSION "\"" + << ",\"r\":\"" << REVISION << "\"" #if defined(__amd64__) || defined(__x86_64__) || defined(__ia64__) || defined(__IA64__) - ostr << ",\"a\":\"amd64\""; + << ",\"a\":\"amd64\"" #elif defined(__aarch64__) - ostr << ",\"a\":\"aarch64\""; + << ",\"a\":\"aarch64\"" #elif defined(__arm__) - ostr << ",\"a\":\"arm\""; + << ",\"a\":\"arm\"" #elif defined(__i386__) || defined(__i686__) - ostr << ",\"a\":\"i386\""; + << ",\"a\":\"i386\"" #elif defined(__mips__) - ostr << ",\"a\":\"mips\""; + << ",\"a\":\"mips\"" #else - ostr << ",\"a\":\"other\""; + << ",\"a\":\"other\"" #endif - ostr << ",\"u\":" << (now-start); + << ",\"u\":" << (now-start); if (m_reconnectCount) { ostr << ",\"rc\":" << m_reconnectCount; } - m_busHandler->formatUpdateInfo(ostr); + m_busHandler->formatUpdateInfo(&ostr); ostr << "}"; string str = ostr.str(); ostr.clear(); ostr.str(""); - ostr << "POST /updatecheck/ HTTP/1.0\r\n"; - ostr << "Host: ebusd.eu" << "\r\n"; - ostr << "User-Agent: " << PACKAGE_NAME << "/" << PACKAGE_VERSION << "\r\n"; - ostr << "Content-Type: application/json; charset=utf-8\r\n"; - ostr << "Content-Length: " << dec << str.length() << "\r\n"; - ostr << "\r\n"; - ostr << str; + ostr << "POST /updatecheck/ HTTP/1.0\r\n" + << "Host: ebusd.eu" << "\r\n" + << "User-Agent: " << PACKAGE_NAME << "/" << PACKAGE_VERSION << "\r\n" + << "Content-Type: application/json; charset=utf-8\r\n" + << "Content-Length: " << dec << str.length() << "\r\n" + << "\r\n" + << str; str = ostr.str(); const char* cstr = str.c_str(); size_t len = str.size(); @@ -417,7 +417,7 @@ void MainLoop::run() { bool connected = true; if (request.length() > 0) { 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()) { ostream << getResultCode(RESULT_EMPTY); @@ -438,7 +438,7 @@ void MainLoop::run() { messages = m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now); for (const auto message : messages) { ostream << message->getCircuit() << " " << message->getName() << " = " << dec; - message->decodeLastData(ostream); + message->decodeLastData(false, NULL, -1, 0, &ostream); 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) { 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& user, bool& reload) { +string MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, bool* listening, + string* user, bool* reload) { string token, previous; istringstream stream(data); vector args; @@ -528,7 +528,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn if (strcmp(str, "GET") == 0) { return executeGet(args, connected); } - connected = false; + *connected = false; 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); } if (cmd == "R" || cmd == "READ") { - return executeRead(args, getUserLevels(user)); + return executeRead(args, getUserLevels(*user)); } if (cmd == "W" || cmd == "WRITE") { - return executeWrite(args, getUserLevels(user)); + return executeWrite(args, getUserLevels(*user)); } if (cmd == "HEX") { if (m_enableHex) { @@ -565,7 +565,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return "ERR: command not enabled"; } if (cmd == "F" || cmd == "FIND") { - return executeFind(args, getUserLevels(user)); + return executeFind(args, getUserLevels(*user)); } if (cmd == "L" || cmd == "LISTEN") { return executeListen(args, listening); @@ -577,7 +577,7 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return executeGrab(args); } if (cmd == "SCAN") { - return executeScan(args, getUserLevels(user)); + return executeScan(args, getUserLevels(*user)); } if (cmd == "LOG") { return executeLog(args); @@ -589,14 +589,14 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return executeDump(args); } if (cmd == "RELOAD") { - reload = true; + *reload = true; return executeReload(args); } if (cmd == "Q" || cmd == "QUIT") { return executeQuit(args, connected); } if (cmd == "I" || cmd == "INFO") { - return executeInfo(args, user); + return executeInfo(args, *user); } if (cmd == "?" || cmd == "H" || cmd == "HELP") { return executeHelp(); @@ -604,8 +604,8 @@ string MainLoop::decodeMessage(const string& data, const bool isHttp, bool& conn return "ERR: command not found"; } -result_t MainLoop::parseHexMaster(vector &args, size_t argPos, MasterSymbolString& master, - symbol_t srcAddress) { +result_t MainLoop::parseHexMaster(const vector& args, size_t argPos, symbol_t srcAddress, + MasterSymbolString* master) { ostringstream msg; while (argPos < args.size()) { if ((args[argPos].length() % 2) != 0) { @@ -617,22 +617,22 @@ result_t MainLoop::parseHexMaster(vector &args, size_t argPos, MasterSym return RESULT_ERR_INVALID_ARG; } 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) { return ret; } if ((4+length)*2 != msg.str().size()) { return RESULT_ERR_INVALID_ARG; } - master.push_back(srcAddress == SYN ? m_address : srcAddress); - ret = master.parseHex(msg.str()); - if (ret == RESULT_OK && !isValidAddress(master[1])) { + master->push_back(srcAddress == SYN ? m_address : srcAddress); + ret = master->parseHex(msg.str()); + if (ret == RESULT_OK && !isValidAddress((*master)[1])) { ret = RESULT_ERR_INVALID_ADDR; } return ret; } -string MainLoop::executeAuth(vector &args, string &user) { +string MainLoop::executeAuth(const vector& args, string *user) { if (args.size() != 3) { return "usage: auth USER SECRET\n" " Authenticate with USER name and SECRET.\n" @@ -640,13 +640,13 @@ string MainLoop::executeAuth(vector &args, string &user) { " SECRET the secret string of the user"; } if (m_userList.checkSecret(args[1], args[2])) { - user = args[1]; + *user = args[1]; return getResultCode(RESULT_OK); } return "ERR: invalid user name or secret"; } -string MainLoop::executeRead(vector &args, const string levels) { +string MainLoop::executeRead(const vector& args, const string& levels) { size_t argPos = 1; bool hex = false, numeric = false, valueName = false; OutputFormat verbosity = 0; @@ -684,7 +684,7 @@ string MainLoop::executeRead(vector &args, const string levels) { argPos++; if (args.size() > argPos) { 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) { argPos = 0; // print usage break; @@ -708,7 +708,7 @@ string MainLoop::executeRead(vector &args, const string levels) { } bool dest = args[argPos] == "-d"; 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)) { return getResultCode(RESULT_ERR_INVALID_ADDR); } @@ -724,7 +724,7 @@ string MainLoop::executeRead(vector &args, const string levels) { break; } 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) { return getResultCode(RESULT_ERR_INVALID_NUM); } @@ -751,7 +751,7 @@ string MainLoop::executeRead(vector &args, const string levels) { if (hex && argPos > 0) { MasterSymbolString master; - result_t ret = parseHexMaster(args, argPos, master, srcAddress); + result_t ret = parseHexMaster(args, argPos, srcAddress, &master); if (ret != RESULT_OK) { return getResultCode(ret); } @@ -785,13 +785,13 @@ string MainLoop::executeRead(vector &args, const string levels) { // send message SlaveSymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); + ret = m_busHandler->sendAndWait(master, &slave); if (ret == RESULT_OK) { ret = message->storeLastData(master, slave); ostringstream result; if (ret == RESULT_OK) { - ret = message->decodeLastData(result); + ret = message->decodeLastData(false, NULL, -1, 0, &result); } if (ret >= RESULT_OK) { 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 &args, const string levels) { size_t pos = fieldName.find_last_of('.'); if (pos != string::npos) { result_t result = RESULT_OK; - fieldIndex = static_cast(parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, result)); + fieldIndex = static_cast(parseInt(fieldName.substr(pos+1).c_str(), 10, 0, MAX_POS, &result)); if (result == RESULT_OK) { fieldName = fieldName.substr(0, pos); } @@ -850,7 +850,7 @@ string MainLoop::executeRead(vector &args, const string levels) { Message* message = m_messages->find(circuit, args[argPos], levels, false); // adjust poll priority 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; result_t ret; @@ -866,8 +866,8 @@ string MainLoop::executeRead(vector &args, const string levels) { if (verbosity & OF_NAMES) { result << cacheMessage->getCircuit() << " " << cacheMessage->getName() << " "; } - ret = cacheMessage->decodeLastData(result, verbosity, false, fieldIndex == -2 ? NULL : fieldName.c_str(), - fieldIndex); + ret = cacheMessage->decodeLastData(false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex, verbosity, + &result); if (ret != RESULT_OK) { if (ret < RESULT_OK) { logError(lf_main, "read %s %s cached: %s", cacheMessage->getCircuit().c_str(), @@ -899,8 +899,8 @@ string MainLoop::executeRead(vector &args, const string levels) { if (verbosity & OF_NAMES) { result << message->getCircuit() << " " << message->getName() << " "; } - ret = message->decodeLastSlaveData(result, verbosity, false, fieldIndex == -2 ? NULL : fieldName.c_str(), - fieldIndex); + ret = message->decodeLastData(false, false, fieldIndex == -2 ? NULL : fieldName.c_str(), fieldIndex, verbosity, + &result); if (ret < RESULT_OK) { logError(lf_main, "read %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); @@ -915,7 +915,7 @@ string MainLoop::executeRead(vector &args, const string levels) { return result.str(); } -string MainLoop::executeWrite(vector &args, const string levels) { +string MainLoop::executeWrite(const vector& args, const string levels) { size_t argPos = 1; bool hex = false; string circuit; @@ -931,7 +931,7 @@ string MainLoop::executeWrite(vector &args, const string levels) { } bool dest = args[argPos] == "-d"; 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)) { return getResultCode(RESULT_ERR_INVALID_ADDR); } @@ -960,7 +960,7 @@ string MainLoop::executeWrite(vector &args, const string levels) { if (hex && argPos > 0) { MasterSymbolString master; - result_t ret = parseHexMaster(args, argPos, master, srcAddress); + result_t ret = parseHexMaster(args, argPos, srcAddress, &master); if (ret != RESULT_OK) { return getResultCode(ret); } @@ -983,14 +983,14 @@ string MainLoop::executeWrite(vector &args, const string levels) { } // send message SlaveSymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); + ret = m_busHandler->sendAndWait(master, &slave); if (ret == RESULT_OK) { // also update read messages ret = message->storeLastData(master, slave); ostringstream result; if (ret == RESULT_OK) { - ret = message->decodeLastData(result); + ret = message->decodeLastData(false, NULL, -1, 0, &result); } if (ret >= RESULT_OK) { logInfo(lf_main, "write hex %s %s cache update: %s", message->getCircuit().c_str(), @@ -1054,7 +1054,7 @@ string MainLoop::executeWrite(vector &args, const string levels) { 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()) { logNotice(lf_main, "write %s %s: decode %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(ret)); @@ -1072,7 +1072,7 @@ string MainLoop::executeWrite(vector &args, const string levels) { return result.str(); } -string MainLoop::executeHex(vector &args) { +string MainLoop::executeHex(const vector& args) { size_t argPos = 1; symbol_t srcAddress = SYN; if (args.size() > argPos && args[argPos] == "-s") { @@ -1081,7 +1081,7 @@ string MainLoop::executeHex(vector &args) { argPos = 0; // print usage } else { 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)) { return getResultCode(RESULT_ERR_INVALID_ADDR); } @@ -1095,7 +1095,7 @@ string MainLoop::executeHex(vector &args) { if (argPos > 0) { MasterSymbolString master; - result_t ret = parseHexMaster(args, argPos, master, srcAddress); + result_t ret = parseHexMaster(args, argPos, srcAddress, &master); if (ret != RESULT_OK) { return getResultCode(ret); } @@ -1103,7 +1103,7 @@ string MainLoop::executeHex(vector &args) { // send message SlaveSymbolString slave; - ret = m_busHandler->sendAndWait(master, slave); + ret = m_busHandler->sendAndWait(master, &slave); if (ret == RESULT_OK) { if (master[1] == BROADCAST) { @@ -1127,10 +1127,11 @@ string MainLoop::executeHex(vector &args) { " Dx data byte(s) to send"; } -string MainLoop::executeFind(vector &args, string levels) { +string MainLoop::executeFind(const vector& args, const string& levels) { size_t argPos = 1; 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; vector fieldNames; string circuit; @@ -1166,7 +1167,7 @@ string MainLoop::executeFind(vector &args, string levels) { argPos = 0; // print usage break; } - if (!Message::extractFieldNames(args[argPos], fieldNames)) { + if (!Message::extractFieldNames(args[argPos], true, &fieldNames)) { argPos = 0; // print usage break; } @@ -1191,7 +1192,7 @@ string MainLoop::executeFind(vector &args, string levels) { } withPassive = true; } else if (args[argPos] == "-a") { - withRead = withWrite = withPassive = true; + withRead = withWrite = withPassive = withConditions = true; } else if (args[argPos] == "-d") { onlyWithData = true; } else if (args[argPos] == "-h") { @@ -1206,7 +1207,7 @@ string MainLoop::executeFind(vector &args, string levels) { argPos = 0; // print usage break; } - result_t result = Message::parseId(args[argPos], id); + result_t result = Message::parseId(args[argPos], &id); if (result != RESULT_OK) { return getResultCode(result); } @@ -1227,7 +1228,7 @@ string MainLoop::executeFind(vector &args, string levels) { argPos = 0; // print usage break; } - levels = args[argPos]; + useLevels = args[argPos]; userLevel = false; } else { argPos = 0; // print usage @@ -1244,7 +1245,7 @@ string MainLoop::executeFind(vector &args, string levels) { " -r limit to active read messages (default: read + passive)\n" " -w limit to active write 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" " -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" @@ -1256,8 +1257,8 @@ string MainLoop::executeFind(vector &args, string levels) { " -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')"; } - deque messages = m_messages->findAll( - circuit, args.size() == argPos ? "" : args[argPos], levels, exact, withRead, withWrite, withPassive, userLevel); + deque messages = m_messages->findAll(circuit, args.size() == argPos ? "" : args[argPos], useLevels, + exact, withRead, withWrite, withPassive, userLevel, !withConditions); bool found = false; ostringstream result; @@ -1274,12 +1275,12 @@ string MainLoop::executeFind(vector &args, string levels) { if (found) { result << endl; } - message->dump(result); + message->dump(NULL, withConditions, &result); } else if (!fieldNames.empty()) { if (found) { result << endl; } - message->dump(result, &fieldNames); + message->dump(&fieldNames, withConditions, &result); } else { if (found) { result << endl; @@ -1287,10 +1288,13 @@ string MainLoop::executeFind(vector &args, string levels) { result << message->getCircuit() << " " << message->getName() << " = "; if (lastup == 0) { result << "no data stored"; + if (!message->isAvailable()) { + result << " (message not available due to condition)"; + } } else if (hexFormat) { result << message->getLastMasterData().getStr() << " / " << message->getLastSlaveData().getStr(); } else { - result_t ret = message->decodeLastData(result, verbosity); + result_t ret = message->decodeLastData(false, NULL, -1, verbosity, &result); if (ret != RESULT_OK) { result << " (" << getResultCode(ret) << " for " << message->getLastMasterData().getStr() @@ -1335,12 +1339,12 @@ string MainLoop::executeFind(vector &args, string levels) { return result.str(); } -string MainLoop::executeListen(vector &args, bool& listening) { +string MainLoop::executeListen(const vector& args, bool* listening) { if (args.size() == 1) { if (listening) { return "listen continued"; } - listening = true; + *listening = true; return "listen started"; } @@ -1348,11 +1352,11 @@ string MainLoop::executeListen(vector &args, bool& listening) { return "usage: listen [stop]\n" " Listen for updates or stop it."; } - listening = false; + *listening = false; return "listen stopped"; } -string MainLoop::executeState(vector &args) { +string MainLoop::executeState(const vector& args) { if (args.size() == 0) { return "usage: state\n" " Report bus state."; @@ -1368,7 +1372,7 @@ string MainLoop::executeState(vector &args) { return "no signal"; } -string MainLoop::executeGrab(vector &args) { +string MainLoop::executeGrab(const vector& args) { if (args.size() == 1) { return m_busHandler->enableGrab(true) ? "grab started" : "grab continued"; } @@ -1378,12 +1382,12 @@ string MainLoop::executeGrab(vector &args) { if (args.size() >= 2 && args[1] == "result") { if (args.size() == 2 || args[2] == "all") { ostringstream result; - m_busHandler->formatGrabResult(args.size() == 2, result); + m_busHandler->formatGrabResult(args.size() == 2, false, &result); return result.str(); } if (args.size() == 3 || args[2] == "decode") { ostringstream result; - m_busHandler->formatGrabResult(true, result, true); + m_busHandler->formatGrabResult(true, true, &result); return result.str(); } } @@ -1392,7 +1396,7 @@ string MainLoop::executeGrab(vector &args) { " Start or stop grabbing, or report/decode unknown or all grabbed messages."; } -string MainLoop::executeScan(vector &args, string levels) { +string MainLoop::executeScan(const vector& args, string levels) { if (args.size() == 1) { result_t result = m_busHandler->startScan(false, levels); if (result == RESULT_ERR_DUPLICATE) { @@ -1415,12 +1419,12 @@ string MainLoop::executeScan(vector &args, string levels) { if (args[1] == "result") { ostringstream ret; - m_busHandler->formatScanResult(ret); + m_busHandler->formatScanResult(&ret); return ret.str(); } 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)) { result = RESULT_ERR_INVALID_ADDR; } @@ -1432,7 +1436,7 @@ string MainLoop::executeScan(vector &args, string levels) { return getResultCode(result); } ostringstream ret; - if (!m_busHandler->formatScanResult(dstAddress, ret, false)) { + if (!m_busHandler->formatScanResult(dstAddress, false, &ret)) { return getResultCode(RESULT_EMPTY); } return ret.str(); @@ -1443,7 +1447,7 @@ string MainLoop::executeScan(vector &args, string levels) { " Scan seen slaves, all slaves (full), a single slave (address ZZ), or report scan result."; } -string MainLoop::executeLog(vector &args) { +string MainLoop::executeLog(const vector& args) { if (args.size() == 1) { ostringstream ret; for (int val = 0; val < lf_COUNT; val++) { @@ -1469,7 +1473,7 @@ string MainLoop::executeLog(vector &args) { return getResultCode(RESULT_ERR_INVALID_ARG); } -string MainLoop::executeRaw(vector &args) { +string MainLoop::executeRaw(const vector& args) { bool bytes = args.size() == 2 && args[1] == "bytes"; if (args.size() != 1 && !bytes) { return "usage: raw [bytes]\n" @@ -1487,7 +1491,7 @@ string MainLoop::executeRaw(vector &args) { return enabled ? "raw logging enabled" : "raw logging disabled"; } -string MainLoop::executeDump(vector &args) { +string MainLoop::executeDump(const vector& args) { if (args.size() != 1) { return "usage: dump\n" " Toggle binary dump of received bytes."; @@ -1500,7 +1504,7 @@ string MainLoop::executeDump(vector &args) { return enabled ? "dump enabled" : "dump disabled"; } -string MainLoop::executeReload(vector &args) { +string MainLoop::executeReload(const vector& args) { if (args.size() != 1) { return "usage: reload\n" " Reload CSV config files."; @@ -1510,7 +1514,7 @@ string MainLoop::executeReload(vector &args) { return getResultCode(result); } -string MainLoop::executeInfo(vector &args, const string user) { +string MainLoop::executeInfo(const vector& args, const string& user) { if (args.size() == 0) { return "usage: info\n" " Report information about the daemon, the configuration, and seen devices."; @@ -1528,25 +1532,25 @@ string MainLoop::executeInfo(vector &args, const string user) { result << "access: " << levels << "\n"; } if (m_busHandler->hasSignal()) { - result << "signal: acquired\n"; - result << "symbol rate: " << m_busHandler->getSymbolRate() << "\n"; - result << "max symbol rate: " << m_busHandler->getMaxSymbolRate() << "\n"; + result << "signal: acquired\n" + << "symbol rate: " << m_busHandler->getSymbolRate() << "\n" + << "max symbol rate: " << m_busHandler->getMaxSymbolRate() << "\n"; } else { result << "signal: no signal\n"; } - result << "reconnects: " << m_reconnectCount << "\n"; - result << "masters: " << m_busHandler->getMasterCount() << "\n"; - result << "messages: " << m_messages->size() << "\n"; - result << "conditional: " << m_messages->sizeConditional() << "\n"; - result << "poll: " << m_messages->sizePoll() << "\n"; - result << "update: " << m_messages->sizePassive(); - m_busHandler->formatSeenInfo(result); + result << "reconnects: " << m_reconnectCount << "\n" + << "masters: " << m_busHandler->getMasterCount() << "\n" + << "messages: " << m_messages->size() << "\n" + << "conditional: " << m_messages->sizeConditional() << "\n" + << "poll: " << m_messages->sizePoll() << "\n" + << "update: " << m_messages->sizePassive(); + m_busHandler->formatSeenInfo(&result); return result.str(); } -string MainLoop::executeQuit(vector &args, bool& connected) { +string MainLoop::executeQuit(const vector& args, bool *connected) { if (args.size() == 1) { - connected = false; + *connected = false; return "connection closed"; } return "usage: quit\n" @@ -1579,7 +1583,7 @@ string MainLoop::executeHelp() { " help|? Print help help [COMMAND], COMMMAND ?"; } -string MainLoop::executeGet(vector &args, bool& connected) { +string MainLoop::executeGet(const vector& args, bool* connected) { result_t ret = RESULT_OK; bool numeric = false, valueName = false, required = false, full = false; OutputFormat verbosity = OF_NAMES; @@ -1616,9 +1620,9 @@ string MainLoop::executeGet(vector &args, bool& connected) { qname = token; } 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") { - 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") { exact = value.length() == 0 || value == "1" || value == "true"; } else if (qname == "verbose") { @@ -1664,7 +1668,7 @@ string MainLoop::executeGet(vector &args, bool& connected) { continue; } if (pollPriority > 0 && message->setPollPriority(pollPriority)) { - m_messages->addPollMessage(message); + m_messages->addPollMessage(false, message); } time_t lastup = message->getLastUpdateTime(); if (lastup == 0 && required) { @@ -1691,11 +1695,11 @@ string MainLoop::executeGet(vector &args, bool& connected) { lastCircuit = message->getCircuit(); result << "\n \"" << lastCircuit << "\": {"; 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; } } - message->decode(result, verbosity, !first); + message->decode(!first, NULL, verbosity, &result); first = false; } @@ -1727,8 +1731,8 @@ string MainLoop::executeGet(vector &args, bool& connected) { result << "\n}"; type = 6; } - connected = false; - return formatHttpResult(ret, result, type); + *connected = false; + return formatHttpResult(ret, type, result); } // request for "/data..." if (uri.length() < 1 || uri[0] != '/' || uri.find("//") != string::npos || uri.find("..") != string::npos) { @@ -1770,11 +1774,11 @@ string MainLoop::executeGet(vector &args, bool& connected) { } } } - connected = false; - return formatHttpResult(ret, result, type); + *connected = false; + 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() : ""; result.str(""); result.clear(); diff --git a/src/ebusd/mainloop.h b/src/ebusd/mainloop.h index b8a28b31..d228510a 100644 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -46,7 +46,7 @@ class UserList : public UserInfo, public MappedFileReader { * Constructor. * @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()) { string levels = defaultLevels; transform(levels.begin(), levels.end(), levels.begin(), [](unsigned char c) { @@ -62,25 +62,25 @@ class UserList : public UserInfo, public MappedFileReader { virtual ~UserList() {} // @copydoc - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override; + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override; // @copydoc - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override; + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override; // @copydoc - bool hasUser(const string user) const override { + bool hasUser(const string& user) const override { return m_userLevels.find(user) != m_userLevels.end(); } // @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); return it != m_userSecrets.end() && it->second == secret; } // @copydoc - string getLevels(const string user) const override { + string getLevels(const string& user) const override { auto it = m_userLevels.find(user); return it == m_userLevels.end() ? "" : it->second; } @@ -105,7 +105,7 @@ class MainLoop : public Thread, DeviceListener { * @param device the @a Device 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. @@ -130,7 +130,7 @@ class MainLoop : public Thread, DeviceListener { void addMessage(NetMessage* message) { m_netQueue.push(message); } // @copydoc - void notifyDeviceData(const symbol_t symbol, bool received) override; + void notifyDeviceData(symbol_t symbol, bool received) override; protected: @@ -149,26 +149,26 @@ class MainLoop : public Thread, DeviceListener { * @param reload set to true when the configuration files were reloaded. * @return result string to send back to the client. */ - string decodeMessage(const string& data, const bool isHttp, bool& connected, bool& listening, - string& user, bool& reload); + string decodeMessage(const string& data, bool isHttp, bool* connected, bool* listening, + string* user, bool* reload); /** * Parse the hex master message from the remaining arguments. * @param args the arguments passed to the command. * @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 master the @a MasterSymbolString to write the data to. * @return the result from parsing the arguments. */ - result_t parseHexMaster(vector &args, size_t argPos, MasterSymbolString& master, - symbol_t srcAddress = SYN); + result_t parseHexMaster(const vector& args, size_t argPos, symbol_t srcAddress, + MasterSymbolString* master); /** * Get the access levels associated with the specified user name. * @param user the user name, or empty for default levels. * @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. @@ -176,7 +176,7 @@ class MainLoop : public Thread, DeviceListener { * @param user the current user name to set to the new user name on success. * @return the result string. */ - string executeAuth(vector &args, string &user); + string executeAuth(const vector& args, string *user); /** * Execute the read command. @@ -184,7 +184,7 @@ class MainLoop : public Thread, DeviceListener { * @param levels the current user's access levels. * @return the result string. */ - string executeRead(vector &args, const string levels); + string executeRead(const vector& args, const string& levels); /** * Execute the write command. @@ -192,14 +192,14 @@ class MainLoop : public Thread, DeviceListener { * @param levels the current user's access levels. * @return the result string. */ - string executeWrite(vector &args, const string levels); + string executeWrite(const vector& args, const string levels); /** * Execute the hex command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeHex(vector &args); + string executeHex(const vector& args); /** * Execute the find command. @@ -207,7 +207,7 @@ class MainLoop : public Thread, DeviceListener { * @param levels the current user's access levels. * @return the result string. */ - string executeFind(vector &args, string levels); + string executeFind(const vector& args, const string& levels); /** * 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. * @return the result string. */ - string executeListen(vector &args, bool& listening); + string executeListen(const vector& args, bool* listening); /** * Execute the state command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeState(vector &args); + string executeState(const vector& args); /** * Execute the grab command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeGrab(vector &args); + string executeGrab(const vector& args); /** * Execute the scan command. @@ -237,35 +237,35 @@ class MainLoop : public Thread, DeviceListener { * @param levels the current user's access levels. * @return the result string. */ - string executeScan(vector &args, const string levels); + string executeScan(const vector& args, const string levels); /** * Execute the log command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeLog(vector &args); + string executeLog(const vector& args); /** * Execute the raw command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeRaw(vector &args); + string executeRaw(const vector& args); /** * Execute the dump command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeDump(vector &args); + string executeDump(const vector& args); /** * Execute the reload command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. * @return the result string. */ - string executeReload(vector &args); + string executeReload(const vector& args); /** * Execute the info command. @@ -273,7 +273,7 @@ class MainLoop : public Thread, DeviceListener { * @param user the current user name. * @return the result string. */ - string executeInfo(vector &args, const string user); + string executeInfo(const vector& args, const string& user); /** * 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. * @return the result string. */ - string executeQuit(vector &args, bool& connected); + string executeQuit(const vector& args, bool *connected); /** * 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. * @return the result string. */ - string executeGet(vector &args, bool& connected); + string executeGet(const vector& args, bool* connected); /** * Format the HTTP answer to the result string. * @param ret the result code of handling the request. - * @param result the @a ostringstream containing the successful result. * @param type the content type. + * @param result the @a ostringstream containing the successful result. * @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. */ Device* m_device; diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index f6ae4ee4..c772e303 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -81,7 +81,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { break; 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) { argp_error(state, "invalid mqttport"); 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. * @return true on success, false on malformed topic template. */ -bool parseTopic(const string topic, vector &strs, vector &fields) { +bool parseTopic(const string& topic, vector* strs, vector* fields) { size_t lastpos = 0; size_t end = topic.length(); vector columns; @@ -205,18 +205,18 @@ bool parseTopic(const string topic, vector &strs, vector &fields return false; } string fieldName = knownFieldNames[idx]; - for (const auto& it : fields) { + for (const auto& it : *fields) { if (it == fieldName) { return false; // duplicate column } } - strs.push_back(topic.substr(lastpos, pos-lastpos)); - fields.push_back(fieldName); + strs->push_back(topic.substr(lastpos, pos-lastpos)); + fields->push_back(fieldName); lastpos = pos+1+len; pos = topic.find('%', lastpos); } if (lastpos < end) { - strs.push_back(topic.substr(lastpos, end-lastpos)); + strs->push_back(topic.substr(lastpos, end-lastpos)); } return true; } @@ -259,7 +259,7 @@ MqttHandler::MqttHandler(UserInfo* userInfo, BusHandler* busHandler, MessageMap* bool enabled = g_port != 0; m_publishByField = false; 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); return; } @@ -386,7 +386,7 @@ void on_message( 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('/'); if (pos == string::npos) { 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()); } ostringstream ostream; - publishMessage(message, ostream); + publishMessage(message, &ostream); } -void MqttHandler::notifyUpdateCheckResult(string checkResult) { +void MqttHandler::notifyUpdateCheckResult(const string& checkResult) { if (checkResult != m_lastUpdateCheckResult) { m_lastUpdateCheckResult = checkResult; publishTopic(m_globalTopic+"updatecheck", checkResult.empty() ? "OK" : checkResult); @@ -525,7 +525,7 @@ void MqttHandler::run() { updates.str(""); updates.clear(); updates << dec; - publishMessage(it.first, updates); + publishMessage(it.first, &updates); } } 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; for (size_t i = 0; i < m_topicStrs.size(); i++) { ret << m_topicStrs[i]; @@ -568,15 +568,15 @@ string MqttHandler::getTopic(Message* message, ssize_t fieldIndex) { if (m_topicFields[i] == "fields" && fieldIndex >= 0) { ret << message->getFieldName(fieldIndex); // TODO skip ignored fields } else { - message->dumpField(ret, m_topicFields[i]); + message->dumpField(m_topicFields[i], false, &ret); } } } return ret.str(); } -void MqttHandler::publishMessage(Message* message, ostringstream& updates) { - result_t result = message->decodeLastData(updates); +void MqttHandler::publishMessage(const Message* message, ostringstream* updates) { + result_t result = message->decodeLastData(false, NULL, -1, 0, updates); if (result != RESULT_OK) { logOtherError("mqtt", "decode %s %s: %s", message->getCircuit().c_str(), message->getName().c_str(), getResultCode(result)); @@ -584,7 +584,7 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) { } if (m_publishByField) { ssize_t index = 0; - istringstream input(updates.str()); + istringstream input(updates->str()); string token; while (getline(input, token, UI_FIELD_SEPARATOR)) { string topic = getTopic(message, index); @@ -592,11 +592,11 @@ void MqttHandler::publishMessage(Message* message, ostringstream& updates) { index++; } } 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()); mosquitto_publish(m_mosquitto, NULL, topic.c_str(), (uint32_t)data.size(), reinterpret_cast(data.c_str()), 0, retain); diff --git a/src/ebusd/mqtthandler.h b/src/ebusd/mqtthandler.h index 04dc9823..98f176bf 100644 --- a/src/ebusd/mqtthandler.h +++ b/src/ebusd/mqtthandler.h @@ -78,10 +78,10 @@ class MqttHandler : public DataSink, public DataSource, public Thread { * @param topic the topic string. * @param data the data string. */ - void notifyTopic(string topic, string data); + void notifyTopic(const string& topic, const string& data); // @copydoc - void notifyUpdateCheckResult(string checkResult) override; + void notifyUpdateCheckResult(const string& checkResult) override; protected: // @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. * @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. * @param message the @a Message to publish. * @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. @@ -115,7 +115,7 @@ class MqttHandler : public DataSink, public DataSource, public Thread { * @param data the data string. * @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. */ MessageMap* m_messages; diff --git a/src/ebusd/network.cpp b/src/ebusd/network.cpp index 348304ec..5e3de66b 100644 --- a/src/ebusd/network.cpp +++ b/src/ebusd/network.cpp @@ -35,6 +35,40 @@ int Connection::m_ids = 0; #define POLLRDHUP 0 #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(((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() { int ret; struct timespec tdiff; diff --git a/src/ebusd/network.h b/src/ebusd/network.h index 8fcc309e..a2c0ae6d 100644 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -76,37 +76,7 @@ class NetMessage { * @param request the request data from the client. * @return true when the request is complete and the response shall be prepared. */ - bool add(string 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(((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; - } + bool add(const char* request); /** * Return whether this is a HTTP message. diff --git a/src/lib/ebus/contrib/tem.cpp b/src/lib/ebus/contrib/tem.cpp index 80cfdec4..a810c6cb 100644 --- a/src/lib/ebus/contrib/tem.cpp +++ b/src/lib/ebus/contrib/tem.cpp @@ -39,7 +39,7 @@ void contrib_tem_register() { 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) { divisor = 1; } @@ -47,27 +47,26 @@ result_t TemParamDataType::derive(int divisor, size_t bitCount, const NumberData bitCount = m_bitCount; } if (divisor == 1 && bitCount == 16) { - derived = this; + *derived = this; return RESULT_OK; } return RESULT_ERR_INVALID_ARG; } -result_t TemParamDataType::readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const { +result_t TemParamDataType::readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const { unsigned int value = 0; - result_t result = readRawValue(input, offset, length, value); + result_t result = readRawValue(offset, length, input, &value); if (result != RESULT_OK) { return result; } if (value == m_replacement) { if (outputFormat & OF_JSON) { - output << "null"; + *output << "null"; } else { - output << NULL_VALUE; + *output << NULL_VALUE; } return RESULT_OK; } @@ -80,31 +79,29 @@ result_t TemParamDataType::readSymbols(const SymbolString& input, num = (value & 0x7f); // num in bits 0...6 } if (outputFormat & OF_JSON) { - output << '"'; + *output << '"'; } - output << setfill('0') << setw(2) << dec << static_cast(grp) << '-' << setw(3) << static_cast(num); + *output << setfill('0') << setw(2) << dec << static_cast(grp) << '-' << setw(3) << static_cast(num); if (outputFormat & OF_JSON) { - output << '"'; + *output << '"'; } - output << setfill(' ') << setw(0); // reset + *output << setfill(' ') << setw(0); // reset return RESULT_OK; } -result_t TemParamDataType::writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const { +result_t TemParamDataType::writeSymbols(const size_t offset, const size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const { unsigned int value; int grp, num; - string token; - const char* str = input.str().c_str(); - if (strcmp(str, NULL_VALUE) == 0) { + if (input->str() == NULL_VALUE) { value = m_replacement; // replacement value } else { - if (input.eof() || !getline(input, token, '-')) { + string token; + if (input->eof() || !getline(*input, token, '-')) { return RESULT_ERR_EOF; // incomplete } - str = token.c_str(); + const char* str = token.c_str(); if (str == NULL || *str == 0) { return RESULT_ERR_EOF; // input too short } @@ -113,7 +110,7 @@ result_t TemParamDataType::writeSymbols(istringstream& input, if (strEnd == NULL || strEnd == str || *strEnd != 0) { return RESULT_ERR_INVALID_NUM; // invalid value } - if (input.eof() || !getline(input, token, '-')) { + if (input->eof() || !getline(*input, token, '-')) { return RESULT_ERR_EOF; // incomplete } str = token.c_str(); @@ -128,7 +125,7 @@ result_t TemParamDataType::writeSymbols(istringstream& input, if (grp < 0 || grp > 0x1f || num < 0 || num > 0x7f) { 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 } else { value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6 diff --git a/src/lib/ebus/contrib/tem.h b/src/lib/ebus/contrib/tem.h index 07901541..e8835ff9 100644 --- a/src/lib/ebus/contrib/tem.h +++ b/src/lib/ebus/contrib/tem.h @@ -46,21 +46,19 @@ class TemParamDataType : public NumberDataType { * Constructs a new instance. * @param id the type identifier. */ - explicit TemParamDataType(const string id) + explicit TemParamDataType(const string& id) : NumberDataType(id, 16, 0, 0xffff, 0, 0xffff, 0, NULL) {} // @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 - result_t readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(size_t offset, size_t length, const SymbolString& input, + const OutputFormat outputFormat, ostream* output) const override; // @copydoc - result_t writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const override; }; /** diff --git a/src/lib/ebus/contrib/test/test_tem.cpp b/src/lib/ebus/contrib/test/test_tem.cpp index 7e7d81b4..e278d811 100644 --- a/src/lib/ebus/contrib/test/test_tem.cpp +++ b/src/lib/ebus/contrib/test/test_tem.cpp @@ -54,31 +54,31 @@ class TestReader : public MappedFileReader { TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest) : MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest), m_fields(NULL) {} - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override { - if (row.empty()) { - row.push_back("*name"); - row.push_back("part"); - row.push_back("type"); - row.push_back("divisor/values"); - row.push_back("unit"); - row.push_back("comment"); + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override { + if (row->empty()) { + row->push_back("*name"); + row->push_back("part"); + row->push_back("type"); + row->push_back("divisor/values"); + row->push_back("unit"); + row->push_back("comment"); return RESULT_OK; } - if (row[0][0] != '*') { + if ((*row)[0][0] != '*') { return RESULT_ERR_INVALID_ARG; } return RESULT_OK; // leave it to DataField::create } - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override { - if (!row.empty() || subRows.empty()) { + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override { + if (!row->empty() || subRows->empty()) { cout << "read line " << static_cast(lineNo) << ": read error: got " - << static_cast(row.size()) << "/0 main, " << static_cast(subRows.size()) + << static_cast(row->size()) << "/0 main, " << static_cast(subRows->size()) << "/>=3 sub" << endl; return RESULT_ERR_EOF; } cout << "read line " << static_cast(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: DataFieldTemplates* m_templates; @@ -118,7 +118,7 @@ int main() { istringstream dummystr("#"); string errorDescription; vector row; - templates->readLineFromStream(dummystr, errorDescription, "inline", lineNo, row); + templates->readLineFromStream("inline", false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL); const DataField* fields = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; @@ -156,7 +156,7 @@ int main() { lineNo = 0; dummystr.clear(); 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) { cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription << endl; @@ -164,7 +164,7 @@ int main() { continue; } 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; if (result != RESULT_OK) { @@ -178,7 +178,7 @@ int main() { continue; } cout << "\"" << check[0] << "\"=\""; - fields->dump(cout); + fields->dump(&cout); cout << "\": create OK" << endl; ostringstream output; @@ -194,21 +194,21 @@ int main() { cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; 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) { - 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 (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 = true; } else { - cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] + cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3] << "< OK" << endl; } } 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 = true; } else { @@ -217,21 +217,21 @@ int main() { } istringstream input(expectStr); - result = fields->write(input, writeMstr, 0); + result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeMstr, NULL); if (result >= RESULT_OK) { - result = fields->write(input, writeSstr, 0); + result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeSstr, NULL); } if (failedWrite) { if (result >= RESULT_OK) { - cout << " failed write " << fields->getName() << " >" + cout << " failed write " << fields->getName(-1) << " >" << expectStr << "< error: unexpectedly succeeded" << endl; error = true; } else { - cout << " failed write " << fields->getName() << " >" + cout << " failed write " << fields->getName(-1) << " >" << expectStr << "< OK" << endl; } } else if (result < RESULT_OK) { - cout << " write " << fields->getName() << " >" << expectStr + cout << " write " << fields->getName(-1) << " >" << expectStr << "< error: " << getResultCode(result) << endl; error = true; } else { diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index d2cade97..f71665b2 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -46,7 +46,7 @@ static const char* defaultTemplateFieldMap[] = { -string getDataFieldName(const string name, bool& supportsLanguage) { +string getDataFieldName(const string& name, bool* supportsLanguage) { if (name.find("name") != string::npos || name.find("field") != string::npos) { return "name"; } @@ -58,12 +58,12 @@ string getDataFieldName(const string name, bool& supportsLanguage) { } if (name.find("divisor") != string::npos) { if (name.find("values") != string::npos) { - supportsLanguage = true; + *supportsLanguage = true; return "divisor/values"; } return "divisor"; } - supportsLanguage = true; + *supportsLanguage = true; if (name == "values" || name == "unit") { return name; } @@ -74,39 +74,37 @@ string getDataFieldName(const string name, bool& supportsLanguage) { } -const string AttributedItem::formatInt(size_t value) { +string AttributedItem::formatInt(size_t value) { ostringstream stream; stream << dec << static_cast(value); return stream.str(); } -const string AttributedItem::pluck(map& row, string key) { - const auto it = row.find(key); - if (it == row.end()) { +string AttributedItem::pluck(const string& key, map* row) { + const auto it = row->find(key); + if (it == row->end()) { return ""; } const string ret = it->second; - row.erase(it); + row->erase(it); return ret; } -void AttributedItem::dumpString(ostream& output, const string str, const bool prependFieldSeparator) { +void AttributedItem::dumpString(bool prependFieldSeparator, const string& str, ostream* output) { if (prependFieldSeparator) { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } if (str.find_first_of(FIELD_SEPARATOR) == string::npos) { - output << str; + *output << str; } else { - output << TEXT_SEPARATOR << str << TEXT_SEPARATOR; + *output << TEXT_SEPARATOR << str << TEXT_SEPARATOR; } } -void AttributedItem::appendJson(ostream& output, const string name, const string value, - const bool prependFieldSeparator, bool asString) { - bool plain; - if (asString) { - plain = false; - } else { +void AttributedItem::appendJson(bool prependFieldSeparator, const string& name, const string& value, + bool asString, ostream* output) { + bool plain = !asString; + if (plain) { plain = value == "false" || value == "true"; if (!plain) { const char* str = value.c_str(); @@ -116,65 +114,60 @@ void AttributedItem::appendJson(ostream& output, const string name, const string } } if (prependFieldSeparator) { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } - output << " \"" << name << "\": "; + *output << " \"" << name << "\": "; if (plain) { - output << value; + *output << value; } else { - output << '"' << value << '"'; + *output << '"' << value << '"'; } } -void AttributedItem::mergeAttributes(map& attributes) const { +void AttributedItem::mergeAttributes(map* attributes) const { for (const auto& entry : m_attributes) { - const auto it = attributes.find(entry.first); - if (it == attributes.end() || it->second.empty()) { - attributes[entry.first] = entry.second; + const auto it = attributes->find(entry.first); + if (it == attributes->end() || it->second.empty()) { + (*attributes)[entry.first] = entry.second; } } } -void AttributedItem::dumpAttribute(ostream& output, const string name, const bool prependFieldSeparator) const { - dumpString(output, getAttribute(name), prependFieldSeparator); +void AttributedItem::dumpAttribute(bool prependFieldSeparator, const string& name, ostream* output) const { + dumpString(prependFieldSeparator, getAttribute(name), output); } -string AttributedItem::getAttribute(const string name) const { - const auto it = m_attributes.find(name); - return it == m_attributes.end() ? "" : it->second; -} - -bool AttributedItem::appendAttribute(ostringstream& output, OutputFormat outputFormat, const string name, - const bool onlyIfNonEmpty, const string prefix, const string suffix) const { +bool AttributedItem::appendAttribute(OutputFormat outputFormat, const string& name, bool onlyIfNonEmpty, + const string& prefix, const string& suffix, ostream* output) const { const auto it = m_attributes.find(name); string value = it == m_attributes.end() ? "" : it->second; if (onlyIfNonEmpty && value.empty()) { return false; } if (outputFormat & OF_JSON) { - appendJson(output, name, value, true); + appendJson(true, name, value, false, output); } else { - output << " " << prefix << value << suffix; + *output << " " << prefix << value << suffix; } return true; } -bool AttributedItem::appendAttributes(ostringstream& output, OutputFormat outputFormat) const { +bool AttributedItem::appendAttributes(OutputFormat outputFormat, ostream* output) const { bool ret = false; if ((outputFormat & OF_UNITS)) { - ret = appendAttribute(output, outputFormat, "unit") || ret; + ret = appendAttribute(outputFormat, "unit", true, "", "", output) || ret; } if ((outputFormat & OF_COMMENTS)) { - ret = appendAttribute(output, outputFormat, "comment", true, "[", "]") || ret; + ret = appendAttribute(outputFormat, "comment", true, "[", "]", output) || ret; } if (outputFormat & OF_ALL_ATTRS) { for (const auto entry : m_attributes) { ret = true; if (!entry.second.empty() && entry.first != "unit" && entry.first != "comment") { if (outputFormat & OF_JSON) { - appendJson(output, entry.first, entry.second); + appendJson(true, entry.first, entry.second, false, output); } else { - output << " " << entry.first << "=" << entry.second; + *output << " " << entry.first << "=" << entry.second; } } } @@ -182,37 +175,40 @@ bool AttributedItem::appendAttributes(ostringstream& output, OutputFormat output return ret; } +string AttributedItem::getAttribute(const string& name) const { + const auto it = m_attributes.find(name); + return it == m_attributes.end() ? "" : it->second; +} -result_t DataField::create(vector< map >& rows, string& errorDescription, - DataFieldTemplates* templates, const DataField*& returnField, - const bool isWriteMessage, - const bool isTemplate, const bool isBroadcastOrMasterDestination, - const size_t maxFieldLength) { + +result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcastOrMasterDestination, + size_t maxFieldLength, const DataFieldTemplates* templates, vector< map >* rows, + string* errorDescription, const DataField** returnField) { // template: name,[,part]basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]] // std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]] vector fields; string firstName; result_t result = RESULT_OK; - if (rows.empty()) { - errorDescription = "no fields"; + if (rows->empty()) { + *errorDescription = "no fields"; return RESULT_ERR_EOF; } size_t fieldIndex = -1; - for (auto& row : rows) { + for (auto& row : *rows) { if (result != RESULT_OK) { break; } fieldIndex++; - const string name = pluck(row, "name"); + const string name = pluck("name", &row); PartType partType; bool hasPart = false; - string part = pluck(row, "part"); + string part = pluck("part", &row); if (isTemplate) { partType = pt_any; } else { hasPart = !part.empty(); if (hasPart) { - FileReader::tolower(part); + FileReader::tolower(&part); } if (isBroadcastOrMasterDestination || (isWriteMessage && !hasPart) @@ -222,7 +218,7 @@ result_t DataField::create(vector< map >& rows, string& errorDes || part == "s") { // slave data partType = pt_slaveData; } else { - errorDescription = "part "+part+" in field "+formatInt(fieldIndex); + *errorDescription = "part "+part+" in field "+formatInt(fieldIndex); result = hasPart ? RESULT_ERR_INVALID_ARG : RESULT_ERR_MISSING_ARG; break; } @@ -231,17 +227,17 @@ result_t DataField::create(vector< map >& rows, string& errorDes firstName = name; } - const string typeStr = pluck(row, "type"); // basetype[:len]|template[:name] + const string typeStr = pluck("type", &row); // basetype[:len]|template[:name] if (typeStr.empty()) { - errorDescription = "field type in field "+formatInt(fieldIndex); + *errorDescription = "field type in field "+formatInt(fieldIndex); result = RESULT_ERR_MISSING_ARG; break; } - string divisorStr = pluck(row, "divisor"); - string valuesStr = pluck(row, "values"); + string divisorStr = pluck("divisor", &row); + string valuesStr = pluck("values", &row); if (divisorStr.empty() && valuesStr.empty()) { - divisorStr = pluck(row, "divisor/values"); // [divisor|values] + divisorStr = pluck("divisor/values", &row); // [divisor|values] if (divisorStr.find('=') != string::npos) { valuesStr = divisorStr; divisorStr = ""; @@ -249,9 +245,9 @@ result_t DataField::create(vector< map >& rows, string& errorDes } int divisor = 0; if (!divisorStr.empty()) { - divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result); + divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, &result); if (result != RESULT_OK) { - errorDescription = "divisor "+divisorStr+" in field "+formatInt(fieldIndex); + *errorDescription = "divisor "+divisorStr+" in field "+formatInt(fieldIndex); } } bool verifyValue = false; @@ -260,12 +256,12 @@ result_t DataField::create(vector< map >& rows, string& errorDes if (!valuesStr.empty()) { size_t equalPos = valuesStr.find('='); if (equalPos == string::npos) { - errorDescription = "values "+valuesStr+" in field "+formatInt(fieldIndex); + *errorDescription = "values "+valuesStr+" in field "+formatInt(fieldIndex); result = RESULT_ERR_INVALID_LIST; } else if (equalPos == 0 && valuesStr.length() > 1) { verifyValue = valuesStr[1] == '='; // == forced verification of constant value if (verifyValue && valuesStr.length() == 1) { - errorDescription = "values "+valuesStr+" in field "+formatInt(fieldIndex); + *errorDescription = "values "+valuesStr+" in field "+formatInt(fieldIndex); result = RESULT_ERR_INVALID_LIST; break; } @@ -274,7 +270,7 @@ result_t DataField::create(vector< map >& rows, string& errorDes string token; istringstream stream(valuesStr); while (getline(stream, token, VALUE_SEPARATOR)) { - FileReader::trim(token); + FileReader::trim(&token); const char* str = token.c_str(); char* strEnd = NULL; unsigned long id; @@ -285,19 +281,19 @@ result_t DataField::create(vector< map >& rows, string& errorDes id = strtoul(str, &strEnd, 10); // decimal } if (strEnd == NULL || strEnd == str || id > MAX_VALUE) { - errorDescription = "value "+token+" in field "+formatInt(fieldIndex); + *errorDescription = "value "+token+" in field "+formatInt(fieldIndex); result = RESULT_ERR_INVALID_LIST; break; } // remove blanks around '=' sign while (*strEnd == ' ') strEnd++; if (*strEnd != '=') { - errorDescription = "value "+token+" in field "+formatInt(fieldIndex); + *errorDescription = "value "+token+" in field "+formatInt(fieldIndex); result = RESULT_ERR_INVALID_LIST; break; } token = string(strEnd + 1); - FileReader::trim(token); + FileReader::trim(&token); values[(unsigned int)id] = token; } } @@ -311,7 +307,7 @@ result_t DataField::create(vector< map >& rows, string& errorDes istringstream stream(typeStr); while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR)) { bool lastType = stream.eof(); - FileReader::trim(token); + FileReader::trim(&token); const DataField* templ = templates->get(token); size_t pos = token.find(LENGTH_SEPARATOR); if (templ == NULL && pos != string::npos) { @@ -327,9 +323,9 @@ result_t DataField::create(vector< map >& rows, string& errorDes if (pos+2 == token.length() && token[pos+1] == '*') { length = REMAIN_LEN; } else { - length = (size_t)parseInt(token.substr(pos+1).c_str(), 10, 1, (unsigned int)maxFieldLength, result); + length = (size_t)parseInt(token.substr(pos+1).c_str(), 10, 1, (unsigned int)maxFieldLength, &result); if (result != RESULT_OK) { - errorDescription = "field type "+token+" in field "+formatInt(fieldIndex); + *errorDescription = "field type "+token+" in field "+formatInt(fieldIndex); break; } } @@ -339,24 +335,24 @@ result_t DataField::create(vector< map >& rows, string& errorDes const DataType* dataType = DataTypeList::getInstance()->get(typeName, length == REMAIN_LEN ? 0 : length); if (!dataType) { result = RESULT_ERR_NOTFOUND; - errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex); + *errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex); } else { SingleDataField* add = NULL; - result = SingleDataField::create(firstType ? name : "", row, dataType, partType, length, divisor, values, - constantValue, verifyValue, add); + result = SingleDataField::create(firstType ? name : "", row, dataType, partType, length, divisor, + constantValue, verifyValue, &values, &add); if (add != NULL) { fields.push_back(add); } else { if (result == RESULT_OK) { - errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex); + *errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex); result = RESULT_ERR_NOTFOUND; // type not found } else { - errorDescription = "create field in field "+formatInt(fieldIndex); + *errorDescription = "create field in field "+formatInt(fieldIndex); } } } } else if (!constantValue.empty()) { - errorDescription = "constant value "+constantValue+" in field "+formatInt(fieldIndex); + *errorDescription = "constant value "+constantValue+" in field "+formatInt(fieldIndex); result = RESULT_ERR_INVALID_ARG; // invalid value list } else { // template[:name] string fieldName; @@ -365,14 +361,19 @@ result_t DataField::create(vector< map >& rows, string& errorDes } else { fieldName = (firstType && lastType) ? name : ""; } - result = templ->derive(fieldName, row, partType, divisor, values, fields); + if (lastType) { + result = templ->derive(fieldName, partType, divisor, values, &row, &fields); + } else { + map attrs = row; // don't let DataField::derive() consume the row + result = templ->derive(fieldName, partType, divisor, values, &attrs, &fields); + } if (result != RESULT_OK) { - errorDescription = "derive field "+fieldName+" in field "+formatInt(fieldIndex); + *errorDescription = "derive field "+fieldName+" in field "+formatInt(fieldIndex); } } if (firstType && !lastType) { - pluck(row, "comment"); - pluck(row, "unit"); + row.erase("comment"); + row.erase("unit"); } firstType = false; } @@ -387,14 +388,14 @@ result_t DataField::create(vector< map >& rows, string& errorDes } if (fields.size() == 1) { - returnField = fields[0]; + *returnField = fields[0]; } else { - returnField = new DataFieldSet(firstName, fields); + *returnField = new DataFieldSet(firstName, fields); } return RESULT_OK; } -string DataField::getDayName(int day) { +const char* DataField::getDayName(int day) { if (day < 0 || day > 6) { return ""; } @@ -402,9 +403,9 @@ string DataField::getDayName(int day) { } -result_t SingleDataField::create(const string name, const map& attributes, const DataType* dataType, - const PartType partType, const size_t length, int divisor, map values, - const string constantValue, const bool verifyValue, SingleDataField* &returnField) { +result_t SingleDataField::create(const string& name, const map& attributes, const DataType* dataType, + PartType partType, size_t length, int divisor, const string& constantValue, + bool verifyValue, map* values, SingleDataField** returnField) { size_t bitCount = dataType->getBitCount(); size_t byteCount = (bitCount + 7) / 8; if (dataType->isAdjustableLength()) { @@ -427,55 +428,62 @@ result_t SingleDataField::create(const string name, const map& a } } if (!constantValue.empty()) { - returnField = new ConstantDataField(name, attributes, dataType, partType, byteCount, constantValue, verifyValue); + *returnField = new ConstantDataField(name, attributes, dataType, partType, byteCount, constantValue, verifyValue); return RESULT_OK; } if (dataType->isNumeric()) { const NumberDataType* numType = reinterpret_cast(dataType); - if (values.empty() && numType->hasFlag(DAY)) { + if (values->empty() && numType->hasFlag(DAY)) { for (unsigned int i = 0; i < sizeof(dayNames) / sizeof(dayNames[0]); i++) { - values[numType->getMinValue() + i] = dayNames[i]; + (*values)[numType->getMinValue() + i] = dayNames[i]; } } - result_t result = numType->derive(divisor, bitCount, numType); + result_t result = numType->derive(divisor, bitCount, &numType); if (result != RESULT_OK) { return result; } - if (values.empty()) { - returnField = new SingleDataField(name, attributes, numType, partType, byteCount); + if (values->empty()) { + *returnField = new SingleDataField(name, attributes, numType, partType, byteCount); return RESULT_OK; } - if (values.begin()->first < numType->getMinValue() || values.rbegin()->first > numType->getMaxValue()) { + if (values->begin()->first < numType->getMinValue() || values->rbegin()->first > numType->getMaxValue()) { return RESULT_ERR_OUT_OF_RANGE; } - returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, values); + *returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, *values); return RESULT_OK; } - if (divisor != 0 || !values.empty()) { + if (divisor != 0 || !values->empty()) { return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for string field } - returnField = new SingleDataField(name, attributes, dataType, partType, byteCount); + *returnField = new SingleDataField(name, attributes, dataType, partType, byteCount); return RESULT_OK; } -void SingleDataField::dump(ostream& output) const { - output << setw(0) << dec; // initialize formatting - dumpString(output, m_name, false); - output << FIELD_SEPARATOR; +void SingleDataField::dumpPrefix(ostream* output) const { + *output << setw(0) << dec; // initialize formatting + dumpString(false, m_name, output); + *output << FIELD_SEPARATOR; if (m_partType == pt_masterData) { - output << "m"; + *output << "m"; } else if (m_partType == pt_slaveData) { - output << "s"; + *output << "s"; } - output << FIELD_SEPARATOR; - m_dataType->dump(output, m_length); - dumpAttribute(output, "unit"); - dumpAttribute(output, "comment"); + *output << FIELD_SEPARATOR; } +void SingleDataField::dumpSuffix(ostream* output) const { + dumpAttribute(true, "unit", output); + dumpAttribute(true, "comment", output); +} + +void SingleDataField::dump(ostream* output) const { + dumpPrefix(output); + m_dataType->dump(m_length, true, output); + dumpSuffix(output); +} result_t SingleDataField::read(const SymbolString& data, size_t offset, - unsigned int& output, const char* fieldName, ssize_t fieldIndex) const { + const char* fieldName, ssize_t fieldIndex, unsigned int* output) const { if (m_partType == pt_any) { return RESULT_ERR_INVALID_PART; } @@ -489,13 +497,13 @@ result_t SingleDataField::read(const SymbolString& data, size_t offset, if (isIgnored() || (fieldName != NULL && (m_name != fieldName || fieldIndex > 0))) { return RESULT_EMPTY; } - result_t res = m_dataType->readRawValue(data, offset, m_length, output); + result_t res = m_dataType->readRawValue(offset, m_length, data, output); return res; } result_t SingleDataField::read(const SymbolString& data, size_t offset, - ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex, - bool leadingSeparator, const char* fieldName, ssize_t fieldIndex) const { + bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, + OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const { if (m_partType == pt_any) { return RESULT_ERR_INVALID_PART; } @@ -512,73 +520,72 @@ result_t SingleDataField::read(const SymbolString& data, size_t offset, bool shortFormat = outputFormat & OF_SHORT; if (outputFormat & OF_JSON) { if (leadingSeparator) { - output << ","; + *output << ","; } if (!shortFormat) { - output << "\n "; + *output << "\n "; } if (outputIndex >= 0 || m_name.empty() || !(outputFormat & OF_NAMES)) { - output << "\"" << static_cast(outputIndex < 0 ? 0 : outputIndex) << "\":"; + *output << "\"" << static_cast(outputIndex < 0 ? 0 : outputIndex) << "\":"; if (!shortFormat) { - output << " {\"name\": \"" << m_name << "\"" << ", \"value\": "; + *output << " {\"name\": \"" << m_name << "\"" << ", \"value\": "; } } else { - output << "\"" << m_name << "\":"; + *output << "\"" << m_name << "\":"; if (!shortFormat) { - output << " {\"value\": "; + *output << " {\"value\": "; } } } else { if (leadingSeparator) { - output << UI_FIELD_SEPARATOR; + *output << UI_FIELD_SEPARATOR; } if (outputFormat & OF_NAMES) { - output << m_name << "="; + *output << m_name << "="; } } - result_t result = readSymbols(data, offset, output, outputFormat); + result_t result = readSymbols(data, offset, outputFormat, output); if (result != RESULT_OK) { return result; } if (!shortFormat) { - appendAttributes(output, outputFormat); + appendAttributes(outputFormat, output); } if (!shortFormat && (outputFormat & OF_JSON)) { - output << "}"; + *output << "}"; } return RESULT_OK; } -result_t SingleDataField::write(istringstream& input, SymbolString& data, - size_t offset, char separator, size_t* length) const { +result_t SingleDataField::write(char separator, size_t offset, istringstream* input, + SymbolString* data, size_t* usedLength) const { if (m_partType == pt_any) { return RESULT_ERR_INVALID_PART; } - if ((data.isMaster() ? pt_masterData : pt_slaveData) != m_partType) { + if ((data->isMaster() ? pt_masterData : pt_slaveData) != m_partType) { return RESULT_OK; } - return writeSymbols(input, (const size_t)offset, data, length); + return writeSymbols(offset, input, data, usedLength); } -result_t SingleDataField::readSymbols(const SymbolString& input, - const size_t offset, - ostringstream& output, OutputFormat outputFormat) const { - return m_dataType->readSymbols(input, offset, m_length, output, outputFormat); +result_t SingleDataField::readSymbols(const SymbolString& input, size_t offset, + OutputFormat outputFormat, ostream* output) const { + return m_dataType->readSymbols(offset, m_length, input, outputFormat, output); } -result_t SingleDataField::writeSymbols(istringstream& input, - const size_t offset, - SymbolString& output, size_t* usedLength) const { - return m_dataType->writeSymbols(input, offset, m_length, output, usedLength); +result_t SingleDataField::writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const { + return m_dataType->writeSymbols(offset, m_length, input, output, usedLength); } const SingleDataField* SingleDataField::clone() const { return new SingleDataField(*this); } -result_t SingleDataField::derive(string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const { +result_t SingleDataField::derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const { if (m_partType != pt_any && partType == pt_any) { return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance } @@ -586,23 +593,21 @@ result_t SingleDataField::derive(string name, map attributes, co if (!numeric && (divisor != 0 || !values.empty())) { return RESULT_ERR_INVALID_ARG; // cannot set divisor or values for non-numeric field } - if (name.empty()) { - name = m_name; - } + string useName = name.empty() ? m_name : name; mergeAttributes(attributes); const DataType* dataType = m_dataType; if (numeric) { const NumberDataType* numType = reinterpret_cast(dataType); - result_t result = numType->derive(divisor, 0, numType); + result_t result = numType->derive(divisor, 0, &numType); if (result != RESULT_OK) { return result; } dataType = numType; } if (values.empty()) { - fields.push_back(new SingleDataField(name, attributes, dataType, partType, m_length)); + fields->push_back(new SingleDataField(useName, *attributes, dataType, partType, m_length)); } else if (numeric) { - fields.push_back(new ValueListDataField(name, attributes, reinterpret_cast(dataType), + fields->push_back(new ValueListDataField(useName, *attributes, reinterpret_cast(dataType), partType, m_length, values)); } else { return RESULT_ERR_INVALID_ARG; @@ -643,8 +648,9 @@ const ValueListDataField* ValueListDataField::clone() const { return new ValueListDataField(*this); } -result_t ValueListDataField::derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const { +result_t ValueListDataField::derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const { if (m_partType != pt_any && partType == pt_any) { return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance } @@ -661,97 +667,83 @@ result_t ValueListDataField::derive(const string name, map attri if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) { return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field } + fields->push_back(new ValueListDataField(useName, *attributes, + reinterpret_cast(m_dataType), partType, m_length, values)); } else { - values = m_values; + fields->push_back(new ValueListDataField(useName, *attributes, + reinterpret_cast(m_dataType), partType, m_length, m_values)); } - fields.push_back(new ValueListDataField(useName, attributes, reinterpret_cast(m_dataType), - partType, m_length, values)); return RESULT_OK; } -void ValueListDataField::dump(ostream& output) const { - output << setw(0) << dec; // initialize formatting - dumpString(output, m_name, false); - output << FIELD_SEPARATOR; - if (m_partType == pt_masterData) { - output << "m"; - } else if (m_partType == pt_slaveData) { - output << "s"; - } - output << FIELD_SEPARATOR; - if (!m_dataType->dump(output, m_length)) { // no divisor appended +void ValueListDataField::dump(ostream* output) const { + dumpPrefix(output); + if (!m_dataType->dump(m_length, true, output)) { // no divisor appended bool first = true; for (const auto it : m_values) { if (first) { first = false; } else { - output << VALUE_SEPARATOR; + *output << VALUE_SEPARATOR; } - output << static_cast(it.first) << "=" << it.second; + *output << static_cast(it.first) << "=" << it.second; } } // else: impossible since divisor is not allowed for ValueListDataField - dumpAttribute(output, "unit"); - dumpAttribute(output, "comment"); + dumpSuffix(output); } -result_t ValueListDataField::readSymbols(const SymbolString& input, - const size_t offset, - ostringstream& output, OutputFormat outputFormat) const { +result_t ValueListDataField::readSymbols(const SymbolString& input, size_t offset, + OutputFormat outputFormat, ostream* output) const { unsigned int value = 0; - result_t result = m_dataType->readRawValue(input, offset, m_length, value); + result_t result = m_dataType->readRawValue(offset, m_length, input, &value); if (result != RESULT_OK) { return result; } const auto it = m_values.find(value); if (it == m_values.end() && value != m_dataType->getReplacement()) { // fall back to raw value in input - output << setw(0) << dec << static_cast(value); + *output << setw(0) << dec << static_cast(value); return RESULT_OK; } if (it == m_values.end()) { if (outputFormat & OF_JSON) { - output << "null"; + *output << "null"; } else if (value == m_dataType->getReplacement()) { - output << NULL_VALUE; + *output << NULL_VALUE; } } else if (outputFormat & OF_NUMERIC) { - output << setw(0) << dec << static_cast(value); + *output << setw(0) << dec << static_cast(value); } else if (outputFormat & OF_JSON) { if (outputFormat & OF_VALUENAME) { - output << "{\"value\":" << setw(0) << dec << static_cast(value); - output << ",\"name\":\"" << it->second << "\"}"; + *output << "{\"value\":" << setw(0) << dec << static_cast(value); + *output << ",\"name\":\"" << it->second << "\"}"; } else { - output << '"' << it->second << '"'; + *output << '"' << it->second << '"'; } } else { if (outputFormat & OF_VALUENAME) { - output << setw(0) << dec << static_cast(value) << '='; + *output << setw(0) << dec << static_cast(value) << '='; } - output << it->second; + *output << it->second; } return RESULT_OK; } -result_t ValueListDataField::writeSymbols(istringstream& input, - const size_t offset, - SymbolString& output, size_t* usedLength) const { +result_t ValueListDataField::writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const { const NumberDataType* numType = reinterpret_cast(m_dataType); - if (isIgnored()) { + if (isIgnored() || input->str() == NULL_VALUE) { // replacement value return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); } - const char* str = input.str().c_str(); + const char* str = input->str().c_str(); for (const auto it : m_values) { if (it.second.compare(str) == 0) { return numType->writeRawValue(it.first, offset, m_length, output, usedLength); } } - if (strcasecmp(str, NULL_VALUE) == 0) { - // replacement value - return numType->writeRawValue(numType->getReplacement(), offset, m_length, output, usedLength); - } char* strEnd = NULL; // fall back to raw value in input unsigned int value; value = (unsigned int)strtoul(str, &strEnd, 10); @@ -769,15 +761,16 @@ const ConstantDataField* ConstantDataField::clone() const { return new ConstantDataField(*this); } -result_t ConstantDataField::derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const { +result_t ConstantDataField::derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const { if (m_partType != pt_any && partType == pt_any) { return RESULT_ERR_INVALID_PART; // cannot create a template from a concrete instance } string useName = name.empty() ? m_name : name; for (const auto entry : m_attributes) { // merge with this attributes - if (attributes[entry.first].empty()) { - attributes[entry.first] = entry.second; + if ((*attributes)[entry.first].empty()) { + (*attributes)[entry.first] = entry.second; } } if (divisor != 0) { @@ -786,38 +779,28 @@ result_t ConstantDataField::derive(const string name, map attrib if (!values.empty()) { return RESULT_ERR_INVALID_ARG; // cannot use value list for constant value field } - fields.push_back(new ConstantDataField(useName, attributes, m_dataType, partType, m_length, m_value, m_verify)); + fields->push_back(new ConstantDataField(useName, *attributes, m_dataType, partType, m_length, m_value, m_verify)); return RESULT_OK; } -void ConstantDataField::dump(ostream& output) const { - output << setw(0) << dec; // initialize formatting - dumpString(output, m_name, false); - output << FIELD_SEPARATOR; - if (m_partType == pt_masterData) { - output << "m"; - } else if (m_partType == pt_slaveData) { - output << "s"; - } - output << FIELD_SEPARATOR; - if (!m_dataType->dump(output, m_length)) { // no divisor appended - output << (m_verify?"==":"=") << m_value; +void ConstantDataField::dump(ostream* output) const { + dumpPrefix(output); + if (!m_dataType->dump(m_length, true, output)) { // no divisor appended + *output << (m_verify?"==":"=") << m_value; } // else: impossible since divisor is not allowed for ConstantDataField - dumpAttribute(output, "unit"); - dumpAttribute(output, "comment"); + dumpSuffix(output); } -result_t ConstantDataField::readSymbols(const SymbolString& input, - const size_t offset, - ostringstream& output, OutputFormat outputFormat) const { +result_t ConstantDataField::readSymbols(const SymbolString& input, size_t offset, + OutputFormat outputFormat, ostream* output) const { ostringstream coutput; - result_t result = SingleDataField::readSymbols(input, offset, coutput, 0); + result_t result = SingleDataField::readSymbols(input, offset, 0, &coutput); if (result != RESULT_OK) { return result; } if (m_verify) { string value = coutput.str(); - FileReader::trim(value); + FileReader::trim(&value); if (value != m_value) { return RESULT_ERR_OUT_OF_RANGE; } @@ -825,11 +808,10 @@ result_t ConstantDataField::readSymbols(const SymbolString& input, return RESULT_OK; } -result_t ConstantDataField::writeSymbols(istringstream& input, - const size_t offset, - SymbolString& output, size_t* usedLength) const { +result_t ConstantDataField::writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const { istringstream cinput(m_value); - return SingleDataField::writeSymbols(cinput, offset, output, usedLength); + return SingleDataField::writeSymbols(offset, &cinput, output, usedLength); } @@ -897,7 +879,6 @@ const DataFieldSet* DataFieldSet::clone() const { size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const { size_t length = 0; bool previousFullByteOffset[] = { true, true, true, true }; - for (const auto field : m_fields) { if (field->getPartType() == partType) { if (!previousFullByteOffset[partType] && !field->hasFullByteOffset(false)) { @@ -918,7 +899,7 @@ size_t DataFieldSet::getLength(PartType partType, size_t maxLength) const { return length; } -string DataFieldSet::getName(const ssize_t fieldIndex) const { +string DataFieldSet::getName(ssize_t fieldIndex) const { if (fieldIndex < 0) { return m_name; } @@ -926,25 +907,26 @@ string DataFieldSet::getName(const ssize_t fieldIndex) const { return ""; } if (m_uniqueNames) { - return m_fields[fieldIndex]->getName(); + return m_fields[fieldIndex]->getName(-1); } ostringstream ostream; ostream << static_cast(fieldIndex); return ostream.str(); } -result_t DataFieldSet::derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const { +result_t DataFieldSet::derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const { if (!values.empty()) { return RESULT_ERR_INVALID_ARG; // value list not allowed in set derive } for (const auto field : m_fields) { - result_t result = field->derive("", attributes, partType, divisor, values, fields); + result_t result = field->derive("", partType, divisor, values, attributes, fields); if (result != RESULT_OK) { return result; } - pluck(attributes, "comment"); - pluck(attributes, "unit"); + attributes->erase("comment"); + attributes->erase("unit"); } return RESULT_OK; @@ -959,20 +941,20 @@ bool DataFieldSet::hasField(const char* fieldName, bool numeric) const { return false; } -void DataFieldSet::dump(ostream& output) const { +void DataFieldSet::dump(ostream* output) const { bool first = true; for (const auto field : m_fields) { if (first) { first = false; } else { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } field->dump(output); } } result_t DataFieldSet::read(const SymbolString& data, size_t offset, - unsigned int& output, const char* fieldName, ssize_t fieldIndex) const { + const char* fieldName, ssize_t fieldIndex, unsigned int* output) const { bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0; PartType partType = data.isMaster() ? pt_masterData : pt_slaveData; for (const auto field : m_fields) { @@ -982,7 +964,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, if (!previousFullByteOffset && !field->hasFullByteOffset(false)) { offset--; } - result_t result = field->read(data, offset, output, fieldName, fieldIndex); + result_t result = field->read(data, offset, fieldName, fieldIndex, output); if (result < RESULT_OK) { return result; } @@ -991,7 +973,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, if (result != RESULT_EMPTY) { found = true; } - if (findFieldIndex && fieldName == field->getName()) { + if (findFieldIndex && fieldName == field->getName(-1)) { if (fieldIndex == 0) { if (!found) { return RESULT_ERR_NOTFOUND; @@ -1010,8 +992,8 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, } result_t DataFieldSet::read(const SymbolString& data, size_t offset, - ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex, - bool leadingSeparator, const char* fieldName, ssize_t fieldIndex) const { + bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, + OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const { bool previousFullByteOffset = true, found = false, findFieldIndex = fieldName != NULL && fieldIndex >= 0; if (outputIndex < 0 && (!m_uniqueNames || ((outputFormat & OF_JSON) && !(outputFormat & OF_NAMES)))) { outputIndex = 0; @@ -1027,8 +1009,8 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, if (!previousFullByteOffset && !field->hasFullByteOffset(false)) { offset--; } - result_t result = field->read(data, offset, output, outputFormat, outputIndex, leadingSeparator, - fieldName, fieldIndex); + result_t result = field->read(data, offset, leadingSeparator, fieldName, fieldIndex, + outputFormat, outputIndex, output); if (result < RESULT_OK) { return result; } @@ -1038,7 +1020,7 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, found = true; leadingSeparator = true; } - if (findFieldIndex && fieldName == field->getName()) { + if (findFieldIndex && fieldName == field->getName(-1)) { if (fieldIndex == 0) { if (!found) { return RESULT_ERR_NOTFOUND; @@ -1058,10 +1040,10 @@ result_t DataFieldSet::read(const SymbolString& data, size_t offset, return RESULT_OK; } -result_t DataFieldSet::write(istringstream& input, SymbolString& data, - size_t offset, char separator, size_t* length) const { +result_t DataFieldSet::write(char separator, size_t offset, istringstream* input, + SymbolString* data, size_t* usedLength) const { string token; - PartType partType = data.isMaster() ? pt_masterData : pt_slaveData; + PartType partType = data->isMaster() ? pt_masterData : pt_slaveData; bool previousFullByteOffset = true; size_t baseOffset = offset; for (const auto field : m_fields) { @@ -1076,13 +1058,13 @@ result_t DataFieldSet::write(istringstream& input, SymbolString& data, if (m_fields.size() > 1) { if (field->isIgnored()) { token.clear(); - } else if (!getline(input, token, separator)) { + } else if (!getline(*input, token, separator)) { token.clear(); } istringstream single(token); - result = field->write(single, data, offset, separator, &fieldLength); + result = field->write(separator, offset, &single, data, &fieldLength); } else { - result = field->write(input, data, offset, separator, &fieldLength); + result = field->write(separator, offset, input, data, &fieldLength); } if (result != RESULT_OK) { return result; @@ -1091,14 +1073,14 @@ result_t DataFieldSet::write(istringstream& input, SymbolString& data, previousFullByteOffset = field->hasFullByteOffset(true); } - if (length != NULL) { - *length = offset-baseOffset; + if (usedLength != NULL) { + *usedLength = offset-baseOffset; } return RESULT_OK; } -DataFieldTemplates::DataFieldTemplates(DataFieldTemplates& other) +DataFieldTemplates::DataFieldTemplates(const DataFieldTemplates& other) : MappedFileReader::MappedFileReader(false) { for (const auto it : other.m_fieldsByName) { m_fieldsByName[it.first] = it.second->clone(); @@ -1115,7 +1097,7 @@ void DataFieldTemplates::clear() { result_t DataFieldTemplates::add(const DataField* field, string name, bool replace) { if (name.length() == 0) { - name = field->getName(); + name = field->getName(-1); } const auto it = m_fieldsByName.find(name); if (it != m_fieldsByName.end()) { @@ -1131,29 +1113,29 @@ result_t DataFieldTemplates::add(const DataField* field, string name, bool repla return RESULT_OK; } -result_t DataFieldTemplates::getFieldMap(vector& row, string& errorDescription, const string preferLanguage) +result_t DataFieldTemplates::getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const { // name[:usename],basetype[:len]|template[:usename][,[divisor|values][,[unit][,[comment]]]] - if (row.empty()) { + if (row->empty()) { // default map does not include separate field name for (const auto& col : defaultTemplateFieldMap) { - row.push_back(col); + row->push_back(col); } return RESULT_OK; } bool inDataFields = false; map seen; - for (size_t col = 0; col < row.size(); col++) { - string &name = row[col]; + for (size_t col = 0; col < row->size(); col++) { + string &name = (*row)[col]; string lowerName = name; - tolower(lowerName); - trim(lowerName); + tolower(&lowerName); + trim(&lowerName); if (lowerName.empty()) { - errorDescription = "missing name in column " + AttributedItem::formatInt(col); + *errorDescription = "missing name in column " + AttributedItem::formatInt(col); return RESULT_ERR_INVALID_ARG; } bool supportsLang = false; - string useName = getDataFieldName(lowerName, supportsLang); + string useName = getDataFieldName(lowerName, &supportsLang); bool unknown = useName.empty(); size_t langPos = supportsLang ? lowerName.find_last_of('.') : string::npos; map::iterator previous; @@ -1170,7 +1152,7 @@ result_t DataFieldTemplates::getFieldMap(vector& row, string& errorDescr continue; } // replace previous - row[previous->second] = SKIP_COLUMN; + (*row)[previous->second] = SKIP_COLUMN; seen.erase(useName); previous = seen.end(); } @@ -1183,7 +1165,7 @@ result_t DataFieldTemplates::getFieldMap(vector& row, string& errorDescr if (inDataFields) { if (!unknown && previous != seen.end()) { if (seen.find("type") == seen.end()) { - errorDescription = "missing field type"; + *errorDescription = "missing field type"; return RESULT_ERR_EOF; // require at least type } seen.clear(); @@ -1193,14 +1175,14 @@ result_t DataFieldTemplates::getFieldMap(vector& row, string& errorDescr // keep first name for template } else if (!unknown) { if (seen.find("name") == seen.end()) { - errorDescription = "missing template name"; + *errorDescription = "missing template name"; return RESULT_ERR_EOF; // require at least name } inDataFields = true; seen.clear(); } if (!inDataFields && seen.find(useName) != seen.end()) { - errorDescription = "duplicate template " + useName; + *errorDescription = "duplicate template " + useName; return RESULT_ERR_INVALID_ARG; } } @@ -1212,19 +1194,19 @@ result_t DataFieldTemplates::getFieldMap(vector& row, string& errorDescr seen[useName] = col; } if (!inDataFields) { - errorDescription = "missing template fields"; + *errorDescription = "missing template fields"; return RESULT_ERR_EOF; // require at least one field } if (seen.find("type") == seen.end()) { - errorDescription = "missing field type"; + *errorDescription = "missing field type"; return RESULT_ERR_EOF; // require at least type } return RESULT_OK; } -result_t DataFieldTemplates::addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) { - string name = row["name"]; // required +result_t DataFieldTemplates::addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) { + string name = (*row)["name"]; // required string firstFieldName; size_t colon = name.find(':'); if (colon == string::npos) { @@ -1234,16 +1216,16 @@ result_t DataFieldTemplates::addFromFile(map& row, vector< mapempty() && (*subRows)[0].find("name") == (*subRows)[0].end()) { + (*subRows)[0]["name"] = firstFieldName; } - result_t result = DataField::create(subRows, errorDescription, this, field, false, true, false); + result_t result = DataField::create(false, true, false, MAX_POS, this, subRows, errorDescription, &field); if (result != RESULT_OK) { return result; } result = add(field, name, true); if (result == RESULT_ERR_DUPLICATE_NAME) { - errorDescription = name; + *errorDescription = name; } if (result != RESULT_OK) { delete field; @@ -1251,7 +1233,7 @@ result_t DataFieldTemplates::addFromFile(map& row, vector< map& attributes) + AttributedItem(const string& name, const map& attributes) : m_name(name), m_attributes(attributes) {} /** * Constructs a new instance (without additional attributes). * @param name the field name. */ - explicit AttributedItem(const string name) + explicit AttributedItem(const string& name) : m_name(name) {} /** @@ -92,69 +92,69 @@ class AttributedItem { * @param value the int value. * @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. - * @param row the map to remove the value from. * @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. */ - static const string pluck(map& row, const string key); + static string pluck(const string& key, map* row); /** * 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 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. - * @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 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 output the @a ostream to append to. */ - static void appendJson(ostream& output, const string name, const string value, - const bool prependFieldSeparator = true, bool asString = false); + static void appendJson(bool prependFieldSeparator, const string& name, const string& value, + bool asString, ostream* output); /** * 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. */ - void mergeAttributes(map& attributes) const; + void mergeAttributes(map* attributes) const; /** * 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 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. - * @param output the @a ostringstream to append the formatted value to. * @param outputFormat the @a OutputFormat options to use. * @param name the name of the attribute to append. * @param onlyIfNonEmpty true to append only if the value is not empty. * @param prefix optional prefix 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. */ - bool appendAttribute(ostringstream& output, OutputFormat outputFormat, const string name, - const bool onlyIfNonEmpty = true, const string prefix = "", const string suffix = "") const; + bool appendAttribute(OutputFormat outputFormat, const string& name, bool onlyIfNonEmpty, + const string& prefix, const string& suffix, ostream* output) const; /** * 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 output the @a ostream to append the formatted values to. * @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. @@ -167,7 +167,7 @@ class AttributedItem { * @param name the name of the attribute. * @return the named attribute value, or empty. */ - string getAttribute(const string name) const; + string getAttribute(const string& name) const; protected: @@ -178,6 +178,7 @@ class AttributedItem { const map m_attributes; }; + /** * Base class for all kinds of data fields. */ @@ -188,14 +189,14 @@ class DataField : public AttributedItem { * @param name the field name. * @param attributes the additional named attributes. */ - DataField(const string name, const map& attributes) + DataField(const string& name, const map& attributes) : AttributedItem(name, attributes) {} /** * Constructs a new instance (without additional attributes). * @param name the field name. */ - explicit DataField(const string name) + explicit DataField(const string& name) : AttributedItem(name) {} /** @@ -211,63 +212,62 @@ class DataField : public AttributedItem { /** * 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 isTemplate true for creating a template @a DataField. * @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. * Note: the caller needs to free the created instance. */ - static result_t create(vector< map >& rows, string& errorDescription, - DataFieldTemplates* templates, const DataField*& returnField, - const bool isWriteMessage, - const bool isTemplate, const bool isBroadcastOrMasterDestination, - const size_t maxFieldLength = MAX_POS); + static result_t create(bool isWriteMessage, bool isTemplate, bool isBroadcastOrMasterDestination, + size_t maxFieldLength, const DataFieldTemplates* templates, vector< map >* rows, + string* errorDescription, const DataField** returnField); /** * Return the name of the specified day. * @param day the day (between 0 and 6). * @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. * @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. */ - 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. * @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 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 fields the @a vector to which created @a SingleDataField instances shall be added. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const = 0; + virtual result_t derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const = 0; /** * Get the specified field name. * @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. */ - 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. * @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. @@ -281,46 +281,46 @@ class DataField : public AttributedItem { * Reads the numeric value from the @a SymbolString. * @param data the data @a SymbolString 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 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, * 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), * or an error code. */ 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. * @param data the data @a SymbolString 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 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 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), * or @a RESULT_EMPTY if the field was skipped (either ignored or due to @a fieldName or @a fieldIndex), * or an error code. */ virtual result_t read(const SymbolString& data, size_t offset, - ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, - bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const = 0; + bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, + OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const = 0; /** * Writes the value to the master or slave @a SymbolString. * @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 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. */ - virtual result_t write(istringstream& input, SymbolString& data, - size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const = 0; + virtual result_t write(char separator, size_t offset, istringstream* input, + 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 length the number of symbols in the message part in which the field is stored. */ - SingleDataField(const string name, const map& attributes, const DataType* dataType, - const PartType partType, const size_t length) + SingleDataField(const string& name, const map& attributes, const DataType* dataType, + PartType partType, size_t length) : DataField(name, attributes), 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. * Note: the caller needs to free the created instance. */ - static result_t create(const string name, const map& attributes, const DataType* dataType, - const PartType partType, const size_t length, int divisor, map values, - const string constantValue, const bool verifyValue, SingleDataField* &returnField); + static result_t create(const string& name, const map& attributes, const DataType* dataType, + PartType partType, size_t length, int divisor, const string& constantValue, + bool verifyValue, map* values, SingleDataField** returnField); /** * Get whether this field is ignored. @@ -382,11 +382,12 @@ class SingleDataField : public DataField { PartType getPartType() const { return m_partType; } // @copydoc - size_t getLength(PartType partType, size_t maxLength = MAX_LEN) const override; + size_t getLength(PartType partType, size_t maxLength) const override; // @copydoc - result_t derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const override; + result_t derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const override; /** * Get whether this field uses a full byte offset. @@ -396,24 +397,36 @@ class SingleDataField : public DataField { */ 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 - void dump(ostream& output) const override; + void dump(ostream* output) const override; // @copydoc bool hasField(const char* fieldName, bool numeric) const override; // @copydoc 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 result_t read(const SymbolString& data, size_t offset, - ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, - bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; + bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, + OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const override; // @copydoc - result_t write(istringstream& input, SymbolString& data, - size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const override; + result_t write(char separator, size_t offset, istringstream* input, + SymbolString* data, size_t* usedLength) const override; protected: @@ -421,13 +434,12 @@ class SingleDataField : public DataField { * 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 @a SymbolString. - * @param output the ostringstream to append the formatted value to. * @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. */ - virtual result_t readSymbols(const SymbolString& input, - const size_t offset, - ostringstream& output, OutputFormat outputFormat) const; + virtual result_t readSymbols(const SymbolString& input, size_t offset, + OutputFormat outputFormat, ostream* output) const; /** * 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. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t writeSymbols(istringstream& input, - const size_t offset, - SymbolString& output, size_t* usedLength) const; + virtual result_t writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const; /** the message part in which the field is stored. */ 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 values the value=text assignments. */ - ValueListDataField(const string name, const map& attributes, const DataType* dataType, - const PartType partType, const size_t length, const map values) + ValueListDataField(const string& name, const map& attributes, const DataType* dataType, + PartType partType, size_t length, const map& values) : SingleDataField(name, attributes, dataType, partType, length), m_values(values) {} @@ -480,21 +491,22 @@ class ValueListDataField : public SingleDataField { const ValueListDataField* clone() const override; // @copydoc - result_t derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const override; + result_t derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const override; // @copydoc - void dump(ostream& output) const override; + void dump(ostream* output) const override; protected: // @copydoc - result_t readSymbols(const SymbolString& input, const size_t offset, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(const SymbolString& input, size_t offset, + const OutputFormat outputFormat, ostream* output) const override; // @copydoc - result_t writeSymbols(istringstream& input, const size_t offset, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const override; private: @@ -518,8 +530,8 @@ class ConstantDataField : public SingleDataField { * @param value the constant value. * @param verify whether to verify the read value against the constant value. */ - ConstantDataField(const string name, const map& attributes, const DataType* dataType, - const PartType partType, const size_t length, const string value, const bool verify) + ConstantDataField(const string& name, const map& attributes, const DataType* dataType, + PartType partType, size_t length, const string& value, bool verify) : SingleDataField(name, attributes, dataType, partType, length), m_value(value), m_verify(verify) {} @@ -532,21 +544,22 @@ class ConstantDataField : public SingleDataField { const ConstantDataField* clone() const override; // @copydoc - result_t derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const override; + result_t derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const override; // @copydoc - void dump(ostream& output) const override; + void dump(ostream* output) const override; protected: // @copydoc - result_t readSymbols(const SymbolString& input, const size_t offset, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(const SymbolString& input, size_t offset, + const OutputFormat outputFormat, ostream* output) const override; // @copydoc - result_t writeSymbols(istringstream& input, const size_t offset, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(size_t offset, istringstream* input, + SymbolString* output, size_t* usedLength) const override; private: @@ -580,7 +593,7 @@ class DataFieldSet : public DataField { * @param name the field name. * @param fields the @a vector of @a SingleDataField instances part of this set. */ - DataFieldSet(const string name, const vector fields) + DataFieldSet(const string& name, const vector fields) : DataField(name), m_fields(fields) { bool uniqueNames = true; map names; @@ -588,7 +601,7 @@ class DataFieldSet : public DataField { if (field->isIgnored()) { continue; } - string name = field->getName(); + string name = field->getName(-1); if (name.empty() || names.find(name) != names.end()) { uniqueNames = false; break; @@ -607,33 +620,22 @@ class DataFieldSet : public DataField { const DataFieldSet* clone() const override; // @copydoc - size_t getLength(PartType partType, size_t maxLength = MAX_LEN) const override; + size_t getLength(PartType partType, size_t maxLength) const override; // @copydoc - string getName(const ssize_t fieldIndex = -1) const override; + string getName(ssize_t fieldIndex) const override; // @copydoc - result_t derive(const string name, map attributes, const PartType partType, - int divisor, map values, vector& fields) const override; + result_t derive(const string& name, PartType partType, int divisor, + const map& values, map* attributes, + vector* fields) const override; /** * 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. */ - /*SingleDataField* operator[](const size_t index) { - 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 { + const SingleDataField* operator[](size_t index) const { if (index >= m_fields.size()) { return NULL; } @@ -650,20 +652,20 @@ class DataFieldSet : public DataField { bool hasField(const char* fieldName, bool numeric) const override; // @copydoc - void dump(ostream& output) const override; + void dump(ostream* output) const override; // @copydoc 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 result_t read(const SymbolString& data, size_t offset, - ostringstream& output, OutputFormat outputFormat, ssize_t outputIndex = -1, - bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const override; + bool leadingSeparator, const char* fieldName, ssize_t fieldIndex, + OutputFormat outputFormat, ssize_t outputIndex, ostream* output) const override; // @copydoc - result_t write(istringstream& input, SymbolString& data, - size_t offset, char separator = UI_FIELD_SEPARATOR, size_t* length = NULL) const override; + result_t write(char separator, size_t offset, istringstream* input, + SymbolString* data, size_t* usedLength) const override; private: @@ -692,7 +694,7 @@ class DataFieldTemplates : public MappedFileReader { * Constructs a new copied instance. * @param other the @a DataFieldTemplates to copy from. */ - DataFieldTemplates(DataFieldTemplates& other); + DataFieldTemplates(const DataFieldTemplates& other); /** * Destructor. @@ -717,11 +719,11 @@ class DataFieldTemplates : public MappedFileReader { result_t add(const DataField* field, string name = "", bool replace = false); // @copydoc - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override; + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override; // @copydoc - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override; + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override; /** * 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. * Note: the caller may not free the returned instance. */ - const DataField* get(string name) const; + const DataField* get(const string& name) const; private: diff --git a/src/lib/ebus/datatype.cpp b/src/lib/ebus/datatype.cpp index 0902b30b..7760a143 100644 --- a/src/lib/ebus/datatype.cpp +++ b/src/lib/ebus/datatype.cpp @@ -42,30 +42,29 @@ using std::setw; using std::endl; -bool DataType::dump(ostream& output, const size_t length, const bool appendSeparatorDivisor) const { - output << m_id; +bool DataType::dump(size_t length, bool appendSeparatorDivisor, ostream* output) const { + *output << m_id; if (isAdjustableLength()) { if (length == REMAIN_LEN) { - output << ":*"; + *output << ":*"; } else { - output << ":" << static_cast(length); + *output << ":" << static_cast(length); } } if (appendSeparatorDivisor) { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } return false; } -result_t StringDataType::readRawValue(const SymbolString& input, const size_t offset, - const size_t length, unsigned int& value) const { +result_t StringDataType::readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const { return RESULT_EMPTY; } -result_t StringDataType::readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const { +result_t StringDataType::readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const { size_t start = 0, count = length; int incr = 1; symbol_t symbol; @@ -81,16 +80,16 @@ result_t StringDataType::readSymbols(const SymbolString& input, } 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++) { symbol = input.dataAt(offset + index); if (m_isHex) { if (i > 0) { - output << ' '; + *output << ' '; } - output << setw(2) << static_cast(symbol); + *output << setw(2) << static_cast(symbol); } else { if (symbol == 0x00) { terminated = true; @@ -101,22 +100,21 @@ result_t StringDataType::readSymbols(const SymbolString& input, symbol = '?'; } else if (outputFormat & OF_JSON) { if (symbol == '"' || symbol == '\\') { - output << '\\'; // escape + *output << '\\'; // escape } } - output << static_cast(symbol); + *output << static_cast(symbol); } } } if (outputFormat & OF_JSON) { - output << '"'; + *output << '"'; } return RESULT_OK; } -result_t StringDataType::writeSymbols(istringstream& input, - size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const { +result_t StringDataType::writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const { size_t start = 0, count = length; bool remainder = count == REMAIN_LEN && hasFlag(ADJ); int incr = 1; @@ -132,7 +130,7 @@ result_t StringDataType::writeSymbols(istringstream& input, count = 1; } 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) { *usedLength = count; @@ -143,39 +141,39 @@ result_t StringDataType::writeSymbols(istringstream& input, size_t i = 0, index; for (index = start; i < count; index += incr, i++) { if (m_isHex) { - while (!input.eof() && input.peek() == ' ') { - input.get(); + while (!input->eof() && input->peek() == ' ') { + input->get(); } - if (input.eof()) { // no more digits + if (input->eof()) { // no more digits value = m_replacement; // fill up with replacement } else { token.clear(); - token.push_back((symbol_t)input.get()); - if (input.eof()) { + token.push_back((symbol_t)input->get()); + if (input->eof()) { return RESULT_ERR_INVALID_NUM; // too short hex value } - token.push_back((symbol_t)input.get()); - if (input.eof()) { + token.push_back((symbol_t)input->get()); + if (input->eof()) { 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) { return result; // invalid hex value } } } else { - if (input.eof()) { + if (input->eof()) { value = m_replacement; } else { - value = input.get(); - if (input.eof() || value < 0x20) { + value = input->get(); + if (input->eof() || value < 0x20) { value = m_replacement; } } } - if (remainder && input.eof() && i > 0) { + if (remainder && input->eof() && i > 0) { if (value == 0x00 && !m_isHex) { - output.dataAt(offset + index) = 0; + output->dataAt(offset + index) = 0; index += incr; } break; @@ -183,7 +181,7 @@ result_t StringDataType::writeSymbols(istringstream& input, if (value > 0xff) { 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) { @@ -196,14 +194,13 @@ result_t StringDataType::writeSymbols(istringstream& input, } -result_t DateTimeDataType::readRawValue(const SymbolString& input, const size_t offset, - const size_t length, unsigned int& value) const { +result_t DateTimeDataType::readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const { return RESULT_EMPTY; } -result_t DateTimeDataType::readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const { +result_t DateTimeDataType::readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const { size_t start = 0, count = length; int incr = 1; symbol_t symbol, last = 0, hour = 0; @@ -218,7 +215,7 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input, } if (outputFormat & OF_JSON) { - output << '"'; + *output << '"'; } int type = (m_hasDate?2:0) | (m_hasTime?1:0); 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 if (!hasFlag(REQ) && symbol == m_replacement) { if (i + 1 != length) { - output << NULL_VALUE << "."; + *output << NULL_VALUE << "."; break; } else if (last == m_replacement) { if (length == 2) { // number of days since 01.01.1900 - output << NULL_VALUE << "."; + *output << NULL_VALUE << "."; } - output << NULL_VALUE; + *output << NULL_VALUE; break; } } @@ -259,29 +256,29 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input, y++; m -= 12; } - output << dec << setfill('0') << setw(2) << static_cast(d) << "." - << setw(2) << static_cast(m) << "." << static_cast(y + 1900); + *output << dec << setfill('0') << setw(2) << static_cast(d) << "." + << setw(2) << static_cast(m) << "." << static_cast(y + 1900); break; } if (i + 1 == length) { - output << (2000 + symbol); + *output << (2000 + symbol); } else if (symbol < 1 || (i == 0 && symbol > 31) || (i == 1 && symbol > 12)) { return RESULT_ERR_OUT_OF_RANGE; // invalid date } else { - output << setw(2) << dec << setfill('0') << static_cast(symbol) << "."; + *output << setw(2) << dec << setfill('0') << static_cast(symbol) << "."; } break; case 1: // time only if (!hasFlag(REQ) && symbol == m_replacement) { if (length == 1) { // truncated time - output << NULL_VALUE << ":" << NULL_VALUE; + *output << NULL_VALUE << ":" << NULL_VALUE; break; } if (i > 0) { - output << ":"; + *output << ":"; } - output << NULL_VALUE; + *output << NULL_VALUE; break; } if (hasFlag(SPE)) { // minutes since midnight @@ -297,7 +294,7 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input, if (hour > 24) { return RESULT_ERR_OUT_OF_RANGE; // invalid hour } - output << setw(2) << dec << setfill('0') << static_cast(hour); + *output << setw(2) << dec << setfill('0') << static_cast(hour); symbol = (symbol_t)(minutes % 60); } else if (length == 1) { // truncated time if (m_bitCount < 8) { @@ -320,22 +317,21 @@ result_t DateTimeDataType::readSymbols(const SymbolString& input, return RESULT_ERR_OUT_OF_RANGE; // invalid time } if (i > 0) { - output << ":"; + *output << ":"; } - output << setw(2) << dec << setfill('0') << static_cast(symbol); + *output << setw(2) << dec << setfill('0') << static_cast(symbol); break; } last = symbol; } if (outputFormat & OF_JSON) { - output << '"'; + *output << '"'; } return RESULT_OK; } -result_t DateTimeDataType::writeSymbols(istringstream& input, - size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const { +result_t DateTimeDataType::writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const { size_t start = 0, count = length; bool remainder = count == REMAIN_LEN && hasFlag(ADJ); int incr = 1; @@ -351,7 +347,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, count = 1; } 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) { *usedLength = count; @@ -369,14 +365,14 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, if (length == 4 && i == 2) { continue; // skip weekday in between } - if (input.eof() || !getline(input, token, '.')) { + if (input->eof() || !getline(*input, token, '.')) { return RESULT_ERR_EOF; // incomplete } - if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) { + if (!hasFlag(REQ) && token == NULL_VALUE) { value = m_replacement; break; } - value = parseInt(token.c_str(), 10, 0, 2099, result); + value = parseInt(token.c_str(), 10, 0, 2099, &result); if (result != RESULT_OK) { return result; // invalid date part } @@ -389,7 +385,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, int l = last <= 2 ? 1 : 0; int mjd = 14956 + lastLast + static_cast((y-l)*365.25) + static_cast((last+1+l*12)*30.6001); value = mjd - 15020; // 01.01.1900 - output.dataAt(offset + index) = (symbol_t)(value&0xff); + output->dataAt(offset + index) = (symbol_t)(value&0xff); value >>= 8; index += incr; skip = false; @@ -404,10 +400,10 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, int mjd = 14956 + lastLast + static_cast((y-l)*365.25) + static_cast((last+1+l*12)*30.6001); int daysSinceSunday = (mjd+3) % 7; // Sun=0 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 { // 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) { @@ -422,10 +418,10 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, break; 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 } - if (!hasFlag(REQ) && strcmp(token.c_str(), NULL_VALUE) == 0) { + if (!hasFlag(REQ) && token == NULL_VALUE) { value = m_replacement; if (length == 1) { // truncated time if (i == 0) { @@ -439,7 +435,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, } break; } - value = parseInt(token.c_str(), 10, 0, 59, result); + value = parseInt(token.c_str(), 10, 0, 59, &result); if (result != RESULT_OK) { return result; // invalid time part } @@ -452,7 +448,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, break; } value += last*60; - output.dataAt(offset + index) = (symbol_t)(value&0xff); + output->dataAt(offset + index) = (symbol_t)(value&0xff); value >>= 8; index += incr; } else if (length == 1) { // truncated time @@ -480,7 +476,7 @@ result_t DateTimeDataType::writeSymbols(istringstream& input, if (value > 0xff) { 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; if (divisor > 1) { for (unsigned int exp = 1; exp < MAX_DIVISOR; exp *= 10, precision++) { @@ -506,28 +502,28 @@ size_t NumberDataType::calcPrecision(const int divisor) { 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) { - DataType::dump(output, m_bitCount, appendSeparatorDivisor); + DataType::dump(m_bitCount, appendSeparatorDivisor, output); } else { - DataType::dump(output, length, appendSeparatorDivisor); + DataType::dump(length, appendSeparatorDivisor, output); } if (!appendSeparatorDivisor) { return false; } if (m_baseType) { if (m_baseType->m_divisor != m_divisor) { - output << static_cast(m_divisor / m_baseType->m_divisor); + *output << static_cast(m_divisor / m_baseType->m_divisor); return true; } } else if (m_divisor != 1) { - output << static_cast(m_divisor); + *output << static_cast(m_divisor); return true; } 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) { divisor = 1; } @@ -549,7 +545,7 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy } } if (divisor == m_divisor && bitCount == m_bitCount) { - derived = this; + *derived = this; return RESULT_OK; } 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; } 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); } 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); } - DataTypeList::getInstance()->addCleanup(derived); + DataTypeList::getInstance()->addCleanup(*derived); return RESULT_OK; } -result_t NumberDataType::readRawValue(const SymbolString& input, - size_t offset, const size_t length, - unsigned int& value) const { +result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const { size_t start = 0, count = length; int incr = 1; symbol_t symbol; @@ -594,13 +589,13 @@ result_t NumberDataType::readRawValue(const SymbolString& input, incr = -1; } - value = 0; + *value = 0; unsigned int exp = 1; for (size_t index = start, i = 0; i < count; index += incr, i++) { symbol = input.dataAt(offset + index); if (hasFlag(BCD)) { if (!hasFlag(REQ) && symbol == (m_replacement & 0xff)) { - value = m_replacement; + *value = m_replacement; return RESULT_OK; } if (!hasFlag(HCD)) { @@ -611,40 +606,39 @@ result_t NumberDataType::readRawValue(const SymbolString& input, } else if (symbol > 0x63) { return RESULT_ERR_OUT_OF_RANGE; // invalid HCD } - value += symbol * exp; + *value += symbol * exp; exp *= 100; } else { - value |= symbol * exp; + *value |= symbol * exp; exp <<= 8; } } if (m_firstBit > 0) { - value >>= m_firstBit; + *value >>= m_firstBit; } if (m_bitCount < 8) { - value &= (1 << m_bitCount) - 1; + *value &= (1 << m_bitCount) - 1; } return RESULT_OK; } -result_t NumberDataType::readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const { +result_t NumberDataType::readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const { unsigned int value = 0; int signedValue; - result_t result = readRawValue(input, offset, length, value); + result_t result = readRawValue(offset, length, input, &value); if (result != RESULT_OK) { return result; } - output << setw(0) << dec; // initialize output + *output << setw(0) << dec; // initialize output if (!hasFlag(REQ) && value == m_replacement) { if (outputFormat & OF_JSON) { - output << "null"; + *output << "null"; } else { - output << NULL_VALUE; + *output << NULL_VALUE; } return RESULT_OK; } @@ -694,21 +688,21 @@ result_t NumberDataType::readSymbols(const SymbolString& input, } } if (m_precision != 0) { - output << fixed << setprecision(static_cast(m_precision+6)); + *output << fixed << setprecision(static_cast(m_precision+6)); } else if (val == 0) { - output << fixed << setprecision(1); + *output << fixed << setprecision(1); } - output << static_cast(val); + *output << static_cast(val); return RESULT_OK; } if (!negative) { if (m_divisor < 0) { - output << (static_cast(value) * static_cast(-m_divisor)); + *output << (static_cast(value) * static_cast(-m_divisor)); } else if (m_divisor <= 1) { - output << static_cast(value); + *output << static_cast(value); } else { - output << setprecision(static_cast(m_precision)) - << fixed << (static_cast(value) / static_cast(m_divisor)); + *output << setprecision(static_cast(m_precision)) + << fixed << (static_cast(value) / static_cast(m_divisor)); } return RESULT_OK; } @@ -719,30 +713,27 @@ result_t NumberDataType::readSymbols(const SymbolString& input, signedValue = static_cast(value); } if (m_divisor < 0) { - output << fixed << setprecision(0) + *output << fixed << setprecision(0) << (static_cast(signedValue) * static_cast(-m_divisor)); } else if (m_divisor <= 1) { if (hasFlag(FIX) && hasFlag(BCD)) { if (outputFormat & OF_JSON) { - output << '"'; - output << setw(static_cast(length * 2)) << setfill('0'); - output << static_cast(signedValue) << setw(0); - output << '"'; + *output << '"' << setw(static_cast(length * 2)) + << setfill('0') << static_cast(signedValue) << setw(0) << '"'; return RESULT_OK; } - output << setw(static_cast(length * 2)) << setfill('0'); + *output << setw(static_cast(length * 2)) << setfill('0'); } - output << static_cast(signedValue) << setw(0); + *output << static_cast(signedValue) << setw(0); } else { - output << setprecision(static_cast(m_precision)) - << fixed << (static_cast(signedValue) / static_cast(m_divisor)); + *output << setprecision(static_cast(m_precision)) + << fixed << (static_cast(signedValue) / static_cast(m_divisor)); } return RESULT_OK; } -result_t NumberDataType::writeRawValue(unsigned int value, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const { +result_t NumberDataType::writeRawValue(unsigned int value, size_t offset, size_t length, + SymbolString* output, size_t* usedLength) const { size_t start = 0, count = length; int incr = 1; symbol_t symbol; @@ -774,10 +765,10 @@ result_t NumberDataType::writeRawValue(unsigned int value, symbol = (value / exp) & 0xff; exp <<= 8; } - if (index == start && (m_bitCount % 8) != 0 && offset + index < output.getDataSize()) { - output.dataAt(offset + index) |= symbol; + if (index == start && (m_bitCount % 8) != 0 && offset + index < output->getDataSize()) { + output->dataAt(offset + index) |= symbol; } else { - output.dataAt(offset + index) = symbol; + output->dataAt(offset + index) = symbol; } } if (usedLength != NULL) { @@ -786,17 +777,16 @@ result_t NumberDataType::writeRawValue(unsigned int value, return RESULT_OK; } -result_t NumberDataType::writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const { +result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const { unsigned int value; - const char* str = input.str().c_str(); - if (!hasFlag(REQ) && (isIgnored() || strcmp(str, NULL_VALUE) == 0)) { + if (!hasFlag(REQ) && (isIgnored() || input->str() == NULL_VALUE)) { value = m_replacement; // replacement value - } else if (str == NULL || *str == 0) { + } else if (input->str().empty()) { return RESULT_ERR_EOF; // input too short } else if (hasFlag(EXP)) { // IEEE 754 binary32 + const char* str = input->str().c_str(); char* strEnd = NULL; double dvalue = strtod(str, &strEnd); if (strEnd == NULL || strEnd == str || *strEnd != 0) { @@ -835,6 +825,7 @@ result_t NumberDataType::writeSymbols(istringstream& input, } #endif } else { + const char* str = input->str().c_str(); char* strEnd = NULL; if (m_divisor == 1) { if (hasFlag(SIG)) { @@ -1038,7 +1029,7 @@ result_t DataTypeList::add(const DataType* dataType) { 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) { ostringstream str; str << id << LENGTH_SEPARATOR << static_cast(length); diff --git a/src/lib/ebus/datatype.h b/src/lib/ebus/datatype.h index 7b595694..49507270 100644 --- a/src/lib/ebus/datatype.h +++ b/src/lib/ebus/datatype.h @@ -167,7 +167,7 @@ class DataType { * @param replacement the replacement value (fill-up value for @a StringDataType, no replacement if equal to * @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) {} /** @@ -190,7 +190,7 @@ class DataType { * @param flag the flag to check (like #BCD). * @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. @@ -216,50 +216,47 @@ class DataType { /** * Dump the type identifier with the specified length and optionally the * divisor to the output. - * @param output the @a ostream to dump to. * @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 output the @a ostream to dump to. * @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. - * @param input the @a SymbolString to read the binary value from. * @param offset the offset in the @a SymbolString. * @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. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t readRawValue(const SymbolString& input, - const size_t offset, const size_t length, - unsigned int& value) const = 0; + virtual result_t readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const = 0; /** * 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 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 output the ostream to append the formatted value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const = 0; + virtual result_t readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const = 0; /** * 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 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 usedLength the variable in which to store the used length in bytes, or NULL. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const = 0; + virtual result_t writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const = 0; protected: @@ -291,8 +288,8 @@ class StringDataType : public DataType { * @param replacement the replacement value (fill-up value). * @param isHex true for hex digits instead of characters. */ - StringDataType(const string id, const size_t bitCount, const uint16_t flags, - const unsigned int replacement, bool isHex = false) + StringDataType(const string& id, size_t bitCount, uint16_t flags, + unsigned int replacement, bool isHex = false) : DataType(id, bitCount, flags, replacement), m_isHex(isHex) {} /** @@ -301,19 +298,16 @@ class StringDataType : public DataType { virtual ~StringDataType() {} // @copydoc - result_t readRawValue(const SymbolString& input, - const size_t offset, const size_t length, - unsigned int& value) const override; + result_t readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const override; // @copydoc - result_t readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const override; // @copydoc - result_t writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const override; private: @@ -337,8 +331,8 @@ class DateTimeDataType : public DataType { * @param hasTime true if time part is present. * @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, - const bool hasDate, const bool hasTime, const int16_t resolution) + DateTimeDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, + bool hasDate, bool hasTime, int16_t resolution) : DataType(id, bitCount, flags, replacement), m_hasDate(hasDate), m_hasTime(hasTime), m_resolution(resolution == 0 ? 1 : resolution) {} @@ -363,19 +357,16 @@ class DateTimeDataType : public DataType { int16_t getResolution() const { return m_resolution; } // @copydoc - result_t readRawValue(const SymbolString& input, - const size_t offset, const size_t length, - unsigned int& value) const override; + result_t readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const override; // @copydoc - result_t readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(size_t offset, size_t length, const SymbolString& input, + OutputFormat outputFormat, ostream* output) const override; // @copydoc - result_t writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(const size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const override; private: @@ -406,8 +397,8 @@ class NumberDataType : public DataType { * @param divisor the divisor (negative for reciprocal). * @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, - const unsigned int minValue, const unsigned int maxValue, const int divisor, + NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, + unsigned int minValue, unsigned int maxValue, int divisor, const NumberDataType* baseType) : 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) {} @@ -422,8 +413,8 @@ class NumberDataType : public DataType { * @param divisor the divisor (negative for reciprocal). * @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, - const int16_t firstBit, const int divisor, const NumberDataType* baseType = NULL) + NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, + 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), m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {} @@ -438,10 +429,10 @@ class NumberDataType : public DataType { * @param divisor the divisor (negative for reciprocal). * @return the precision for formatting the value. */ - static size_t calcPrecision(const int divisor); + static size_t calcPrecision(int divisor); // @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. @@ -453,7 +444,7 @@ class NumberDataType : public DataType { * not necessary. * @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. @@ -481,14 +472,12 @@ class NumberDataType : public DataType { int16_t getFirstBit() const { return m_firstBit; } // @copydoc - result_t readRawValue(const SymbolString& input, - const size_t offset, const size_t length, - unsigned int& value) const override; + result_t readRawValue(size_t offset, size_t length, const SymbolString& input, + unsigned int* value) const override; // @copydoc - result_t readSymbols(const SymbolString& input, - const size_t offset, const size_t length, - ostringstream& output, OutputFormat outputFormat) const override; + result_t readSymbols(size_t offset, size_t length, const SymbolString& input, + const OutputFormat outputFormat, ostream* output) const override; /** * Internal method for writing the numeric raw value to a @a SymbolString. @@ -500,14 +489,12 @@ class NumberDataType : public DataType { * or NULL. * @return @a RESULT_OK on success, or an error code. */ - result_t writeRawValue(unsigned int value, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength = NULL) const; + result_t writeRawValue(unsigned int value, size_t offset, size_t length, + SymbolString* output, size_t* usedLength) const; // @copydoc - result_t writeSymbols(istringstream& input, - const size_t offset, const size_t length, - SymbolString& output, size_t* usedLength) const override; + result_t writeSymbols(size_t offset, size_t length, istringstream* input, + SymbolString* output, size_t* usedLength) const override; private: @@ -580,7 +567,7 @@ class DataTypeList { * @return the @a DataType instance, or NULL if not available. * 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. diff --git a/src/lib/ebus/device.cpp b/src/lib/ebus/device.cpp index f30caa73..491d5f8b 100644 --- a/src/lib/ebus/device.cpp +++ b/src/lib/ebus/device.cpp @@ -42,7 +42,7 @@ Device::~Device() { 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) { char* in = strdup(name); 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 } 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) { free(in); return NULL; // invalid port @@ -98,7 +98,7 @@ bool Device::isValid() { return m_fd != -1; } -result_t Device::send(const symbol_t value) { +result_t Device::send(symbol_t value) { if (!isValid()) { return RESULT_ERR_DEVICE; } @@ -111,7 +111,7 @@ result_t Device::send(const symbol_t value) { 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()) { return RESULT_ERR_DEVICE; } @@ -162,7 +162,7 @@ result_t Device::recv(const unsigned int timeout, symbol_t& value) { return RESULT_ERR_DEVICE; } if (m_listener != NULL) { - m_listener->notifyDeviceData(value, true); + m_listener->notifyDeviceData(*value, true); } return RESULT_OK; } @@ -299,14 +299,14 @@ bool NetworkDevice::available() { 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 return Device::write(value); } -ssize_t NetworkDevice::read(symbol_t& value) { +ssize_t NetworkDevice::read(symbol_t* value) { if (available()) { - value = m_buffer[m_bufPos]; + *value = m_buffer[m_bufPos]; m_bufPos = (m_bufPos+1)%m_bufSize; m_bufLen--; return 1; @@ -316,7 +316,7 @@ ssize_t NetworkDevice::read(symbol_t& value) { if (size <= 0) { return size; } - value = m_buffer[0]; + *value = m_buffer[0]; m_bufPos = 1; m_bufLen = size-1; return size; diff --git a/src/lib/ebus/device.h b/src/lib/ebus/device.h index faa4c9dc..6f09f562 100644 --- a/src/lib/ebus/device.h +++ b/src/lib/ebus/device.h @@ -54,7 +54,7 @@ class DeviceListener { * @param symbol the received/sent symbol. * @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 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_listener(NULL) {} @@ -88,8 +88,8 @@ class Device { * @return the new @a Device, or NULL on error. * Note: the caller needs to free the created instance. */ - static Device* create(const char* name, const bool checkDevice = true, const bool readOnly = false, - const bool initialSend = false); + static Device* create(const char* name, bool checkDevice = true, bool readOnly = false, + bool initialSend = false); /** * Get the transfer latency of this device. @@ -113,7 +113,7 @@ class Device { * @param value the byte value to write. * @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. @@ -121,7 +121,7 @@ class Device { * @param value the reference in which the received byte value is stored. * @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. @@ -165,14 +165,14 @@ class Device { * @param value the byte value to write. * @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. * @param value the reference in which the read byte value is stored. * @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). */ const char* m_name; @@ -207,7 +207,7 @@ class SerialDevice : public Device { * @param readOnly whether to allow read access to the device only. * @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) {} // @copydoc @@ -240,8 +240,8 @@ class NetworkDevice : public Device { * @param initialSend whether to send an initial @a ESC symbol in @a open(). * @param udp true for UDP, false to TCP. */ - NetworkDevice(const char* name, const struct sockaddr_in address, const bool readOnly, const bool initialSend, - const bool udp) + NetworkDevice(const char* name, const struct sockaddr_in& address, bool readOnly, bool initialSend, + bool udp) : Device(name, true, readOnly, initialSend), m_address(address), m_udp(udp), m_buffer(NULL), m_bufSize(0), m_bufLen(0), m_bufPos(0) {} @@ -269,10 +269,10 @@ class NetworkDevice : public Device { bool available() override; // @copydoc - ssize_t write(const symbol_t value) override; + ssize_t write(symbol_t value) override; // @copydoc - ssize_t read(symbol_t& value) override; + ssize_t read(symbol_t* value) override; private: diff --git a/src/lib/ebus/filereader.cpp b/src/lib/ebus/filereader.cpp index 2df6bae7..5ebe8c65 100644 --- a/src/lib/ebus/filereader.cpp +++ b/src/lib/ebus/filereader.cpp @@ -36,21 +36,21 @@ using std::setw; using std::dec; -result_t FileReader::readFromFile(const string filename, string& errorDescription, bool verbose, - map* defaults, size_t* hash, size_t* size, time_t* time) { +result_t FileReader::readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time) { struct stat st; if (stat(filename.c_str(), &st) != 0) { - errorDescription = filename; + *errorDescription = filename; return RESULT_ERR_NOTFOUND; } if (S_ISDIR(st.st_mode)) { - errorDescription = filename+" is a directory"; + *errorDescription = filename+" is a directory"; return RESULT_ERR_NOTFOUND; } - ifstream ifs; - ifs.open(filename.c_str(), ifstream::in); - if (!ifs.is_open()) { - errorDescription = filename; + ifstream stream; + stream.open(filename.c_str(), ifstream::in); + if (!stream.is_open()) { + *errorDescription = filename; return RESULT_ERR_NOTFOUND; } if (hash) { @@ -65,60 +65,56 @@ result_t FileReader::readFromFile(const string filename, string& errorDescriptio unsigned int lineNo = 0; vector row; result_t result = RESULT_OK; - while (ifs.peek() != EOF && result == RESULT_OK) { - result = readLineFromStream(ifs, errorDescription, filename, lineNo, row, verbose, hash, size); + while (stream.peek() != EOF && result == RESULT_OK) { + result = readLineFromStream(filename, verbose, &stream, &lineNo, &row, errorDescription, hash, size); } - ifs.close(); + stream.close(); return result; } -result_t FileReader::readLineFromStream(istream& stream, string& errorDescription, - const string filename, unsigned int& lineNo, vector& row, bool verbose, - size_t* hash, size_t* size) { +result_t FileReader::readLineFromStream(const string& filename, bool verbose, istream* stream, + unsigned int* lineNo, vector* row, string* errorDescription, size_t* hash, size_t* size) { result_t result; if (!splitFields(stream, row, lineNo, hash, size)) { - errorDescription = "blank line"; + *errorDescription = "blank line"; result = RESULT_ERR_EOF; } else { - errorDescription = ""; - result = addFromFile(row, errorDescription, filename, lineNo); + *errorDescription = ""; + result = addFromFile(filename, *lineNo, row, errorDescription); } if (result != RESULT_OK) { - if (!verbose) { - ostringstream error; - error << filename << ":" << lineNo; - if (errorDescription.length() > 0) { - error << ": " << errorDescription; + if (!errorDescription->empty()) { + string error; + formatError(filename, *lineNo, result, *errorDescription, &error); + *errorDescription = error; + 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) { + return formatError(filename, *lineNo, result, "", errorDescription); } } else if (!verbose) { - errorDescription = ""; + *errorDescription = ""; } return result; } -void FileReader::trim(string& str) { - size_t pos = str.find_first_not_of(" \t"); +void FileReader::trim(string* str) { + size_t pos = str->find_first_not_of(" \t"); 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) { - str.erase(pos+1); + str->erase(pos+1); } } -void FileReader::tolower(string& str) { - transform(str.begin(), str.end(), str.begin(), ::tolower); +void FileReader::tolower(string* str) { + 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; for (char c : str) { hash = (31 * hash) ^ c; @@ -126,27 +122,27 @@ static size_t hashFunction(const string str) { return hash; } -bool FileReader::splitFields(istream& ifs, vector& row, unsigned int& lineNo, +bool FileReader::splitFields(istream* stream, vector* row, unsigned int* lineNo, size_t* hash, size_t* size) { - row.clear(); + row->clear(); string line; bool quotedText = false, wasQuoted = false; ostringstream field; char prev = FIELD_SEPARATOR; bool empty = true, read = false; - while (getline(ifs, line)) { + while (getline(*stream, line)) { read = true; - lineNo++; - trim(line); + ++(*lineNo); + trim(&line); size_t length = line.size(); if (size) { *size += length + 1; // normalized with trailing endl } 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 (lineNo == 1) { + if (*lineNo == 1) { break; // keep empty first line for applying default header } continue; // skip empty lines and comments @@ -159,9 +155,9 @@ bool FileReader::splitFields(istream& ifs, vector& row, unsigned int& li field << ch; } else { string str = field.str(); - trim(str); + trim(&str); empty &= str.empty(); - row.push_back(str); + row->push_back(str); field.str(""); wasQuoted = false; } @@ -197,37 +193,52 @@ bool FileReader::splitFields(istream& ifs, vector& row, unsigned int& li } } string str = field.str(); - trim(str); + trim(&str); if (empty && str.empty()) { - row.clear(); + row->clear(); return read; } - row.push_back(str); + row->push_back(str); return true; } +result_t FileReader::formatError(const string& filename, unsigned int lineNo, result_t result, + const string& error, string* errorDescription) { + ostringstream str; + if (!errorDescription->empty()) { + str << *errorDescription << ", "; + } + str << filename << ":" << static_cast(lineNo) << ": " << getResultCode(result); + if (!error.empty()) { + str << ", " << error; + } + *errorDescription = str.str(); + return result; +} -string MappedFileReader::normalizeLanguage(string lang) { - tolower(lang); - if (lang.size() > 2) { - size_t pos = lang.find('.'); + +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 = lang.size(); + pos = normLang.size(); } - size_t strip = lang.find('_'); + size_t strip = normLang.find('_'); if (strip == string::npos || strip > pos) { strip = pos; } if (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, - map* defaults, size_t* hash, size_t* size, time_t* time) { +result_t MappedFileReader::readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time) { m_mutex.lock(); m_columnNames.clear(); m_lastDefaults.clear(); @@ -237,47 +248,47 @@ result_t MappedFileReader::readFromFile(const string filename, string& errorDesc } size_t lastSep = filename.find_last_of('/'); string defaultsPart = lastSep == string::npos ? filename : filename.substr(lastSep+1); - extractDefaultsFromFilename(defaultsPart, m_lastDefaults[""]); - result_t result = FileReader::readFromFile(filename, errorDescription, verbose, defaults, hash, size, time); + extractDefaultsFromFilename(defaultsPart, &m_lastDefaults[""], NULL, NULL, NULL); + result_t result = FileReader::readFromFile(filename, verbose, defaults, errorDescription, hash, size, time); m_mutex.unlock(); return result; } -result_t MappedFileReader::addFromFile(vector& row, string& errorDescription, - const string filename, unsigned int lineNo) { +result_t MappedFileReader::addFromFile(const string& filename, unsigned int lineNo, vector* row, + string* errorDescription) { result_t result; if (lineNo == 1) { // first line defines column names - result = getFieldMap(row, errorDescription, m_preferLanguage); + result = getFieldMap(m_preferLanguage, row, errorDescription); if (result != RESULT_OK) { return result; } - if (row.empty()) { - errorDescription = "missing field map"; + if (row->empty()) { + *errorDescription = "missing field map"; return RESULT_ERR_EOF; } - m_columnNames = row; + m_columnNames = *row; return RESULT_OK; } - if (row.empty()) { + if (row->empty()) { return RESULT_OK; } if (m_columnNames.empty()) { - errorDescription = "missing field map"; + *errorDescription = "missing field map"; return RESULT_ERR_INVALID_ARG; } map rowMapped; vector< map > subRowsMapped; - bool isDefault = m_supportsDefaults && !row[0].empty() && row[0][0] == '*'; + bool isDefault = m_supportsDefaults && !(*row)[0].empty() && (*row)[0][0] == '*'; if (isDefault) { - row[0] = row[0].substr(1); + (*row)[0].erase(0, 1); } size_t lastRepeatStart = UINT_MAX; map* lastMappedRow = &rowMapped; 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 (lastRepeatStart == UINT_MAX) { - errorDescription = "named columns exceeded"; + *errorDescription = "named columns exceeded"; return RESULT_ERR_INVALID_ARG; } colNameIdx = lastRepeatStart; @@ -297,7 +308,7 @@ result_t MappedFileReader::addFromFile(vector& row, string& errorDescrip } else if (columnName == SKIP_COLUMN) { continue; } - string value = row[colIdx]; + string value = (*row)[colIdx]; empty &= value.empty(); (*lastMappedRow)[columnName] = value; } @@ -308,12 +319,12 @@ result_t MappedFileReader::addFromFile(vector& row, string& errorDescrip } } 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& row) { +const string MappedFileReader::combineRow(const map& row) { ostringstream ostream; bool first = true; for (auto entry : row) { diff --git a/src/lib/ebus/filereader.h b/src/lib/ebus/filereader.h index 75e579ac..77028a25 100644 --- a/src/lib/ebus/filereader.h +++ b/src/lib/ebus/filereader.h @@ -79,76 +79,88 @@ class FileReader { /** * Read the definitions from a file. * @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 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 size optional pointer to a @a size_t value for storing the normalized size of the file, or NULL. * @param time optional pointer to a @a time_t value for storing the modification time of the file, or NULL. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t readFromFile(const string filename, string& errorDescription, bool verbose = false, - map* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL); + virtual result_t readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time); /** * 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 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 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 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. */ - virtual result_t readLineFromStream(istream& stream, string& errorDescription, - const string filename, unsigned int& lineNo, vector& row, bool verbose = false, - size_t* hash = NULL, size_t* size = NULL); + virtual result_t readLineFromStream(const string& filename, bool verbose, istream* stream, + unsigned int* lineNo, vector* row, string* errorDescription, size_t* hash, size_t* size); /** * 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 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. */ - virtual result_t addFromFile(vector& row, string& errorDescription, - const string filename, unsigned int lineNo) = 0; + virtual result_t addFromFile(const string& filename, unsigned int lineNo, vector* row, + string* errorDescription) = 0; /** * Left and right trim the string. * @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. * @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. - * @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 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 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. */ - static bool splitFields(istream& ifs, vector& row, unsigned int& lineNo, + static bool splitFields(istream* stream, vector* row, unsigned int* lineNo, size_t* hash = NULL, size_t* size = NULL); /** * Format the specified hash as 8 hex digits to the output stream. * @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) { - str << std::hex << std::setw(8) << std::setfill('0') << (hash & 0xffffffff) << std::dec << std::setw(0); + static void formatHash(size_t hash, ostream* stream) { + *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,8 +175,8 @@ class MappedFileReader : public FileReader { * @param supportsDefaults whether this instance supports rows with defaults (starting with a star). * @param preferLanguage the preferred language code, or empty. */ - explicit MappedFileReader(bool supportsDefaults, const string preferLanguage = "") - : FileReader(), m_supportsDefaults(supportsDefaults), m_preferLanguage(normalizeLanguage(preferLanguage)) { + explicit MappedFileReader(bool supportsDefaults, const string& preferLanguage = "") + : FileReader(), m_supportsDefaults(supportsDefaults), m_preferLanguage(normalizeLanguage(preferLanguage)) { } /** @@ -181,11 +193,11 @@ class MappedFileReader : public FileReader { * @param lang the language string to normalize. * @return the normalized language code. */ - static string normalizeLanguage(string lang); + static const string normalizeLanguage(const string& lang); // @copydoc - result_t readFromFile(const string filename, string& errorDescription, bool verbose = false, - map* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL) override; + result_t readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time) override; /** * 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. * @return true if the minimum parts were extracted, false otherwise. */ - virtual bool extractDefaultsFromFilename(string filename, map& defaults, - symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const { + virtual bool extractDefaultsFromFilename(const string& filename, map* defaults, + symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const { return false; } // @copydoc - result_t addFromFile(vector& row, string& errorDescription, - const string filename, unsigned int lineNo) override; + result_t addFromFile(const string& filename, unsigned int lineNo, vector* row, + string* errorDescription) override; /** * 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. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const = 0; + virtual result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const = 0; /** * 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. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t addDefaultFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) { - errorDescription = "defaults not supported"; + virtual result_t addDefaultFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) { + *errorDescription = "defaults not supported"; return RESULT_ERR_INVALID_ARG; } /** * 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 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. */ - virtual result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) = 0; + virtual result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) = 0; /** * @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. * @return the combined string. */ - static string combineRow(const map& row); + static const string combineRow(const map& row); private: /** whether this instance supports rows with defaults (starting with a star). */ diff --git a/src/lib/ebus/message.cpp b/src/lib/ebus/message.cpp index 23169023..e54bb391 100644 --- a/src/lib/ebus/message.cpp +++ b/src/lib/ebus/message.cpp @@ -79,7 +79,7 @@ static const char* defaultMessageFieldMap[] = { // access level not included in "*name", "part", "type", "divisor/values", "unit", "comment", }; -extern DataFieldTemplates* getTemplates(const string filename); +extern DataFieldTemplates* getTemplates(const string& filename); /** * Get the normalized message field name for the given name. @@ -87,7 +87,7 @@ extern DataFieldTemplates* getTemplates(const string filename); * @param supportsLanguage set to true when the field supports multiple language. * @return the normalized message field name, or empty if unknown. */ -string getMessageFieldName(const string name, bool& supportsLanguage) { +string getMessageFieldName(const string& name, bool* supportsLanguage) { if (name.find("type") != string::npos) { return "type"; } @@ -97,23 +97,20 @@ string getMessageFieldName(const string name, bool& supportsLanguage) { if (name.find("name") != string::npos) { return "name"; } - supportsLanguage = true; + *supportsLanguage = true; if (name.find("comment") == 0) { return "comment"; } return ""; } -/* case MESSAGEFIELD_DATAFIELDS: - return withDataFields ? "fields" : ""; - */ -Message::Message(const string circuit, const string level, const string name, - const bool isWrite, const bool isPassive, const map& attributes, - const symbol_t srcAddress, const symbol_t dstAddress, - const vector id, - const DataField* data, const bool deleteData, - const size_t pollPriority, +Message::Message(const string& circuit, const string& level, const string& name, + bool isWrite, bool isPassive, const map& attributes, + symbol_t srcAddress, symbol_t dstAddress, + const vector& id, + const DataField* data, bool deleteData, + size_t pollPriority, Condition* condition) : AttributedItem(name, attributes), m_circuit(circuit), m_level(level), m_isWrite(isWrite), m_isPassive(isPassive), @@ -129,9 +126,9 @@ Message::Message(const string circuit, const string level, const string name, } } -Message::Message(const string circuit, const string level, const string name, - const symbol_t pb, const symbol_t sb, - const bool broadcast, const DataField* data, const bool deleteData) +Message::Message(const string& circuit, const string& level, const string& name, + symbol_t pb, symbol_t sb, + bool broadcast, const DataField* data, bool deleteData) : AttributedItem(name), m_circuit(circuit), m_level(level), m_isWrite(broadcast), m_isPassive(false), m_srcAddress(SYN), m_dstAddress(broadcast ? BROADCAST : SYN), @@ -155,7 +152,7 @@ Message::Message(const string circuit, const string level, const string name, * empty and @p replaceStar is @p true. * @return the default if available and value is empty, or the value. */ -string getDefault(const string value, const map& defaults, const string fieldName, +string getDefault(const string& value, const map& defaults, const string& fieldName, bool replaceStar = false, bool required = false) { if (defaults.empty()) { return value; @@ -175,9 +172,8 @@ string getDefault(const string value, const map& defaults, const return defaultStr.substr(0, insertPos)+value+defaultStr.substr(insertPos+1); } -uint64_t Message::createKey(const vector id, - const bool isWrite, const bool isPassive, - const symbol_t srcAddress, const symbol_t dstAddress) { +uint64_t Message::createKey(const vector& id, bool isWrite, bool isPassive, symbol_t srcAddress, + symbol_t dstAddress) { uint64_t key = (uint64_t)(id.size()-2) << (8 * 7 + 5); if (isPassive) { key |= (uint64_t)getMasterNumber(srcAddress) << (8 * 7); // 0..25 @@ -221,7 +217,7 @@ uint64_t Message::createKey(const MasterSymbolString& master, size_t maxIdLength return key; } -uint64_t Message::createKey(const symbol_t pb, const symbol_t sb, const bool broadcast) { +uint64_t Message::createKey(symbol_t pb, symbol_t sb, bool broadcast) { uint64_t key = 0; key |= (broadcast ? 0x1fLL : 0x1eLL) << (8 * 7); // special values for active key |= (uint64_t)(broadcast ? BROADCAST : SYN) << (8 * 6); @@ -230,8 +226,9 @@ uint64_t Message::createKey(const symbol_t pb, const symbol_t sb, const bool bro return key; } -result_t Message::parseId(string input, vector& id) { +result_t Message::parseId(const string& input, vector* id) { istringstream in(input); + string str; while (!in.eof()) { while (in.peek() == ' ') { in.get(); @@ -239,35 +236,38 @@ result_t Message::parseId(string input, vector& id) { if (in.eof()) { // no more digits break; } - input.clear(); - input.push_back(static_cast(in.get())); + str.clear(); + str.push_back(static_cast(in.get())); if (in.eof()) { return RESULT_ERR_INVALID_ARG; // too short hex } - input.push_back(static_cast(in.get())); + str.push_back(static_cast(in.get())); result_t result; - symbol_t value = (symbol_t)parseInt(input.c_str(), 16, 0, 0xff, result); + symbol_t value = (symbol_t)parseInt(str.c_str(), 16, 0, 0xff, &result); if (result != RESULT_OK) { return result; // invalid hex value } - id.push_back(value); + id->push_back(value); } return RESULT_OK; } -result_t Message::create(map row, vector< map > subRows, - map >& rowDefaults, map > >& subRowDefaults, - string& errorDescription, Condition* condition, const string filename, DataFieldTemplates* templates, - vector& messages) { +static const map noDefaults; + +result_t Message::create(const string& filename, const DataFieldTemplates* templates, + const map >& rowDefaults, + const map > >& subRowDefaults, + const string& typeStr, Condition* condition, + map* row, vector< map >* subRows, + string* errorDescription, vector* messages) { // [type],[circuit],name,[comment],[QQ[;QQ]*],[ZZ],[PBSB],[ID],fields... result_t result; bool isWrite = false, isPassive = false; string defaultName; size_t pollPriority = 0; - string typeStr = pluck(row, "type"); if (typeStr.empty()) { - errorDescription = "empty type"; + *errorDescription = "empty type"; return RESULT_ERR_EOF; } if (typeStr.empty()) { // default: active read @@ -275,7 +275,7 @@ result_t Message::create(map row, vector< map > } else { defaultName = typeStr; string lower = typeStr; - FileReader::tolower(lower); + FileReader::tolower(&lower); char type = lower[0]; if (type == 'r') { // active read char poll = lower[1]; @@ -292,44 +292,45 @@ result_t Message::create(map row, vector< map > } } - map& defaults = rowDefaults[defaultName]; - string circuit = getDefault(pluck(row, "circuit"), defaults, "circuit", true); // [circuit[#level]] - string level = getDefault(pluck(row, "level"), defaults, "level", true); + auto it = rowDefaults.find(defaultName); + const map& defaults = it == rowDefaults.end() ? noDefaults : it->second; + string circuit = getDefault(pluck("circuit", row), defaults, "circuit", true); // [circuit[#level]] + string level = getDefault(pluck("level", row), defaults, "level", true); size_t pos = circuit.find('#'); // TODO remove some day if (pos != string::npos) { level = circuit.substr(pos+1); circuit.resize(pos); } if (circuit.empty()) { - errorDescription = "circuit"; + *errorDescription = "circuit"; return RESULT_ERR_MISSING_ARG; // empty circuit } - string name = getDefault(pluck(row, "name"), defaults, "name", true, true); // name + string name = getDefault(pluck("name", row), defaults, "name", true, true); // name if (name.empty()) { - errorDescription = "name"; + *errorDescription = "name"; return RESULT_ERR_MISSING_ARG; // empty name } - string comment = getDefault(pluck(row, "comment"), defaults, "comment", true); // [comment] + string comment = getDefault(pluck("comment", row), defaults, "comment", true); // [comment] if (!comment.empty()) { - row["comment"] = comment; + (*row)["comment"] = comment; } - string str = getDefault(pluck(row, "qq"), defaults, "qq"); // [QQ[;QQ]*] + string str = getDefault(pluck("qq", row), defaults, "qq"); // [QQ[;QQ]*] symbol_t srcAddress; if (str.empty()) { srcAddress = SYN; // no specific source } else { - srcAddress = (symbol_t)parseInt(str.c_str(), 16, 0, 0xff, result); + srcAddress = (symbol_t)parseInt(str.c_str(), 16, 0, 0xff, &result); if (result != RESULT_OK) { - errorDescription = "qq "+str; + *errorDescription = "qq "+str; return result; } if (!isMaster(srcAddress)) { - errorDescription = "qq "+str; + *errorDescription = "qq "+str; return RESULT_ERR_INVALID_ADDR; } } - str = getDefault(pluck(row, "zz"), defaults, "zz"); // [ZZ] + str = getDefault(pluck("zz", row), defaults, "zz"); // [ZZ] vector dstAddresses; bool isBroadcastOrMasterDestination = false; if (str.empty()) { @@ -339,14 +340,14 @@ result_t Message::create(map row, vector< map > string token; bool first = true; while (getline(stream, token, VALUE_SEPARATOR)) { - FileReader::trim(token); - symbol_t dstAddress = (symbol_t)parseInt(token.c_str(), 16, 0, 0xff, result); + FileReader::trim(&token); + symbol_t dstAddress = (symbol_t)parseInt(token.c_str(), 16, 0, 0xff, &result); if (result != RESULT_OK) { - errorDescription = "zz "+token; + *errorDescription = "zz "+token; return result; } if (!isValidAddress(dstAddress)) { - errorDescription = "zz "+token; + *errorDescription = "zz "+token; return RESULT_ERR_INVALID_ADDR; } bool broadcastOrMaster = (dstAddress == BROADCAST) || isMaster(dstAddress); @@ -354,7 +355,7 @@ result_t Message::create(map row, vector< map > isBroadcastOrMasterDestination = broadcastOrMaster; first = false; } else if (isBroadcastOrMasterDestination != broadcastOrMaster) { - errorDescription = "zz "+token; + *errorDescription = "zz "+token; return RESULT_ERR_INVALID_ADDR; } dstAddresses.push_back(dstAddress); @@ -362,21 +363,21 @@ result_t Message::create(map row, vector< map > } vector id; - str = pluck(row, "pbsb"); // [PBSB] + str = pluck("pbsb", row); // [PBSB] bool useDefaults = str.empty(); if (useDefaults) { str = getDefault(str, defaults, "pbsb"); } - result = parseId(str, id); + result = parseId(str, &id); if (result != RESULT_OK) { - errorDescription = "pbsb "+str; + *errorDescription = "pbsb "+str; return result; } if (id.size() != 2) { - errorDescription = "pbsb "+str; + *errorDescription = "pbsb "+str; return RESULT_ERR_INVALID_ARG; // missing/to short/to long PBSB } - str = pluck(row, "id"); // [ID] (optional master data) + str = pluck("id", row); // [ID] (optional master data) string defaultIdPrefix; if (useDefaults) { defaultIdPrefix = getDefault("", defaults, "id"); @@ -389,26 +390,26 @@ result_t Message::create(map row, vector< map > size_t chainPrefixLength = id.size(); bool first = true, lastChainLengthSpecified = false; while (getline(stream, str, VALUE_SEPARATOR) || first) { - FileReader::trim(str); + FileReader::trim(&str); str = defaultIdPrefix+str; size_t lengthPos = str.find(LENGTH_SEPARATOR); lastChainLengthSpecified = lengthPos != string::npos; if (lastChainLengthSpecified) { - chainLength = parseInt(str.substr(lengthPos+1).c_str(), 10, 0, MAX_POS, result); + chainLength = parseInt(str.substr(lengthPos+1).c_str(), 10, 0, MAX_POS, &result); if (result != RESULT_OK) { - errorDescription = "id "+str; + *errorDescription = "id "+str; return result; } str.resize(lengthPos); } vector chainId = id; - result = parseId(str, chainId); + result = parseId(str, &chainId); if (result != RESULT_OK) { - errorDescription = "id "+str; + *errorDescription = "id "+str; return result; } if (!chainIds.empty() && chainId.size() != chainIds.front().size()) { - errorDescription = "id length "+str; + *errorDescription = "id length "+str; return RESULT_ERR_INVALID_LIST; } chainIds.push_back(chainId); @@ -426,7 +427,7 @@ result_t Message::create(map row, vector< map > } } if (maxLength+chainLength > 255) { - errorDescription = "id length "+str; + *errorDescription = "id length "+str; return RESULT_ERR_INVALID_POS; } maxLength += chainLength; @@ -435,7 +436,7 @@ result_t Message::create(map row, vector< map > id = chainIds.front(); if (chainIds.size() > 1) { if (isPassive) { - errorDescription = "id (passive)"; + *errorDescription = "id (passive)"; return RESULT_ERR_INVALID_LIST; } if (id.size() > chainPrefixLength) { @@ -448,17 +449,17 @@ result_t Message::create(map row, vector< map > maxLength = MAX_POS; } vector newTypes; - vector< map >& subDefaults = subRowDefaults[defaultName]; - if (!subDefaults.empty()) { - subRows.insert(subRows.begin(), subDefaults.begin(), subDefaults.end()); + auto subIt = subRowDefaults.find(defaultName); + if (subIt != subRowDefaults.end()) { + subRows->insert(subRows->begin(), subIt->second.begin(), subIt->second.end()); } const DataField* data = NULL; - if (subRows.empty()) { + if (subRows->empty()) { vector fields; data = new DataFieldSet("", fields); } else { - result = DataField::create(subRows, errorDescription, templates, data, isWrite, false, - isBroadcastOrMasterDestination, maxLength); + result = DataField::create(isWrite, false, isBroadcastOrMasterDestination, maxLength, templates, + subRows, errorDescription, &data); if (result != RESULT_OK) { return result; } @@ -467,7 +468,7 @@ result_t Message::create(map row, vector< map > || data->getLength(pt_slaveData, maxLength) > maxLength) { // max NN exceeded delete data; - errorDescription = "data length"; + *errorDescription = "data length"; return RESULT_ERR_INVALID_POS; } unsigned int index = 0; @@ -481,13 +482,13 @@ result_t Message::create(map row, vector< map > } Message* message; if (chainIds.size() > 1) { - message = new ChainedMessage(useCircuit, level, name, isWrite, row, srcAddress, dstAddress, id, chainIds, + message = new ChainedMessage(useCircuit, level, name, isWrite, *row, srcAddress, dstAddress, id, chainIds, chainLengths, data, index == 0, pollPriority, condition); } else { - message = new Message(useCircuit, level, name, isWrite, isPassive, row, srcAddress, dstAddress, id, data, + message = new Message(useCircuit, level, name, isWrite, isPassive, *row, srcAddress, dstAddress, id, data, index == 0, pollPriority, condition); } - messages.push_back(message); + messages->push_back(message); index++; } return RESULT_OK; @@ -497,7 +498,7 @@ Message* Message::createScanMessage(bool broadcast) { return new Message("scan", "", "", 0x07, 0x04, broadcast, DataFieldSet::getIdentFields(), !broadcast); } -bool Message::extractFieldNames(string str, vector& fields, bool checkAbbreviated) { +bool Message::extractFieldNames(const string& str, bool checkAbbreviated, vector* fields) { istringstream input(str); vector row; string column; @@ -516,12 +517,12 @@ bool Message::extractFieldNames(string str, vector& fields, bool checkAb if (idx != knownFieldCount) { column = knownFieldNamesFull[idx]; } // else: custom attribute - fields.push_back(column); + fields->push_back(column); } - return !fields.empty(); + return !fields->empty(); } -Message* Message::derive(const symbol_t dstAddress, const symbol_t srcAddress, const string circuit) const { +Message* Message::derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const { Message* result = new Message(circuit.length() == 0 ? m_circuit : circuit, m_level, m_name, m_isWrite, m_isPassive, m_attributes, srcAddress == SYN ? m_srcAddress : srcAddress, dstAddress, @@ -533,7 +534,7 @@ Message* Message::derive(const symbol_t dstAddress, const symbol_t srcAddress, c return result; } -Message* Message::derive(const symbol_t dstAddress, const bool extendCircuit) const { +Message* Message::derive(symbol_t dstAddress, bool extendCircuit) const { if (extendCircuit) { ostringstream out; out << m_circuit << '.' << hex << setw(2) << setfill('0') << static_cast(dstAddress); @@ -542,7 +543,7 @@ Message* Message::derive(const symbol_t dstAddress, const bool extendCircuit) co return derive(dstAddress, SYN, m_circuit); } -bool Message::checkLevel(const string level, const string checkLevels) { +bool Message::checkLevel(const string& level, const string& checkLevels) { if (level.empty()) { return true; } @@ -593,7 +594,7 @@ bool Message::checkId(const MasterSymbolString& master, size_t* index) const { return true; } -bool Message::checkId(Message& other) const { +bool Message::checkId(const Message& other) const { size_t idLen = getIdLength(); if (idLen != other.getIdLength() || getCount() > 1) { // only equal for non-chained messages return false; @@ -601,7 +602,7 @@ bool Message::checkId(Message& other) const { return other.checkIdPrefix(m_id); } -uint64_t Message::getDerivedKey(const symbol_t dstAddress) const { +uint64_t Message::getDerivedKey(symbol_t dstAddress) const { return (m_key & ~(0xffLL << (8*6))) | (uint64_t)dstAddress << (8*6); } @@ -609,11 +610,12 @@ bool Message::setPollPriority(size_t priority) { if (priority == m_pollPriority || m_isPassive || isScanMessage() || m_dstAddress == SYN) { return false; } + size_t usePriority = priority; if (m_usedByCondition && (priority == 0 || priority > POLL_PRIORITY_CONDITION)) { - priority = POLL_PRIORITY_CONDITION; + usePriority = POLL_PRIORITY_CONDITION; } - bool ret = m_pollPriority == 0 && priority > 0; - m_pollPriority = priority; + bool ret = m_pollPriority == 0 && usePriority > 0; + m_pollPriority = usePriority; return ret; } @@ -635,80 +637,78 @@ bool Message::hasField(const char* fieldName, bool numeric) const { return m_data->hasField(fieldName, numeric); } -result_t Message::prepareMaster(const symbol_t srcAddress, MasterSymbolString& master, - istringstream& input, char separator, - const symbol_t dstAddress, size_t index) { +result_t Message::prepareMaster(size_t index, symbol_t srcAddress, symbol_t dstAddress, + char separator, istringstream* input, MasterSymbolString* master) { if (m_isPassive) { return RESULT_ERR_INVALID_ARG; // prepare not possible } - master.clear(); - master.push_back(srcAddress); + master->clear(); + master->push_back(srcAddress); if (dstAddress == SYN) { if (m_dstAddress == SYN) { return RESULT_ERR_INVALID_ADDR; } - master.push_back(m_dstAddress); + master->push_back(m_dstAddress); } else { - master.push_back(dstAddress); + master->push_back(dstAddress); } - master.push_back(m_id[0]); - master.push_back(m_id[1]); - result_t result = prepareMasterPart(master, input, separator, index); + master->push_back(m_id[0]); + master->push_back(m_id[1]); + result_t result = prepareMasterPart(index, separator, input, master); if (result != RESULT_OK) { return result; } - result = storeLastData(master, index); + result = storeLastData(index, *master); if (result < RESULT_OK) { return result; } return RESULT_OK; } -result_t Message::prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, - size_t index) { +result_t Message::prepareMasterPart(size_t index, char separator, istringstream* input, MasterSymbolString* master) { if (index != 0) { return RESULT_ERR_NOTFOUND; } - master.push_back(0); // length, will be set later + master->push_back(0); // length, will be set later for (size_t i = 2; i < m_id.size(); i++) { - master.push_back(m_id[i]); + master->push_back(m_id[i]); } - result_t result = m_data->write(input, master, getIdLength(), separator); + result_t result = m_data->write(separator, getIdLength(), input, master, NULL); if (result != RESULT_OK) { return result; } - master.adjustHeader(); + master->adjustHeader(); return result; } -result_t Message::prepareSlave(istringstream& input, SlaveSymbolString& slave) { +result_t Message::prepareSlave(istringstream* input, SlaveSymbolString* slave) { if (m_isWrite) { return RESULT_ERR_INVALID_ARG; // prepare not possible } - slave.clear(); - slave.push_back(0); // length, will be set later - result_t result = m_data->write(input, slave, 0); + slave->clear(); + slave->push_back(0); // length, will be set later + result_t result = m_data->write(UI_FIELD_SEPARATOR, 0, input, slave, NULL); if (result != RESULT_OK) { return result; } - slave.adjustHeader(); + slave->adjustHeader(); time(&m_lastUpdateTime); - if (slave != m_lastSlaveData) { + if (*slave != m_lastSlaveData) { m_lastChangeTime = m_lastUpdateTime; - m_lastSlaveData = slave; + m_lastSlaveData = *slave; } return result; } -result_t Message::storeLastData(MasterSymbolString& master, SlaveSymbolString& slave) { - result_t result = storeLastData(master, 0); +result_t Message::storeLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) { + result_t result = storeLastData(0, master); if (result >= RESULT_OK) { - result = storeLastData(slave, 0); + result = storeLastData(0, slave); } return result; } -result_t Message::storeLastData(MasterSymbolString& data, size_t index) { +result_t Message::storeLastData(size_t index, const MasterSymbolString& data) { if (data.size() > 0 && (m_isWrite || this->m_dstAddress == BROADCAST || isMaster(this->m_dstAddress) || data.getDataSize() + 2 > m_id.size())) { time(&m_lastUpdateTime); @@ -726,22 +726,27 @@ result_t Message::storeLastData(MasterSymbolString& data, size_t index) { return RESULT_OK; } -result_t Message::storeLastData(SlaveSymbolString& data, size_t index) { +result_t Message::storeLastData(size_t index, const SlaveSymbolString& data) { if (data.size() > 0) { time(&m_lastUpdateTime); } - if (data != m_lastSlaveData) { + if (m_lastSlaveData != data) { m_lastChangeTime = m_lastUpdateTime; m_lastSlaveData = data; } return RESULT_OK; } -result_t Message::decodeLastMasterData(ostringstream& output, OutputFormat outputFormat, - bool leadingSeparator, const char* fieldName, ssize_t fieldIndex) const { - size_t offset = m_id.size() - 2; - result_t result = m_data->read(m_lastMasterData, offset, - output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex); +result_t Message::decodeLastData(bool master, bool leadingSeparator, const char* fieldName, + ssize_t fieldIndex, OutputFormat outputFormat, ostream* output) const { + result_t result; + if (master) { + result = m_data->read(m_lastMasterData, m_id.size() - 2, leadingSeparator, fieldName, fieldIndex, + outputFormat, -1, output); + } else { + result = m_data->read(m_lastSlaveData, 0, leadingSeparator, fieldName, fieldIndex, + outputFormat, -1, output); + } if (result < RESULT_OK) { return result; } @@ -751,30 +756,17 @@ result_t Message::decodeLastMasterData(ostringstream& output, OutputFormat outpu return result; } -result_t Message::decodeLastSlaveData(ostringstream& output, OutputFormat outputFormat, - bool leadingSeparator, const char* fieldName, ssize_t fieldIndex) const { - result_t result = m_data->read(m_lastSlaveData, 0, - output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex); - if (result < RESULT_OK) { - return result; - } - if (result == RESULT_EMPTY && fieldName != NULL) { - return RESULT_ERR_NOTFOUND; - } - return result; -} - -result_t Message::decodeLastData(ostringstream& output, OutputFormat outputFormat, - bool leadingSeparator, const char* fieldName, ssize_t fieldIndex) const { - size_t startPos = output.str().length(); - result_t result = m_data->read(m_lastMasterData, getIdLength(), output, outputFormat, -1, - leadingSeparator, fieldName, fieldIndex); +result_t Message::decodeLastData(bool leadingSeparator, const char* fieldName, + ssize_t fieldIndex, const OutputFormat outputFormat, ostream* output) const { + ssize_t startPos = output->tellp(); + result_t result = m_data->read(m_lastMasterData, getIdLength(), leadingSeparator, fieldName, fieldIndex, + outputFormat, -1, output); if (result < RESULT_OK) { return result; } bool empty = result == RESULT_EMPTY; - leadingSeparator |= output.str().length() > startPos; - result = m_data->read(m_lastSlaveData, 0, output, outputFormat, -1, leadingSeparator, fieldName, fieldIndex); + bool useLeadingSeparator = leadingSeparator || output->tellp() > startPos; + result = m_data->read(m_lastSlaveData, 0, useLeadingSeparator, fieldName, fieldIndex, outputFormat, -1, output); if (result < RESULT_OK) { return result; } @@ -786,13 +778,13 @@ result_t Message::decodeLastData(ostringstream& output, OutputFormat outputForma return result; } -result_t Message::decodeLastDataNumField(unsigned int& output, const char* fieldName, ssize_t fieldIndex) const { - result_t result = m_data->read(m_lastMasterData, getIdLength(), output, fieldName, fieldIndex); +result_t Message::decodeLastDataNumField(const char* fieldName, ssize_t fieldIndex, unsigned int* output) const { + result_t result = m_data->read(m_lastMasterData, getIdLength(), fieldName, fieldIndex, output); if (result < RESULT_OK) { return result; } if (result == RESULT_EMPTY) { - result = m_data->read(m_lastSlaveData, 0, output, fieldName, fieldIndex); + result = m_data->read(m_lastSlaveData, 0, fieldName, fieldIndex, output); } if (result < RESULT_OK) { return result; @@ -826,16 +818,16 @@ bool Message::isLessPollWeight(const Message* other) const { return false; } -void Message::dumpHeader(ostream& output, vector* fieldNames) { +void Message::dumpHeader(const vector* fieldNames, ostream* output) { bool first = true; if (fieldNames == NULL) { for (const auto& fieldName : defaultMessageFieldMap) { if (first) { first = false; } else { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } - output << fieldName; + *output << fieldName; } return; } @@ -843,13 +835,13 @@ void Message::dumpHeader(ostream& output, vector* fieldNames) { if (first) { first = false; } else { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } - output << fieldName; + *output << fieldName; } } -void Message::dump(ostream& output, vector* fieldNames, bool withConditions) const { +void Message::dump(const vector* fieldNames, bool withConditions, ostream* output) const { bool first = true; if (fieldNames == NULL) { for (const auto& fieldName : knownFieldNamesFull) { @@ -859,9 +851,9 @@ void Message::dump(ostream& output, vector* fieldNames, bool withConditi if (first) { first = false; } else { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } - dumpField(output, fieldName, withConditions); + dumpField(fieldName, withConditions, output); } return; } @@ -869,65 +861,65 @@ void Message::dump(ostream& output, vector* fieldNames, bool withConditi if (first) { first = false; } else { - output << FIELD_SEPARATOR; + *output << FIELD_SEPARATOR; } - dumpField(output, fieldName, withConditions); + dumpField(fieldName, withConditions, output); } } -void Message::dumpField(ostream& output, string fieldName, bool withConditions) const { +void Message::dumpField(const string& fieldName, bool withConditions, ostream* output) const { if (fieldName == "type") { if (withConditions && m_condition != NULL) { - m_condition->dump(output); + m_condition->dump(false, output); } if (m_isPassive) { - output << "u"; + *output << "u"; if (m_isWrite) { - output << "w"; + *output << "w"; } } else if (m_isWrite) { - output << "w"; + *output << "w"; } else { - output << "r"; + *output << "r"; if (m_pollPriority > 0) { - output << static_cast(m_pollPriority); + *output << static_cast(m_pollPriority); } } return; } if (fieldName == "circuit") { - dumpString(output, m_circuit, false); + dumpString(false, m_circuit, output); return; } if (fieldName == "level") { - dumpString(output, m_level, false); + dumpString(false, m_level, output); return; } if (fieldName == "name") { - dumpString(output, m_name, false); + dumpString(false, m_name, output); return; } if (fieldName == "qq") { if (m_srcAddress != SYN) { - output << hex << setw(2) << setfill('0') << static_cast(m_srcAddress); + *output << hex << setw(2) << setfill('0') << static_cast(m_srcAddress); } return; } if (fieldName == "zz") { if (m_dstAddress != SYN) { - output << hex << setw(2) << setfill('0') << static_cast(m_dstAddress); + *output << hex << setw(2) << setfill('0') << static_cast(m_dstAddress); } return; } if (fieldName == "pbsb") { for (auto it = m_id.begin(); it < m_id.begin()+2 && it < m_id.end(); it++) { - output << hex << setw(2) << setfill('0') << static_cast(*it); + *output << hex << setw(2) << setfill('0') << static_cast(*it); } return; } if (fieldName == "id") { for (auto it = m_id.begin()+2; it < m_id.end(); it++) { - output << hex << setw(2) << setfill('0') << static_cast(*it); + *output << hex << setw(2) << setfill('0') << static_cast(*it); } return; } @@ -935,44 +927,44 @@ void Message::dumpField(ostream& output, string fieldName, bool withConditions) m_data->dump(output); return; } - dumpAttribute(output, fieldName, false); + dumpAttribute(false, fieldName, output); } -void Message::decode(ostringstream& output, OutputFormat outputFormat, bool leadingSeparator, - vector* fields) const { +void Message::decode(bool leadingSeparator, const vector* fields, + OutputFormat outputFormat, ostringstream* output) const { if (leadingSeparator) { - output << ","; + *output << ","; } - output << "\n \"" << getName() << "\": {"; - output << "\n \"lastup\": " << setw(0) << dec << static_cast(getLastUpdateTime()); + *output << "\n \"" << getName() << "\": {" + << "\n \"lastup\": " << setw(0) << dec << static_cast(getLastUpdateTime()); if (getLastUpdateTime() != 0) { - output << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast(getDstAddress()) << "\""; - appendAttributes(output, OF_JSON | outputFormat); - size_t pos = (size_t) output.tellp(); - output << ",\n \"fields\": {"; - result_t dret = decodeLastData(output, outputFormat); + *output << ",\n \"zz\": \"" << setfill('0') << setw(2) << hex << static_cast(getDstAddress()) << "\""; + appendAttributes(OF_JSON | outputFormat, output); + size_t pos = (size_t)output->tellp(); + *output << ",\n \"fields\": {"; + result_t dret = decodeLastData(false, NULL, -1, outputFormat, output); if (dret == RESULT_OK) { - output << "\n }"; + *output << "\n }"; } else { - string prefix = output.str().substr(0, pos); - output.str(""); - output.clear(); // remove written fields - output << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\""; + string prefix = output->str().substr(0, pos); + output->str(""); + output->clear(); // remove written fields + *output << prefix << ",\n \"decodeerror\": \"" << getResultCode(dret) << "\""; } } - output << ",\n \"passive\": " << (isPassive() ? "true" : "false"); - output << ",\n \"write\": " << (isWrite() ? "true" : "false"); - output << "\n }"; + *output << ",\n \"passive\": " << (isPassive() ? "true" : "false") + << ",\n \"write\": " << (isWrite() ? "true" : "false") + << "\n }"; } -ChainedMessage::ChainedMessage(const string circuit, const string level, const string name, - const bool isWrite, const map& attributes, - const symbol_t srcAddress, const symbol_t dstAddress, - const vector id, - vector< vector > ids, vector lengths, - const DataField* data, const bool deleteData, - const size_t pollPriority, +ChainedMessage::ChainedMessage(const string& circuit, const string& level, const string& name, + bool isWrite, const map& attributes, + symbol_t srcAddress, symbol_t dstAddress, + const vector& id, + const vector< vector >& ids, const vector& lengths, + const DataField* data, bool deleteData, + size_t pollPriority, Condition* condition) : Message(circuit, level, name, isWrite, false, attributes, srcAddress, dstAddress, id, @@ -1003,7 +995,7 @@ ChainedMessage::~ChainedMessage() { free(m_lastSlaveUpdateTimes); } -Message* ChainedMessage::derive(const symbol_t dstAddress, const symbol_t srcAddress, const string circuit) const { +Message* ChainedMessage::derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const { ChainedMessage* result = new ChainedMessage(circuit.length() == 0 ? m_circuit : circuit, m_level, m_name, m_isWrite, m_attributes, srcAddress == SYN ? m_srcAddress : srcAddress, dstAddress, @@ -1046,7 +1038,7 @@ bool ChainedMessage::checkId(const MasterSymbolString& master, size_t* index) co return false; } -bool ChainedMessage::checkId(Message& other) const { +bool ChainedMessage::checkId(const Message& other) const { size_t idLen = getIdLength(); if (idLen != other.getIdLength() || other.getCount() == 1) { // only equal for chained messages return false; @@ -1076,14 +1068,14 @@ bool ChainedMessage::checkId(Message& other) const { return false; } -result_t ChainedMessage::prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, - size_t index) { +result_t ChainedMessage::prepareMasterPart(size_t index, char separator, istringstream* input, + MasterSymbolString* master) { size_t cnt = getCount(); if (index >= cnt) { return RESULT_ERR_NOTFOUND; } MasterSymbolString allData; - result_t result = m_data->write(input, allData, 0, separator); + result_t result = m_data->write(separator, 0, input, &allData, NULL); if (result != RESULT_OK) { return result; } @@ -1099,12 +1091,12 @@ result_t ChainedMessage::prepareMasterPart(MasterSymbolString& master, istringst return RESULT_ERR_INVALID_POS; } vector id = m_ids[index]; - master.push_back((symbol_t)(id.size()-2+addData)); // NN + master->push_back((symbol_t)(id.size()-2+addData)); // NN for (size_t i = 2; i < id.size(); i++) { - master.push_back(id[i]); + master->push_back(id[i]); } for (size_t i = 0; i < addData; i++) { - master.push_back(allData.dataAt(pos+i)); + master->push_back(allData.dataAt(pos+i)); } if (index == 0) { for (size_t i = 0; i < cnt; i++) { @@ -1114,20 +1106,20 @@ result_t ChainedMessage::prepareMasterPart(MasterSymbolString& master, istringst return result; } -result_t ChainedMessage::storeLastData(MasterSymbolString& master, SlaveSymbolString& slave) { +result_t ChainedMessage::storeLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) { // determine index from master ID size_t index = 0; if (checkId(master, &index)) { - result_t result = storeLastData(master, index); + result_t result = storeLastData(index, master); if (result >= RESULT_OK) { - result = storeLastData(slave, index); + result = storeLastData(index, slave); } return result; } return RESULT_ERR_INVALID_ARG; } -result_t ChainedMessage::storeLastData(MasterSymbolString& data, size_t index) { +result_t ChainedMessage::storeLastData(size_t index, const MasterSymbolString& data) { if (index >= m_ids.size()) { return RESULT_ERR_INVALID_ARG; } @@ -1143,11 +1135,11 @@ result_t ChainedMessage::storeLastData(MasterSymbolString& data, size_t index) { return combineLastParts(); } -result_t ChainedMessage::storeLastData(SlaveSymbolString& data, size_t index) { +result_t ChainedMessage::storeLastData(size_t index, const SlaveSymbolString& data) { if (index >= m_ids.size()) { return RESULT_ERR_INVALID_ARG; } - if (data != *m_lastSlaveDatas[index]) { + if (*m_lastSlaveDatas[index] != data) { *m_lastSlaveDatas[index] = data; } time(&m_lastSlaveUpdateTimes[index]); @@ -1203,16 +1195,16 @@ result_t ChainedMessage::combineLastParts() { if (!master.adjustHeader() || !slave.adjustHeader()) { return RESULT_ERR_INVALID_POS; } - result_t result = Message::storeLastData(master, 0); + result_t result = Message::storeLastData(0, master); if (result == RESULT_OK) { - result = Message::storeLastData(slave, 0); + result = Message::storeLastData(0, slave); } return result; } -void ChainedMessage::dumpField(ostream& output, string fieldName, bool withConditions) const { +void ChainedMessage::dumpField(const string& fieldName, bool withConditions, ostream* output) const { if (fieldName != "id") { - Message::dumpField(output, fieldName, withConditions); + Message::dumpField(fieldName, withConditions, output); return; } bool first = true; @@ -1222,11 +1214,11 @@ void ChainedMessage::dumpField(ostream& output, string fieldName, bool withCondi if (first) { first = false; } else { - output << VALUE_SEPARATOR; + *output << VALUE_SEPARATOR; } - output << hex << setw(2) << setfill('0') << static_cast(*it); + *output << hex << setw(2) << setfill('0') << static_cast(*it); } - output << LENGTH_SEPARATOR << dec << setw(0) << static_cast(m_lengths[index]); + *output << LENGTH_SEPARATOR << dec << setw(0) << static_cast(m_lengths[index]); } } @@ -1238,10 +1230,10 @@ void ChainedMessage::dumpField(ostream& output, string fieldName, bool withCondi * @param onlyAvailable true to include only available messages (default true), false to also include messages that * are currently not available (e.g. due to unresolved or false conditions). */ -Message* getFirstAvailable(const vector &messages, const MasterSymbolString* sameIdExtAs, +Message* getFirstAvailable(const vector& messages, const MasterSymbolString* sameIdExtAs, const bool onlyAvailable = true) { for (auto message : messages) { - if (sameIdExtAs && !message->checkId(*sameIdExtAs)) { + if (sameIdExtAs && !message->checkId(*sameIdExtAs, NULL)) { continue; } if (!onlyAvailable || message->isAvailable()) { @@ -1258,7 +1250,7 @@ Message* getFirstAvailable(const vector &messages, const MasterSymbolS * @param onlyAvailable true to include only available messages (default true), false to also include messages that * are currently not available (e.g. due to unresolved or false conditions). */ -Message* getFirstAvailable(const vector &messages, Message* sameIdExtAs = NULL, +Message* getFirstAvailable(const vector& messages, const Message* sameIdExtAs = NULL, const bool onlyAvailable = true) { for (auto message : messages) { if (sameIdExtAs && !message->checkId(*sameIdExtAs)) { @@ -1276,14 +1268,14 @@ Message* getFirstAvailable(const vector &messages, Message* sameIdExtA * @param valueList the input string to split. * @param values the output value list to append to. */ -result_t splitValues(string valueList, vector& values) { +result_t splitValues(const string& valueList, vector* values) { istringstream stream(valueList); string str; while (getline(stream, str, VALUE_SEPARATOR)) { if (str.length() > 0 && str[0] == '\'' && str[str.length()-1] == '\'') { str = str.substr(1, str.length()-2); } - values.push_back(str); + values->push_back(str); } return RESULT_OK; } @@ -1293,12 +1285,12 @@ result_t splitValues(string valueList, vector& values) { * @param valueList the input string to split. * @param valueRanges the output list of value ranges to append to (pairs of inclusive from-to values). */ -result_t splitValues(string valueList, vector& valueRanges) { +result_t splitValues(const string& valueList, vector* valueRanges) { istringstream stream(valueList); string str; result_t result; while (getline(stream, str, VALUE_SEPARATOR)) { - FileReader::trim(str); + FileReader::trim(&str); if (str.length() == 0) { return RESULT_ERR_INVALID_ARG; } @@ -1308,63 +1300,66 @@ result_t splitValues(string valueList, vector& valueRanges) { return RESULT_ERR_INVALID_ARG; } if (upto) { - valueRanges.push_back(0); + valueRanges->push_back(0); } bool inclusive = str[1] == '='; unsigned int val = parseInt(str.substr(inclusive?2:1).c_str(), 10, inclusive?0:1, - inclusive?UINT_MAX:(UINT_MAX-1), result); + inclusive?UINT_MAX:(UINT_MAX-1), &result); if (result != RESULT_OK) { return result; } - valueRanges.push_back(inclusive ? val : (val+(upto?-1:1))); + valueRanges->push_back(inclusive ? val : (val+(upto?-1:1))); if (!upto) { - valueRanges.push_back(UINT_MAX); + valueRanges->push_back(UINT_MAX); } } else { size_t pos = str.find('-'); if (pos != string::npos && pos > 0) { // range - unsigned int val = parseInt(str.substr(0, pos).c_str(), 10, 0, UINT_MAX, result); + unsigned int val = parseInt(str.substr(0, pos).c_str(), 10, 0, UINT_MAX, &result); if (result != RESULT_OK) { return result; } - valueRanges.push_back(val); + valueRanges->push_back(val); pos++; } else { // single value pos = 0; } - unsigned int val = parseInt(str.substr(pos).c_str(), 10, 0, UINT_MAX, result); + unsigned int val = parseInt(str.substr(pos).c_str(), 10, 0, UINT_MAX, &result); if (result != RESULT_OK) { return result; } - valueRanges.push_back(val); + valueRanges->push_back(val); if (pos == 0) { - valueRanges.push_back(val); // single value + valueRanges->push_back(val); // single value } } } return RESULT_OK; } -result_t Condition::create(const string condName, map row, map rowDefaults, - SimpleCondition*& returnValue) { +result_t Condition::create(const string& condName, const map& rowDefaults, + map* row, SimpleCondition** returnValue) { // type=name,circuit,name=messagename,[comment],qq=[fieldname],[ZZ],pbsb=values - string circuit = row["circuit"]; // circuit[#level] + string circuit = (*row)["circuit"]; // circuit[#level] string level; size_t pos = circuit.find('#'); if (pos != string::npos) { level = circuit.substr(pos+1); circuit.resize(pos); } - string name = row["name"]; // messagename - string field = row["qq"]; // fieldname - string zz = row["zz"]; // ZZ + string name = (*row)["name"]; // messagename + string field = (*row)["qq"]; // fieldname + string zz = (*row)["zz"]; // ZZ symbol_t dstAddress = SYN; result_t result = RESULT_OK; if (zz.empty()) { - zz = rowDefaults["zz"]; + auto it = rowDefaults.find("zz"); + if (it != rowDefaults.end()) { + zz = it->second; + } } if (zz.length() > 0) { - dstAddress = (symbol_t)parseInt(zz.c_str(), 16, 0, 0xff, result); + dstAddress = (symbol_t)parseInt(zz.c_str(), 16, 0, 0xff, &result); if (result != RESULT_OK) { return result; } @@ -1377,49 +1372,53 @@ result_t Condition::create(const string condName, map row, mapsecond; + } } - string valueList = row["pbsb"]; + string valueList = (*row)["pbsb"]; if (valueList.empty()) { - valueList = row["id"]; + valueList = (*row)["id"]; } if (valueList.empty()) { - returnValue = new SimpleCondition(condName, condName, circuit, level, name, dstAddress, field); + *returnValue = new SimpleCondition(condName, condName, circuit, level, name, dstAddress, field); return RESULT_OK; } if (valueList[0] == '\'') { // strings vector values; - result = splitValues(valueList, values); + result = splitValues(valueList, &values); if (result != RESULT_OK) { return result; } - returnValue = new SimpleStringCondition(condName, condName, circuit, level, name, dstAddress, field, values); + *returnValue = new SimpleStringCondition(condName, condName, circuit, level, name, dstAddress, field, values); return RESULT_OK; } // numbers vector valueRanges; - result = splitValues(valueList, valueRanges); + result = splitValues(valueList, &valueRanges); if (result != RESULT_OK) { return result; } - returnValue = new SimpleNumericCondition(condName, condName, circuit, level, name, dstAddress, field, valueRanges); + *returnValue = new SimpleNumericCondition(condName, condName, circuit, level, name, dstAddress, field, valueRanges); return RESULT_OK; } -SimpleCondition* SimpleCondition::derive(string valueList) const { +SimpleCondition* SimpleCondition::derive(const string& valueList) const { if (valueList.empty()) { return NULL; } - string name = m_condName+valueList; - if (valueList[0] == '=') { - valueList.erase(0, 1); + string useValueList = valueList; + string name = m_condName+useValueList; + if (useValueList[0] == '=') { + useValueList.erase(0, 1); } result_t result; - if (valueList[0] == '\'') { + if (useValueList[0] == '\'') { // strings vector values; - result = splitValues(valueList, values); + result = splitValues(useValueList, &values); if (result != RESULT_OK) { return NULL; } @@ -1430,25 +1429,25 @@ SimpleCondition* SimpleCondition::derive(string valueList) const { return NULL; } vector valueRanges; - result = splitValues(valueList, valueRanges); + result = splitValues(useValueList, &valueRanges); if (result != RESULT_OK) { return NULL; } return new SimpleNumericCondition(name, m_refName, m_circuit, m_level, m_name, m_dstAddress, m_field, valueRanges); } -void SimpleCondition::dump(ostream& output, bool matched) const { +void SimpleCondition::dump(bool matched, ostream* output) const { if (matched) { if (!m_isTrue) { return; } - output << "[" << m_refName; + *output << "[" << m_refName; if (m_hasValues) { - output << "=" << m_matchedValue; + *output << "=" << m_matchedValue; } - output << "]"; + *output << "]"; } else { - output << "[" << m_condName << "]"; + *output << "[" << m_condName << "]"; } } @@ -1457,32 +1456,32 @@ CombinedCondition* SimpleCondition::combineAnd(Condition* other) { return ret->combineAnd(this)->combineAnd(other); } -result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMessage, - void (*readMessageFunc)(Message* message)) { +result_t SimpleCondition::resolve(void (*readMessageFunc)(Message* message), MessageMap* messages, + ostringstream* errorMessage) { if (m_message == NULL) { Message* message; if (m_name.length() == 0) { message = messages->getScanMessage(m_dstAddress); - errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0') + *errorMessage << "scan condition " << nouppercase << setw(2) << hex << setfill('0') << static_cast(m_dstAddress); } else { message = messages->find(m_circuit, m_name, m_level, false); if (!message) { message = messages->find(m_circuit, m_name, m_level, false, true); } - errorMessage << "condition " << m_circuit << " " << m_name; + *errorMessage << "condition " << m_circuit << " " << m_name; } if (!message) { - errorMessage << ": message not found"; + *errorMessage << ": message not found"; return RESULT_ERR_NOTFOUND; } if (message->getDstAddress() == SYN) { if (message->isPassive()) { - errorMessage << ": invalid passive message"; + *errorMessage << ": invalid passive message"; return RESULT_ERR_INVALID_ARG; } if (m_dstAddress == SYN) { - errorMessage << ": destination address missing"; + *errorMessage << ": destination address missing"; return RESULT_ERR_INVALID_ADDR; } // clone the message with dedicated dstAddress if necessary @@ -1490,11 +1489,11 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess const vector* derived = messages->getByKey(key); if (derived == NULL) { message = message->derive(m_dstAddress, true); - messages->add(message); + messages->add(true, message); } else { Message* first = getFirstAvailable(*derived, message); if (first == NULL) { - errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName() + *errorMessage << ": conditional derived message " << message->getCircuit() << "." << message->getName() << " for " << hex << setw(2) << setfill('0') << static_cast(m_dstAddress) << " not found"; return RESULT_ERR_INVALID_ARG; } @@ -1504,14 +1503,14 @@ result_t SimpleCondition::resolve(MessageMap* messages, ostringstream& errorMess if (m_hasValues) { if (!message->hasField(m_field.length() > 0 ? m_field.c_str() : NULL, isNumeric())) { - errorMessage << (isNumeric() ? ": numeric field " : ": string field ") << m_field << " not found"; + *errorMessage << (isNumeric() ? ": numeric field " : ": string field ") << m_field << " not found"; return RESULT_ERR_NOTFOUND; } } m_message = message; message->setUsedByCondition(); if (m_name.length() > 0 && !message->isScanMessage()) { - messages->addPollMessage(message, true); + messages->addPollMessage(true, message); } } if (m_message->getLastUpdateTime() == 0 && readMessageFunc != NULL) { @@ -1536,9 +1535,9 @@ bool SimpleCondition::isTrue() { } -bool SimpleNumericCondition::checkValue(Message* message, string field) { +bool SimpleNumericCondition::checkValue(const Message* message, const string& field) { unsigned int value = 0; - result_t result = message->decodeLastDataNumField(value, field.length() == 0 ? NULL : field.c_str()); + result_t result = message->decodeLastDataNumField(field.length() == 0 ? NULL : field.c_str(), -1, &value); if (result == RESULT_OK) { for (size_t i = 0; i+1 < m_valueRanges.size(); i+=2) { if (m_valueRanges[i] <= value && value <= m_valueRanges[i+1]) { @@ -1553,9 +1552,9 @@ bool SimpleNumericCondition::checkValue(Message* message, string field) { } -bool SimpleStringCondition::checkValue(Message* message, string field) { +bool SimpleStringCondition::checkValue(const Message* message, const string& field) { ostringstream output; - result_t result = message->decodeLastData(output, 0, false, field.length() == 0 ? NULL : field.c_str()); + result_t result = message->decodeLastData(false, field.length() == 0 ? NULL : field.c_str(), -1, 0, &output); if (result == RESULT_OK) { string value = output.str(); for (size_t i = 0; i < m_values.size(); i++) { @@ -1569,19 +1568,19 @@ bool SimpleStringCondition::checkValue(Message* message, string field) { } -void CombinedCondition::dump(ostream& output, bool matched) const { +void CombinedCondition::dump(bool matched, ostream* output) const { for (const auto condition : m_conditions) { - condition->dump(output, matched); + condition->dump(matched, output); } } -result_t CombinedCondition::resolve(MessageMap* messages, ostringstream& errorMessage, - void (*readMessageFunc)(Message* message)) { +result_t CombinedCondition::resolve(void (*readMessageFunc)(Message* message), MessageMap* messages, + ostringstream* errorMessage) { for (const auto condition : m_conditions) { ostringstream dummy; - result_t ret = condition->resolve(messages, dummy, readMessageFunc); + result_t ret = condition->resolve(readMessageFunc, messages, &dummy); if (ret != RESULT_OK) { - errorMessage << dummy.str(); + *errorMessage << dummy.str(); return ret; } } @@ -1598,9 +1597,9 @@ bool CombinedCondition::isTrue() { } -result_t Instruction::create(const string& contextPath, const string type, - Condition* condition, map& row, map& defaults, - Instruction*& returnValue) { +result_t Instruction::create(const string& contextPath, const string& type, + Condition* condition, const map& row, const map& defaults, + Instruction** returnValue) { // type[,argument]* bool singleton = type == "load"; if (singleton || type == "include") { @@ -1614,15 +1613,19 @@ result_t Instruction::create(const string& contextPath, const string type, } else { path = contextPath.substr(0, pos+1); } - string arg = row["file"]; - row.erase("file"); - for (const auto entry : row) { // fallback to first field - if (!entry.second.empty()) { - arg = entry.second; - break; + auto it = row.find("file"); + string arg; + if (it == row.end()) { + for (const auto entry : row) { // fallback to first field + if (!entry.second.empty()) { + arg = entry.second; + break; + } } + } else { + arg = it->second; } - returnValue = new LoadInstruction(condition, singleton, defaults, path+arg); + *returnValue = new LoadInstruction(singleton, defaults, path+arg, condition); return RESULT_OK; } // unknown instruction @@ -1657,31 +1660,31 @@ string Instruction::getDestination() const { } -result_t LoadInstruction::execute(MessageMap* messages, ostringstream& log, Condition* condition) { +result_t LoadInstruction::execute(MessageMap* messages, ostringstream* log) { string errorDescription; - result_t result = messages->readFromFile(m_filename, errorDescription, false, &m_defaults); - if (log.tellp() > 0) { - log << ", "; + result_t result = messages->readFromFile(m_filename, false, &m_defaults, &errorDescription, NULL, NULL, NULL); + if (log->tellp() > 0) { + *log << ", "; } if (result != RESULT_OK) { - log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \"" + *log << "error " << (isSingleton() ? "loading \"" : "including \"") << m_filename << "\" for \"" << getDestination() << "\": " << getResultCode(result); if (!errorDescription.empty()) { - log << " " << errorDescription; + *log << " " << errorDescription; } return result; } - log << (isSingleton() ? "loaded \"" : "included \"") << m_filename << "\" for \"" << getDestination() << "\""; + *log << (isSingleton() ? "loaded \"" : "included \"") << m_filename << "\" for \"" << getDestination() << "\""; if (isSingleton() && !m_defaults["zz"].empty()) { result_t temp; - symbol_t address = (symbol_t)parseInt(m_defaults["zz"].c_str(), 16, 0, 0xff, temp); + symbol_t address = (symbol_t)parseInt(m_defaults["zz"].c_str(), 16, 0, 0xff, &temp); if (temp == RESULT_OK) { string comment; - if (condition) { + if (m_condition) { ostringstream out; - condition->dump(out, true); + m_condition->dump(true, &out); comment = out.str(); - log << " ("+comment+")"; + *log << " ("+comment+")"; } messages->addLoadedFile(address, m_filename, comment); } @@ -1692,14 +1695,14 @@ result_t LoadInstruction::execute(MessageMap* messages, ostringstream& log, Cond vector MessageMap::s_noFiles; -const string MessageMap::getRelativePath(const string filename) const { +const string MessageMap::getRelativePath(const string& filename) const { if (filename.length() >= m_configPath.length() && filename.substr(0, m_configPath.length()) == m_configPath) { return filename.substr(m_configPath.length()); } return filename; } -result_t MessageMap::add(Message* message, bool storeByName) { +result_t MessageMap::add(bool storeByName, Message* message) { uint64_t key = message->getKey(); bool conditional = message->isConditional(); if (!m_addAll) { @@ -1720,12 +1723,12 @@ result_t MessageMap::add(Message* message, bool storeByName) { if (storeByName) { bool isWrite = message->isWrite(); string circuit = message->getCircuit(); - FileReader::tolower(circuit); + FileReader::tolower(&circuit); if (circuit == "scan") { m_additionalScanMessages = true; } string name = message->getName(); - FileReader::tolower(name); + FileReader::tolower(&name); string suffix = FIELD_SEPARATOR + name + (isPassive ? "P" : (isWrite ? "W" : "R")); string nameKey = circuit + suffix; if (!m_addAll) { @@ -1761,7 +1764,7 @@ result_t MessageMap::add(Message* message, bool storeByName) { if (isPassive) { m_passiveMessageCount++; } - addPollMessage(message); + addPollMessage(false, message); } size_t idLength = message->getIdLength(); if (message->getDstAddress() == BROADCAST && idLength > m_maxBroadcastIdLength) { @@ -1774,35 +1777,35 @@ result_t MessageMap::add(Message* message, bool storeByName) { return RESULT_OK; } -result_t MessageMap::getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const { +result_t MessageMap::getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const { // type (r[1-9];w;u),circuit,name,[comment],[QQ],ZZ,PBSB,[ID],field1,part (m/s),datatypes/templates,divider/values, // unit,comment // minimum: type,name,PBSB,field,datatype - if (row.empty()) { + if (row->empty()) { for (const auto& col : defaultMessageFieldMap) { - row.push_back(col); + row->push_back(col); } return RESULT_OK; } bool inDataFields = false; map seen; - for (size_t col = 0; col < row.size(); col++) { - string &name = row[col]; + for (size_t col = 0; col < row->size(); col++) { + string &name = (*row)[col]; string lowerName = name; - tolower(lowerName); - trim(lowerName); + tolower(&lowerName); + trim(&lowerName); if (lowerName.empty()) { - errorDescription = "missing name in column " + AttributedItem::formatInt(col); + *errorDescription = "missing name in column " + AttributedItem::formatInt(col); return RESULT_ERR_INVALID_ARG; } bool supportsLang = false, toDataFields = false; string useName; if (inDataFields) { - useName = getDataFieldName(lowerName, supportsLang); + useName = getDataFieldName(lowerName, &supportsLang); } else { - useName = getMessageFieldName(lowerName, supportsLang); + useName = getMessageFieldName(lowerName, &supportsLang); if (useName.empty()) { - useName = getDataFieldName(lowerName, supportsLang); + useName = getDataFieldName(lowerName, &supportsLang); toDataFields = !useName.empty(); } } @@ -1822,7 +1825,7 @@ result_t MessageMap::getFieldMap(vector& row, string& errorDescription, continue; } // replace previous - row[previous->second] = SKIP_COLUMN; + (*row)[previous->second] = SKIP_COLUMN; seen.erase(useName); previous = seen.end(); } @@ -1835,7 +1838,7 @@ result_t MessageMap::getFieldMap(vector& row, string& errorDescription, if (inDataFields) { if (!unknown && previous != seen.end()) { if (seen.find("name") == seen.end() || seen.find("type") == seen.end()) { - errorDescription = "missing field name/type as of already seen "+useName; + *errorDescription = "missing field name/type as of already seen "+useName; return RESULT_ERR_EOF; // require at least name and type } seen.clear(); @@ -1846,14 +1849,14 @@ result_t MessageMap::getFieldMap(vector& row, string& errorDescription, } else {*/ if (toDataFields) { if (seen.find("type") == seen.end() || seen.find("name") == seen.end() || seen.find("pbsb") == seen.end()) { - errorDescription = "missing message name/type/pbsb"; + *errorDescription = "missing message name/type/pbsb"; return RESULT_ERR_EOF; // require at least type, name, and pbsb } inDataFields = true; seen.clear(); } if (!inDataFields && seen.find(useName) != seen.end()) { - errorDescription = "duplicate message " + useName; + *errorDescription = "duplicate message " + useName; return RESULT_ERR_INVALID_ARG; } } @@ -1866,21 +1869,20 @@ result_t MessageMap::getFieldMap(vector& row, string& errorDescription, } if (inDataFields) { if (seen.find("name") == seen.end() || seen.find("type") == seen.end()) { - errorDescription = "missing field name/type"; + *errorDescription = "missing field name/type"; return RESULT_ERR_EOF; // require at least name and type } } else if (seen.find("type") == seen.end() || seen.find("name") == seen.end() || seen.find("pbsb") == seen.end()) { - errorDescription = "missing message name/type/pbsb"; + *errorDescription = "missing message name/type/pbsb"; return RESULT_ERR_EOF; // require at least type, name, and pbsb } return RESULT_OK; } -result_t MessageMap::addDefaultFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) { +result_t MessageMap::addDefaultFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) { // check for condition in defaults - string type = row["type"]; - row.erase("type"); + string type = AttributedItem::pluck("type", row); const auto& mainDefaults = getDefaults().find(""); map defaults; if (mainDefaults != getDefaults().end()) { @@ -1890,19 +1892,19 @@ result_t MessageMap::addDefaultFromFile(map& row, vector< map& row, vector< map& row, vector< map > subDefaults = subRows; // ensure to have a copy + getDefaults()[type] = defaults; // without suffix + vector< map > subDefaults = *subRows; // ensure to have a copy getSubDefaults()[type] = subDefaults; return RESULT_OK; } -result_t MessageMap::readConditions(string& types, const string filename, string& errorDescription, - Condition*& condition) { +result_t MessageMap::readConditions(const string& filename, string* types, string* errorDescription, + Condition** condition) { size_t pos; - if (types.length() > 0 && types[0] == '[' && (pos=types.find_last_of(']')) != string::npos) { + if (types->length() > 0 && types->at(0) == '[' && (pos=types->find_last_of(']')) != string::npos) { // check if combined or simple condition is already known - const string combinedkey = filename+":"+types.substr(1, pos-1); + const string combinedkey = filename+":"+types->substr(1, pos-1); auto it = m_conditions.find(combinedkey); if (it != m_conditions.end()) { - condition = it->second; - types = types.substr(pos+1); + *condition = it->second; + types->erase(0, pos+1); } else { bool store = false; - condition = NULL; - while ((pos=types.find(']')) != string::npos) { + *condition = NULL; + while ((pos=types->find(']')) != string::npos) { // simple condition - string key = filename+":"+types.substr(1, pos-1); + string key = filename+":"+types->substr(1, pos-1); it = m_conditions.find(key); Condition* add = NULL; if (it == m_conditions.end()) { @@ -1984,7 +1983,7 @@ result_t MessageMap::readConditions(string& types, const string filename, string // derive from another condition add = it->second->derive(key.substr(pos)); if (add == NULL) { - errorDescription = "derive condition with values "+key.substr(pos)+" failed"; + *errorDescription = "derive condition with values "+key.substr(pos)+" failed"; return RESULT_ERR_INVALID_ARG; } m_conditions[key] = add; // store derived condition @@ -1992,32 +1991,32 @@ result_t MessageMap::readConditions(string& types, const string filename, string } if (add == NULL) { // shared condition not available - errorDescription = "condition "+types.substr(1, pos-1)+" not defined"; + *errorDescription = "condition "+types->substr(1, pos-1)+" not defined"; return RESULT_ERR_NOTFOUND; } } else { add = it->second; } - if (condition) { - condition = condition->combineAnd(add); + if (*condition) { + *condition = (*condition)->combineAnd(add); store = true; } else { - condition = add; + *condition = add; } - types = types.substr(pos+1); - if (types.empty() || types[0] != '[') { + types->erase(0, pos+1); + if (types->empty() || types->at(0) != '[') { break; } } if (store) { - m_conditions[combinedkey] = condition; // store combined condition + m_conditions[combinedkey] = *condition; // store combined condition } } } return RESULT_OK; } -bool MessageMap::extractDefaultsFromFilename(string filename, map& defaults, +bool MessageMap::extractDefaultsFromFilename(const string& filename, map* defaults, symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const { string ident, circuit, suffix; unsigned int sw = UINT_MAX, hw = UINT_MAX; @@ -2031,7 +2030,7 @@ bool MessageMap::extractDefaultsFromFilename(string filename, map 1) { pos = remain.rfind(".SW"); // check for ".SWxxxx." if (pos != string::npos && remain.find(".", pos+1) == pos+7) { - sw = parseInt(remain.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL); + sw = parseInt(remain.substr(pos+3, 4).c_str(), 10, 0, 9999, &result); if (result != RESULT_OK) { return false; // invalid "SWxxxx" } @@ -2055,7 +2054,7 @@ bool MessageMap::extractDefaultsFromFilename(string filename, map 1) { pos = remain.rfind(".HW"); // check for ".HWxxxx." if (pos != string::npos && remain.find(".", pos+1) == pos+7) { - hw = parseInt(remain.substr(pos+3, 4).c_str(), 10, 0, 9999, result, NULL); + hw = parseInt(remain.substr(pos+3, 4).c_str(), 10, 0, 9999, &result); if (result != RESULT_OK) { return false; // invalid "HWxxxx" } @@ -2083,15 +2082,15 @@ bool MessageMap::extractDefaultsFromFilename(string filename, map* defaults, size_t* hash, size_t* size, time_t* time) { +result_t MessageMap::readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time) { size_t localHash, localSize; time_t localTime; if (!hash) { @@ -2103,7 +2102,7 @@ result_t MessageMap::readFromFile(const string filename, string& errorDescriptio if (!time) { time = &localTime; } - result_t result = MappedFileReader::readFromFile(filename, errorDescription, verbose, defaults, hash, size, time); + result_t result = MappedFileReader::readFromFile(filename, verbose, defaults, errorDescription, hash, size, time); if (result == RESULT_OK) { const string file = getRelativePath(filename); m_loadedFileInfos[file].m_hash = *hash; @@ -2113,26 +2112,25 @@ result_t MessageMap::readFromFile(const string filename, string& errorDescriptio return result; } -result_t MessageMap::addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) { +result_t MessageMap::addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) { Condition* condition = NULL; - string types = row["type"]; - result_t result = readConditions(types, filename, errorDescription, condition); + string types = AttributedItem::pluck("type", row); + result_t result = readConditions(filename, &types, errorDescription, &condition); if (result != RESULT_OK) { return result; } if (!types.empty() && types[0] == '!') { // instruction - if (!subRows.empty()) { - errorDescription = "invalid instruction"; + if (!subRows->empty()) { + *errorDescription = "invalid instruction"; return RESULT_ERR_INVALID_ARG; } types = types.substr(1); Instruction* instruction = NULL; - row.erase("type"); - result_t result = Instruction::create(filename, types, condition, row, getDefaults()[""], instruction); + result_t result = Instruction::create(filename, types, condition, *row, getDefaults()[""], &instruction); if (instruction == NULL || result != RESULT_OK) { - errorDescription = "invalid instruction"; + *errorDescription = "invalid instruction"; return result; } auto it = m_instructions.find(filename); @@ -2146,27 +2144,34 @@ result_t MessageMap::addFromFile(map& row, vector< map messages; while (getline(stream, type, VALUE_SEPARATOR)) { - FileReader::trim(type); + FileReader::trim(&type); messages.clear(); - row["type"] = type; - result = Message::create(row, subRows, getDefaults(), getSubDefaults(), errorDescription, condition, filename, - templates, messages); + if (hasMulti) { + map newRow = *row; // don't let Message::create() consume the row and subRows + vector< map > newSubRows = *subRows; + result = Message::create(filename, templates, getDefaults(), getSubDefaults(), type, condition, + &newRow, &newSubRows, errorDescription, &messages); + } else { + result = Message::create(filename, templates, getDefaults(), getSubDefaults(), type, condition, + row, subRows, errorDescription, &messages); + } for (const auto message : messages) { if (result == RESULT_OK) { - result = add(message); + result = add(true, message); if (result == RESULT_ERR_DUPLICATE_NAME) { - errorDescription = "invalid name"; + *errorDescription = "invalid name"; } else if (result == RESULT_ERR_DUPLICATE) { - errorDescription = "duplicate ID"; + *errorDescription = "duplicate ID"; } } if (result != RESULT_OK) { @@ -2180,7 +2185,7 @@ result_t MessageMap::addFromFile(map& row, vector< mapfront(); } Message* message = m_scanMessage->derive(dstAddress, true); - add(message); + add(true, message); return message; } -result_t MessageMap::resolveConditions(string& errorDescription, bool verbose) { +result_t MessageMap::resolveConditions(bool verbose, string* errorDescription) { result_t overallResult = RESULT_OK; for (const auto& it : m_conditions) { Condition* condition = it.second; - result_t result = resolveCondition(condition, errorDescription); + result_t result = resolveCondition(NULL, condition, errorDescription); if (result != RESULT_OK) { overallResult = result; } @@ -2212,23 +2217,23 @@ result_t MessageMap::resolveConditions(string& errorDescription, bool verbose) { return overallResult; } -result_t MessageMap::resolveCondition(Condition* condition, string& errorDescription, - void (*readMessageFunc)(Message* message)) { +result_t MessageMap::resolveCondition(void (*readMessageFunc)(Message* message), Condition* condition, + string* errorDescription) { ostringstream error; - result_t result = condition->resolve(this, error, readMessageFunc); + result_t result = condition->resolve(readMessageFunc, this, &error); if (result != RESULT_OK) { string errorMessage = error.str(); if (errorMessage.length() > 0) { - if (!errorDescription.empty()) { - errorDescription += ", "; + if (!errorDescription->empty()) { + *errorDescription += ", "; } - errorDescription += errorMessage; + *errorDescription += errorMessage; } } return result; } -result_t MessageMap::executeInstructions(ostringstream& log, void (*readMessageFunc)(Message* message)) { +result_t MessageMap::executeInstructions(void (*readMessageFunc)(Message* message), ostringstream* log) { result_t overallResult = RESULT_OK; vector remove; for (auto& it : m_instructions) { @@ -2244,14 +2249,14 @@ result_t MessageMap::executeInstructions(ostringstream& log, void (*readMessageF bool execute = condition == NULL; if (!execute) { string errorDescription; - result_t result = resolveCondition(condition, errorDescription, - instruction->isSingleton()?readMessageFunc:NULL); + result_t result = resolveCondition(instruction->isSingleton()?readMessageFunc:NULL, condition, + &errorDescription); if (result != RESULT_OK) { overallResult = result; - log << "error resolving condition for \"" << instruction->getDestination() << "\": " + *log << "error resolving condition for \"" << instruction->getDestination() << "\": " << getResultCode(result); if (!errorDescription.empty()) { - log << " " << errorDescription; + *log << " " << errorDescription; } } else if (condition->isTrue()) { execute = true; @@ -2261,7 +2266,7 @@ result_t MessageMap::executeInstructions(ostringstream& log, void (*readMessageF if (instruction->isSingleton()) { removeSingletons = true; } - result_t result = instruction->execute(this, log, condition); + result_t result = instruction->execute(this, log); if (result != RESULT_OK) { overallResult = result; } @@ -2293,7 +2298,7 @@ result_t MessageMap::executeInstructions(ostringstream& log, void (*readMessageF return overallResult; } -void MessageMap::addLoadedFile(const symbol_t address, const string filename, string const comment) { +void MessageMap::addLoadedFile(symbol_t address, const string& filename, const string& comment) { if (!filename.empty()) { vector& files = m_loadedFiles[address]; const string file = getRelativePath(filename); @@ -2304,7 +2309,7 @@ void MessageMap::addLoadedFile(const symbol_t address, const string filename, st } } -const vector& MessageMap::getLoadedFiles(const symbol_t address) const { +const vector& MessageMap::getLoadedFiles(symbol_t address) const { const auto it = m_loadedFiles.find(address); if (it != m_loadedFiles.end()) { return it->second; @@ -2320,16 +2325,16 @@ vector MessageMap::getLoadedFiles() const { return ret; } -bool MessageMap::getLoadedFileInfo(const string filename, string& comment, size_t* hash, size_t* size, time_t* time) - const { +bool MessageMap::getLoadedFileInfo(const string& filename, string* comment, size_t* hash, size_t* size, + time_t* time) const { const auto it = m_loadedFileInfos.find(filename); if (it == m_loadedFileInfos.end()) { - comment = ""; + *comment = ""; hash = size = 0; time = 0; return false; } - comment = it->second.m_comment; + *comment = it->second.m_comment; if (hash) { *hash = it->second.m_hash; } @@ -2342,7 +2347,7 @@ bool MessageMap::getLoadedFileInfo(const string filename, string& comment, size_ return true; } -const vector* MessageMap::getByKey(const uint64_t key) const { +const vector* MessageMap::getByKey(uint64_t key) const { const auto it = m_messagesByKey.find(key); if (it != m_messagesByKey.end()) { return &it->second; @@ -2350,12 +2355,12 @@ const vector* MessageMap::getByKey(const uint64_t key) const { return NULL; } -Message* MessageMap::find(const string& circuit, const string& name, const string& levels, const bool isWrite, - const bool isPassive) const { +Message* MessageMap::find(const string& circuit, const string& name, const string& levels, bool isWrite, + bool isPassive) const { string lcircuit = circuit; - FileReader::tolower(lcircuit); + FileReader::tolower(&lcircuit); string lname = name; - FileReader::tolower(lname); + FileReader::tolower(&lname); string suffix = FIELD_SEPARATOR + lname + (isPassive ? "P" : (isWrite ? "W" : "R")); for (int i = 0; i < 2; i++) { string nameKey; @@ -2378,14 +2383,14 @@ Message* MessageMap::find(const string& circuit, const string& name, const strin } deque MessageMap::findAll(const string& circuit, const string& name, const string& levels, - const bool completeMatch, const bool withRead, const bool withWrite, const bool withPassive, - const bool includeEmptyLevel, const bool onlyAvailable, - const time_t since, const time_t until) const { + bool completeMatch, bool withRead, bool withWrite, bool withPassive, + bool includeEmptyLevel, bool onlyAvailable, + time_t since, time_t until) const { deque ret; string lcircuit = circuit; - FileReader::tolower(lcircuit); + FileReader::tolower(&lcircuit); string lname = name; - FileReader::tolower(lname); + FileReader::tolower(&lname); bool checkCircuit = lcircuit.length() > 0; bool checkLevel = levels != "*"; bool checkName = lname.length() > 0; @@ -2399,14 +2404,14 @@ deque MessageMap::findAll(const string& circuit, const string& name, c } if (checkCircuit) { string check = message->getCircuit(); - FileReader::tolower(check); + FileReader::tolower(&check); if (completeMatch ? (check != lcircuit) : (check.find(lcircuit) == check.npos)) { continue; } } if (checkName) { string check = message->getName(); - FileReader::tolower(check); + FileReader::tolower(&check); if (completeMatch ? (check != lname) : (check.find(lname) == check.npos)) { continue; } @@ -2443,8 +2448,8 @@ deque MessageMap::findAll(const string& circuit, const string& name, c return ret; } -Message* MessageMap::find(const MasterSymbolString& master, const bool anyDestination, - const bool withRead, const bool withWrite, const bool withPassive, const bool onlyAvailable) const { +Message* MessageMap::find(const MasterSymbolString& master, bool anyDestination, + bool withRead, bool withWrite, bool withPassive, bool onlyAvailable) const { if (anyDestination && master.size() >= 5 && master[4] == 0 && master[2] == 0x07 && master[3] == 0x04) { return m_scanMessage; } @@ -2531,24 +2536,24 @@ void MessageMap::invalidateCache(Message* message) { } } -void MessageMap::addPollMessage(Message* message, bool toFront) { +void MessageMap::addPollMessage(bool toFront, Message* message) { if (message != NULL && message->getPollPriority() > 0) { message->m_lastPollTime = toFront ? 0 : m_pollMessages.size(); m_pollMessages.push(message); } } -bool MessageMap::decodeCircuit(const string circuit, ostringstream& output, OutputFormat outputFormat) const { +bool MessageMap::decodeCircuit(const string& circuit, OutputFormat outputFormat, ostringstream* output) const { const auto it = m_circuitData.find(circuit); if (it == m_circuitData.end()) { return false; } if (outputFormat & OF_JSON) { - output << "\"name\": \"" << it->second->getName() << "\""; + *output << "\"name\": \"" << it->second->getName() << "\""; } else { - output << it->second->getName() << "="; + *output << it->second->getName() << "="; } - return it->second->appendAttributes(output, outputFormat); + return it->second->appendAttributes(outputFormat, output); } void MessageMap::clear() { @@ -2633,10 +2638,10 @@ Message* MessageMap::getNextPoll() { return ret; } -void MessageMap::dump(ostream& output, bool withConditions) const { +void MessageMap::dump(bool withConditions, ostream* output) const { bool first = true; - Message::dumpHeader(output, NULL); - output << endl; + Message::dumpHeader(NULL, output); + *output << endl; for (const auto it : m_messagesByName) { if (it.first[0] == '-') { // skip instances stored multiple times (key starting with "-") continue; @@ -2649,9 +2654,9 @@ void MessageMap::dump(ostream& output, bool withConditions) const { if (first) { first = false; } else { - output << endl; + *output << endl; } - message->dump(output, NULL, withConditions); + message->dump(NULL, withConditions, output); } } else { Message* message = getFirstAvailable(it.second); @@ -2661,13 +2666,13 @@ void MessageMap::dump(ostream& output, bool withConditions) const { if (first) { first = false; } else { - output << endl; + *output << endl; } - message->dump(output, NULL, withConditions); + message->dump(NULL, withConditions, output); } } if (!first) { - output << endl; + *output << endl; } } diff --git a/src/lib/ebus/message.h b/src/lib/ebus/message.h index 8d44faf1..23bc2c94 100644 --- a/src/lib/ebus/message.h +++ b/src/lib/ebus/message.h @@ -92,12 +92,12 @@ class Message : public AttributedItem { * @param pollPriority the priority for polling, or 0 for no polling at all. * @param condition the @a Condition for this message, or NULL. */ - Message(const string circuit, const string level, const string name, - const bool isWrite, const bool isPassive, const map& attributes, - const symbol_t srcAddress, const symbol_t dstAddress, - const vector id, - const DataField* data, const bool deleteData, - const size_t pollPriority = 0, + Message(const string& circuit, const string& level, const string& name, + bool isWrite, bool isPassive, const map& attributes, + symbol_t srcAddress, symbol_t dstAddress, + const vector& id, + const DataField* data, bool deleteData, + size_t pollPriority = 0, Condition* condition = NULL); @@ -113,9 +113,9 @@ class Message : public AttributedItem { * @param data the @a DataField for encoding/decoding the message. * @param deleteData whether to delete the @a DataField during destruction. */ - Message(const string circuit, const string level, const string name, - const symbol_t pb, const symbol_t sb, - const bool broadcast, const DataField* data, const bool deleteData); + Message(const string& circuit, const string& level, const string& name, + symbol_t pb, symbol_t sb, + bool broadcast, const DataField* data, bool deleteData); public: @@ -134,9 +134,8 @@ class Message : public AttributedItem { * @param dstAddress the destination address, or @a SYN for any (set later). * @return the key for the ID. */ - static uint64_t createKey(const vector id, - const bool isWrite, const bool isPassive, - const symbol_t srcAddress, const symbol_t dstAddress); + static uint64_t createKey(const vector& id, bool isWrite, bool isPassive, symbol_t srcAddress, + symbol_t dstAddress); /** * 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. * @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. @@ -169,26 +168,29 @@ class Message : public AttributedItem { * @param id the vector to which to add the parsed values. * @return @a RESULT_OK on success, or an error code. */ - static result_t parseId(string input, vector& id); + static result_t parseId(const string& input, vector* id); /** * 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 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. * @return @a RESULT_OK on success, or an error code. * Note: the caller needs to free the created instances. */ - static result_t create(map row, vector< map > subRows, - map >& rowDefaults, map > >& subRowDefaults, - string& errorDescription, Condition* condition, const string filename, DataFieldTemplates* templates, - vector& messages); + static result_t create(const string& filename, const DataFieldTemplates* templates, + const map >& rowDefaults, + const map > >& subRowDefaults, + const string& typeStr, Condition* condition, + map* row, vector< map >* subRows, + string* errorDescription, vector* messages); /** * Create a new scan @a Message instance. @@ -200,11 +202,11 @@ class Message : public AttributedItem { /** * Extract the known field names from the input string. * @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 fields the vector to update with the extracted normalized field names with. * @return true when all fields are valid. */ - static bool extractFieldNames(string str, vector& fields, bool checkAbbreviated = true); + static bool extractFieldNames(const string& str, bool checkAbbreviated, vector* fields); /** * 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. * @return the derived @a Message instance. */ - virtual Message* derive(const symbol_t dstAddress, const symbol_t srcAddress = SYN, - const string circuit = "") const; + virtual Message* derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const; /** * 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. * @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. @@ -254,7 +255,7 @@ class Message : public AttributedItem { * level to check. * @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); } @@ -264,14 +265,14 @@ class Message : public AttributedItem { * @param checkLevels the access levels to check against, separated by semicolon. * @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. * @param fieldIndex the index of the field. * @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. @@ -329,14 +330,14 @@ class Message : public AttributedItem { * @param index the variable in which to store the message part index, or NULL to ignore. * @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. * @param other the other @a Message to check against. * @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. @@ -349,7 +350,7 @@ class Message : public AttributedItem { * @param dstAddress the destination address for the derivation. * @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. @@ -362,7 +363,7 @@ class Message : public AttributedItem { * @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. */ - bool setPollPriority(size_t priority); + bool setPollPriority(const size_t priority); /** * 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. - * @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 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. */ - result_t prepareMaster(const symbol_t srcAddress, MasterSymbolString& master, - istringstream& input, char separator = UI_FIELD_SEPARATOR, - const symbol_t dstAddress = SYN, size_t index = 0); + result_t prepareMaster(size_t index, symbol_t srcAddress, symbol_t dstAddress, + char separator, istringstream* input, MasterSymbolString* master); protected: /** * 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 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. */ - virtual result_t prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, - size_t index); + virtual result_t prepareMasterPart(size_t index, char separator, istringstream* input, MasterSymbolString* master); public: @@ -429,7 +428,7 @@ class Message : public AttributedItem { * @param slave the @a SlaveSymbolString for writing symbols to. * @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. @@ -437,68 +436,57 @@ class Message : public AttributedItem { * @param slave the last seen @a SlaveSymbolString. * @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. - * @param data the last @a MasterSymbolString. * @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. */ - virtual result_t storeLastData(MasterSymbolString& data, size_t index); + virtual result_t storeLastData(size_t index, const MasterSymbolString& data); /** * Store last seen slave data. - * @param data the last seen @a SlaveSymbolString. * @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. */ - 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. - * @param output the @a ostringstream to append the formatted value to. - * @param outputFormat the @a OutputFormat options to use. + * Decode the value from the last stored master or slave data. + * @param master true for deocding the master data, false for slave. * @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 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. */ - virtual result_t decodeLastMasterData(ostringstream& output, OutputFormat outputFormat = 0, - bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const; + virtual result_t decodeLastData(bool master, bool leadingSeparator, const char* fieldName, + ssize_t fieldIndex, OutputFormat outputFormat, ostream* output) const; /** - * Decode the value from the last stored slave data. - * @param output the @a ostringstream to append the formatted value to. - * @param outputFormat the @a OutputFormat options to use. + * Decode the value from the last stored master and slave data. * @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 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 leadingSeparator whether to prepend a separator before the formatted value. - * @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 output the @a ostream to append the formatted value to. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t decodeLastData(ostringstream& output, OutputFormat outputFormat = 0, - bool leadingSeparator = false, const char* fieldName = NULL, ssize_t fieldIndex = -1) const; + virtual result_t decodeLastData(bool leadingSeparator, const char* fieldName, + ssize_t fieldIndex, OutputFormat outputFormat, ostream* output) const; /** * 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 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. */ - 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. @@ -539,36 +527,36 @@ class Message : public AttributedItem { /** * 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 output the @a ostream to append the formatted value to. */ - static void dumpHeader(ostream& output, vector* fieldNames = NULL); + static void dumpHeader(const vector* fieldNames, ostream* output); /** * 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 withConditions whether to include the optional conditions prefix. + * @param output the @a ostream to append the formatted value to. */ - void dump(ostream& output, vector* fieldNames = NULL, bool withConditions = false) const; + void dump(const vector* fieldNames, bool withConditions, ostream* output) const; /** * 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 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. - * @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 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, - vector* fields = NULL) const; + virtual void decode(bool leadingSeparator, const vector* fields, + OutputFormat outputFormat, ostringstream* output) const; protected: /** 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 condition the @a Condition for this message, or NULL. */ - ChainedMessage(const string circuit, const string level, const string name, - const bool isWrite, const map& attributes, - const symbol_t srcAddress, const symbol_t dstAddress, - const vector id, - vector< vector > ids, vector lengths, - const DataField* data, const bool deleteData, - const size_t pollPriority, + ChainedMessage(const string& circuit, const string& level, const string& name, + bool isWrite, const map& attributes, + symbol_t srcAddress, symbol_t dstAddress, + const vector& id, + const vector< vector >& ids, const vector& lengths, + const DataField* data, bool deleteData, + size_t pollPriority = 0, Condition* condition = NULL); virtual ~ChainedMessage(); // @copydoc - Message* derive(const symbol_t dstAddress, const symbol_t srcAddress = SYN, - const string circuit = "") const override; + Message* derive(symbol_t dstAddress, symbol_t srcAddress, const string& circuit) const override; // @copydoc size_t getIdLength() const override { return m_ids[0].size() - 2; } // @copydoc - bool checkId(const MasterSymbolString& master, size_t* index = NULL) const override; + bool checkId(const MasterSymbolString& master, size_t* index) const override; // @copydoc - bool checkId(Message& other) const override; + bool checkId(const Message& other) const override; // @copydoc size_t getCount() const override { return m_ids.size(); } @@ -706,19 +693,19 @@ class ChainedMessage : public Message { protected: // @copydoc - result_t prepareMasterPart(MasterSymbolString& master, istringstream& input, char separator, - size_t index) override; + result_t prepareMasterPart(size_t index, const char separator, istringstream* input, + MasterSymbolString* master) override; public: // @copydoc - result_t storeLastData(MasterSymbolString& master, SlaveSymbolString& slave) override; + result_t storeLastData(const MasterSymbolString& master, const SlaveSymbolString& slave) override; // @copydoc - result_t storeLastData(MasterSymbolString& data, size_t index) override; + result_t storeLastData(size_t index, const MasterSymbolString& data) override; // @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. @@ -728,7 +715,7 @@ class ChainedMessage : public Message { protected: // @copydoc - void dumpField(ostream& output, string fieldName, bool withConditions = false) const override; + void dumpField(const string& fieldName, bool withConditions, ostream* output) const override; private: @@ -810,27 +797,27 @@ class Condition { /** * Factory method for creating a new instance. * @param condName the name of the condition. - * @param row the mapped definition row. * @param rowDefaults the mapped definition defaults. + * @param row the mapped definition row. * @param returnValue the variable in which to store the created instance. * @return @a RESULT_OK on success, or an error code. */ - static result_t create(const string condName, map row, map rowDefaults, - SimpleCondition*& returnValue); + static result_t create(const string& condName, const map& rowDefaults, + map* row, SimpleCondition** returnValue); /** * Derive a new @a SimpleCondition from this condition. * @param valueList the @a string with the new list of values. * @return the derived @a SimpleCondition instance, or NULL if the value list is invalid. */ - virtual SimpleCondition* derive(string valueList) const { return NULL; } + virtual SimpleCondition* derive(const string& valueList) const { return NULL; } /** * 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 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. @@ -842,12 +829,12 @@ class Condition { /** * Resolve the referred @a Message instance(s) and field index(es). * @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 errorMessage a @a ostringstream to which to add optional error messages. * @return @a RESULT_OK on success, or an error code. */ - virtual result_t resolve(MessageMap* messages, ostringstream& errorMessage, - void (*readMessageFunc)(Message* message) = NULL) = 0; + virtual result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages, + ostringstream* errorMessage) = 0; /** * Check and return whether this condition is fulfilled. @@ -882,8 +869,8 @@ class SimpleCondition : public Condition { * @param field the field name. * @param hasValues whether a value has to be checked against. */ - 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) + SimpleCondition(const string& condName, const string& refName, const string& circuit, const string& level, + const string& name, symbol_t dstAddress, const string& field, bool hasValues = false) : Condition(), 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) { } @@ -894,17 +881,17 @@ class SimpleCondition : public Condition { virtual ~SimpleCondition() {} // @copydoc - SimpleCondition* derive(string valueList) const override; + SimpleCondition* derive(const string& valueList) const override; // @copydoc - void dump(ostream& output, bool matched = false) const override; + void dump(bool matched, ostream* output) const override; // @copydoc CombinedCondition* combineAnd(Condition* other) override; // @copydoc - result_t resolve(MessageMap* messages, ostringstream& errorMessage, - void (*readMessageFunc)(Message* message) = NULL) override; + result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages, + ostringstream* errorMessage) override; // @copydoc bool isTrue() override; @@ -923,7 +910,7 @@ class SimpleCondition : public Condition { * @param field the field name to check against, or empty for first field. * @return whether the field matches one of the valid values. */ - virtual bool checkValue(Message* message, const string field) { return true; } + virtual bool checkValue(const Message* message, const string& field) { return true; } /** the value that matched in @a checkValue. */ string m_matchedValue; @@ -976,8 +963,8 @@ class SimpleNumericCondition : public SimpleCondition { * @param field the field name. * @param valueRanges the valid value ranges (pairs of from/to inclusive), empty for @a m_message seen check. */ - SimpleNumericCondition(const string condName, const string refName, const string circuit, const string level, - const string name, const symbol_t dstAddress, const string field, const vector valueRanges) + SimpleNumericCondition(const string& condName, const string& refName, const string& circuit, const string& level, + const string& name, symbol_t dstAddress, const string& field, const vector& valueRanges) : SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true), m_valueRanges(valueRanges) { } @@ -989,7 +976,7 @@ class SimpleNumericCondition : public SimpleCondition { protected: // @copydoc - bool checkValue(Message* message, const string field) override; + bool checkValue(const Message* message, const string& field) override; private: @@ -1014,8 +1001,8 @@ class SimpleStringCondition : public SimpleCondition { * @param field the field name. * @param values the valid values. */ - 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 values) + SimpleStringCondition(const string& condName, const string& refName, const string& circuit, const string& level, + const string& name, symbol_t dstAddress, const string& field, const vector& values) : SimpleCondition(condName, refName, circuit, level, name, dstAddress, field, true), m_values(values) { } @@ -1030,7 +1017,7 @@ class SimpleStringCondition : public SimpleCondition { protected: // @copydoc - bool checkValue(Message* message, const string field) override; + bool checkValue(const Message* message, const string& field) override; private: @@ -1056,14 +1043,14 @@ class CombinedCondition : public Condition { virtual ~CombinedCondition() {} // @copydoc - void dump(ostream& output, bool matched = false) const override; + void dump(bool matched, ostream* output) const override; // @copydoc CombinedCondition* combineAnd(Condition* other) override { m_conditions.push_back(other); return this; } // @copydoc - result_t resolve(MessageMap* messages, ostringstream& errorMessage, - void (*readMessageFunc)(Message* message) = NULL) override; + result_t resolve(void (*readMessageFunc)(Message* message), MessageMap* messages, + ostringstream* errorMessage) override; // @copydoc bool isTrue() override; @@ -1087,7 +1074,7 @@ class Instruction { * executed for the same source file. * @param defaults the mapped definition defaults. */ - Instruction(Condition* condition, const bool singleton, const map& defaults) + Instruction(bool singleton, const map& defaults, Condition* condition) : 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. * @return @a RESULT_OK on success, or an error code. */ - static result_t create(const string& contextPath, const string type, - Condition* condition, map& row, map& defaults, - Instruction*& returnValue); + static result_t create(const string& contextPath, const string& type, + Condition* condition, const map& row, const map& defaults, + Instruction** returnValue); /** * Return the @a Condition this instruction requires. @@ -1133,13 +1120,12 @@ class Instruction { * Execute the instruction. * @param messages the @a MessageMap. * @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. */ - 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. */ Condition* m_condition; @@ -1147,8 +1133,6 @@ class Instruction { * same source file. */ const bool m_singleton; - - protected: /** the defaults by field name. */ map m_defaults; }; @@ -1167,8 +1151,9 @@ class LoadInstruction : public Instruction { * @param defaults the mapped definition defaults. * @param filename the name of the file to load. */ - LoadInstruction(Condition* condition, const bool singleton, map& defaults, const string filename) - : Instruction(condition, singleton, defaults), m_filename(filename) { } + LoadInstruction(bool singleton, const map& defaults, const string& filename, + Condition* condition) + : Instruction(singleton, defaults, condition), m_filename(filename) { } /** * Destructor. @@ -1176,7 +1161,7 @@ class LoadInstruction : public Instruction { virtual ~LoadInstruction() { } // @copydoc - result_t execute(MessageMap* messages, ostringstream& log, Condition* condition) override; + result_t execute(MessageMap* messages, ostringstream* log) override; private: @@ -1215,7 +1200,7 @@ class MessageMap : public MappedFileReader { * @param addAll whether to add all messages, even if duplicate. * @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), m_configPath(configPath), 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). * @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. @@ -1253,36 +1238,36 @@ class MessageMap : public MappedFileReader { * @return @a RESULT_OK on success, or an error code. * 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 - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override; + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override; // @copydoc - result_t addDefaultFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override; + result_t addDefaultFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override; /** * 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 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 condition the variable in which to store the result. * @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 - bool extractDefaultsFromFilename(string filename, map& defaults, - symbol_t* destAddress = NULL, unsigned int* software = NULL, unsigned int* hardware = NULL) const override; + bool extractDefaultsFromFilename(const string& filename, map* defaults, + symbol_t* destAddress, unsigned int* software, unsigned int* hardware) const override; // @copydoc - result_t readFromFile(const string filename, string& errorDescription, bool verbose = false, - map* defaults = NULL, size_t* hash = NULL, size_t* size = NULL, time_t* time = NULL) override; + result_t readFromFile(const string& filename, bool verbose, map* defaults, + string* errorDescription, size_t* hash, size_t* size, time_t* time) override; // @copydoc - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override; + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override; /** * Get the scan @a Message instance for the specified address. @@ -1299,30 +1284,30 @@ class MessageMap : public MappedFileReader { /** * 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 errorDescription a string in which to store the error description in case of error. * @return @a RESULT_OK on success, or an error code. */ - result_t resolveConditions(string& errorDescription, bool verbose = false); + result_t resolveConditions(bool verbose, string* errorDescription); /** * 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 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. */ - result_t resolveCondition(Condition* condition, string& errorDescription, - void (*readMessageFunc)(Message* message) = NULL); + result_t resolveCondition(void (*readMessageFunc)(Message* message), Condition* condition, + string* errorDescription); /** * 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 * @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. */ - 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. @@ -1330,14 +1315,14 @@ class MessageMap : public MappedFileReader { * @param filename the name of the configuration file (including relative path). * @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. * @param address the slave address. * @return the loaded configuration files (list of file names with relative path). */ - const vector& getLoadedFiles(const symbol_t address) const; + const vector& getLoadedFiles(symbol_t address) const; /** * 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. * @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; /** @@ -1363,7 +1348,7 @@ class MessageMap : public MappedFileReader { * @return the found @a Message instances, or NULL. * Note: the caller may not free the returned instances. */ - const vector* getByKey(const uint64_t key) const; + const vector* getByKey(uint64_t key) const; /** * 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. * Note: the caller may not free the returned instance. */ - Message* find(const string& circuit, const string& name, const string& levels, const bool isWrite, - const bool isPassive = false) const; + Message* find(const string& circuit, const string& name, const string& levels, bool isWrite, + bool isPassive = false) const; /** * 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. */ deque findAll(const string& circuit, const string& name, const string& levels, - const bool completeMatch = true, const bool withRead = true, const bool withWrite = false, - const bool withPassive = false, const bool includeEmptyLevel = true, const bool onlyAvailable = true, - const time_t since = 0, const time_t until = 0) const; + bool completeMatch = true, bool withRead = true, bool withWrite = false, + bool withPassive = false, bool includeEmptyLevel = true, bool onlyAvailable = true, + time_t since = 0, time_t until = 0) const; /** * 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. * Note: the caller may not free the returned instance. */ - Message* find(const MasterSymbolString& master, const bool anyDestination = false, const bool withRead = true, - const bool withWrite = true, const bool withPassive = true, const bool onlyAvailable = true) const; + Message* find(const MasterSymbolString& master, bool anyDestination = false, bool withRead = true, + 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. @@ -1427,19 +1412,19 @@ class MessageMap : public MappedFileReader { /** * 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 message the @a Message to poll. */ - void addPollMessage(Message* message, bool toFront = false); + void addPollMessage(bool toFront, Message* message); /** * Decode circuit specific data. * @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 output the @a ostringstream to append the decoded value(s) to. * @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. @@ -1491,10 +1476,10 @@ class MessageMap : public MappedFileReader { /** * 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 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: diff --git a/src/lib/ebus/symbol.cpp b/src/lib/ebus/symbol.cpp index bdadd89e..c359edea 100644 --- a/src/lib/ebus/symbol.cpp +++ b/src/lib/ebus/symbol.cpp @@ -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, - result_t& result, size_t* length) { +unsigned int parseInt(const char* str, int base, unsigned int minValue, unsigned int maxValue, + result_t* result, size_t* length) { char* strEnd = NULL; unsigned long ret = strtoul(str, &strEnd, base); if (strEnd == NULL || strEnd == str || *strEnd != 0) { - result = RESULT_ERR_INVALID_NUM; // invalid value + *result = RESULT_ERR_INVALID_NUM; // invalid value return 0; } if (minValue > ret || ret > maxValue) { - result = RESULT_ERR_OUT_OF_RANGE; // invalid value + *result = RESULT_ERR_OUT_OF_RANGE; // invalid value return 0; } if (length != NULL) { *length = (unsigned int)(strEnd - str); } - result = RESULT_OK; + *result = RESULT_OK; return (unsigned int)ret; } -int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, - size_t* length) { +int parseSignedInt(const char* str, int base, int minValue, int maxValue, + result_t* result, size_t* length) { char* strEnd = NULL; long ret = strtol(str, &strEnd, base); if (strEnd == NULL || *strEnd != 0) { - result = RESULT_ERR_INVALID_NUM; // invalid value + *result = RESULT_ERR_INVALID_NUM; // invalid value return 0; } if (minValue > ret || ret > maxValue) { - result = RESULT_ERR_OUT_OF_RANGE; // invalid value + *result = RESULT_ERR_OUT_OF_RANGE; // invalid value return 0; } if (length != NULL) { *length = (unsigned int)(strEnd - str); } - result = RESULT_OK; + *result = RESULT_OK; return static_cast(ret); } -void SymbolString::updateCrc(symbol_t& crc, const symbol_t value) { - crc = CRC_LOOKUP_TABLE[crc]^value; +void SymbolString::updateCrc(symbol_t value, symbol_t* crc) { + *crc = CRC_LOOKUP_TABLE[*crc]^value; } result_t SymbolString::parseHex(const string& str) { result_t result; 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) { return result; } @@ -119,7 +119,7 @@ result_t SymbolString::parseHexEscaped(const string& str) { result_t result; bool inEscape = false; 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) { return result; } @@ -162,13 +162,13 @@ symbol_t SymbolString::calcCrc() const { for (size_t i = 0; i < m_data.size(); i++) { symbol_t value = m_data[i]; if (value == ESC) { - updateCrc(crc, ESC); - updateCrc(crc, 0x00); + updateCrc(ESC, &crc); + updateCrc(0x00, &crc); } else if (value == SYN) { - updateCrc(crc, ESC); - updateCrc(crc, 0x01); + updateCrc(ESC, &crc); + updateCrc(0x01, &crc); } else { - updateCrc(crc, value); + updateCrc(value, &crc); } } return crc; diff --git a/src/lib/ebus/symbol.h b/src/lib/ebus/symbol.h index 0c88e31d..bd9dd008 100644 --- a/src/lib/ebus/symbol.h +++ b/src/lib/ebus/symbol.h @@ -96,8 +96,8 @@ typedef unsigned char symbol_t; * @param length the optional variable in which to store the number of read characters. * @return the parsed value. */ -unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, - result_t& result, size_t* length = NULL); +unsigned int parseInt(const char* str, int base, unsigned int minValue, unsigned int maxValue, + result_t* result, size_t* length = NULL); /** * 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. * @return the parsed value. */ -int parseSignedInt(const char* str, int base, const int minValue, const int maxValue, result_t& result, - size_t* length = NULL); +int parseSignedInt(const char* str, int base, int minValue, int maxValue, + result_t* result, size_t* length = NULL); /** * A string of unescaped bus symbols. @@ -121,15 +121,15 @@ class SymbolString { * Creates a new empty instance. * @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: /** * 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 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. @@ -175,7 +175,7 @@ class SymbolString { * @param index the index of the symbol to return. * @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()) { return SYN; } @@ -187,7 +187,7 @@ class SymbolString { * @param other 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; } @@ -196,7 +196,7 @@ class SymbolString { * @param other 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; } @@ -207,7 +207,7 @@ class SymbolString { * 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). */ - int compareTo(SymbolString& other) { + int compareTo(const SymbolString& other) const { if (m_data.size() != other.m_data.size() || m_isMaster != other.m_isMaster) { return 1; } @@ -230,7 +230,7 @@ class SymbolString { * Append a symbol to the end of the symbol string. * @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. @@ -277,7 +277,7 @@ class SymbolString { * @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. */ - symbol_t dataAt(const size_t index) const { + symbol_t dataAt(size_t index) const { size_t offset = (m_isMaster ? 5 : 1) + index; if (offset < m_data.size()) { return m_data[offset]; @@ -290,7 +290,7 @@ class SymbolString { * @param index the index of the data byte (within DD) to return. * @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; if (offset >= m_data.size()) { m_data.resize(offset+1, 0); diff --git a/src/lib/ebus/test/test_data.cpp b/src/lib/ebus/test/test_data.cpp index 21970ef8..b9d8489d 100644 --- a/src/lib/ebus/test/test_data.cpp +++ b/src/lib/ebus/test/test_data.cpp @@ -53,34 +53,34 @@ class TestReader : public MappedFileReader { TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest) : MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest), m_fields(NULL) {} - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override { - if (row.empty()) { - row.push_back("*name"); - row.push_back("part"); - row.push_back("type"); - row.push_back("divisor/values"); - row.push_back("unit"); - row.push_back("comment"); + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override { + if (row->empty()) { + row->push_back("*name"); + row->push_back("part"); + row->push_back("type"); + row->push_back("divisor/values"); + row->push_back("unit"); + row->push_back("comment"); return RESULT_OK; } - if (row[0][0] != '*') { + if ((*row)[0][0] != '*') { return RESULT_ERR_INVALID_ARG; } return RESULT_OK; // leave it to DataField::create } - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override { - if (!row.empty() || subRows.empty()) { + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override { + if (!row->empty() || subRows->empty()) { cout << "read line " << static_cast(lineNo) << ": read error: got " - << static_cast(row.size()) << "/0 main, " << static_cast(subRows.size()) + << static_cast(row->size()) << "/0 main, " << static_cast(subRows->size()) << "/>=3 sub" << endl; return RESULT_ERR_EOF; } cout << "read line " << static_cast(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: - DataFieldTemplates* m_templates; + const DataFieldTemplates* m_templates; const bool m_isSet; const bool m_isMasterDest; public: @@ -508,7 +508,7 @@ int main() { istringstream dummystr("#"); string errorDescription; vector row; - templates->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row); + templates->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL); const DataField* fields = NULL; for (size_t i = 0; i < sizeof(checks) / sizeof(checks[0]); i++) { string check[5] = checks[i]; @@ -558,7 +558,7 @@ int main() { } if (isTemplate) { 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) { cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", " << errorDescription << endl; @@ -570,7 +570,7 @@ int main() { lineNo = 0; dummystr.clear(); 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) { cout << "\"" << check[0] << "\": reader header error: " << getResultCode(result) << ", " << errorDescription << endl; @@ -578,7 +578,7 @@ int main() { continue; } lineNo = baseLine + i; - result = reader.readLineFromStream(isstr, errorDescription, "", lineNo, row); + result = reader.readLineFromStream("", false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL); fields = reader.m_fields; if (failedCreate) { if (result == RESULT_OK) { @@ -600,7 +600,7 @@ int main() { continue; } cout << "\"" << check[0] << "\"=\""; - fields->dump(cout); + fields->dump(&cout); cout << "\": create OK" << endl; ostringstream output; @@ -616,22 +616,21 @@ int main() { cout << " parse \"" << sstr.getStr().substr(0, 2) << "\" error: " << getResultCode(result) << endl; 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) { - result = fields->read(sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, - !output.str().empty()); + result = fields->read(sstr, 0, !output.str().empty(), NULL, -1, verbosity|(numeric?OF_NUMERIC:0), -1, &output); } if (failedRead) { 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 = true; } else { - cout << " failed read " << fields->getName() << " >" << check[2] << " " << check[3] + cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3] << "< OK" << endl; } } 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 = true; } else { @@ -641,21 +640,21 @@ int main() { if (verbosity == 0) { istringstream input(expectStr); - result = fields->write(input, writeMstr, 0); + result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeMstr, NULL); if (result >= RESULT_OK) { - result = fields->write(input, writeSstr, 0); + result = fields->write(UI_FIELD_SEPARATOR, 0, &input, &writeSstr, NULL); } if (failedWrite) { if (result >= RESULT_OK) { - cout << " failed write " << fields->getName() << " >" + cout << " failed write " << fields->getName(-1) << " >" << expectStr << "< error: unexpectedly succeeded" << endl; error = true; } else { - cout << " failed write " << fields->getName() << " >" + cout << " failed write " << fields->getName(-1) << " >" << expectStr << "< OK" << endl; } } else if (result < RESULT_OK) { - cout << " write " << fields->getName() << " >" << expectStr + cout << " write " << fields->getName(-1) << " >" << expectStr << "< error: " << getResultCode(result) << endl; error = true; } else { diff --git a/src/lib/ebus/test/test_device.cpp b/src/lib/ebus/test/test_device.cpp index 35e9251d..d54de3c8 100644 --- a/src/lib/ebus/test/test_device.cpp +++ b/src/lib/ebus/test/test_device.cpp @@ -40,7 +40,7 @@ int main() { while (1) { symbol_t byte = 0; - result = device->recv(0, byte); + result = device->recv(0, &byte); if (result == RESULT_OK) { cout << hex << setw(2) << setfill('0') diff --git a/src/lib/ebus/test/test_filereader.cpp b/src/lib/ebus/test/test_filereader.cpp index ebcd14e3..41bae447 100644 --- a/src/lib/ebus/test/test_filereader.cpp +++ b/src/lib/ebus/test/test_filereader.cpp @@ -73,8 +73,8 @@ static unsigned int baseLine = 0; class NoopReader : public FileReader { public: - result_t addFromFile(vector& row, string& errorDescription, - const string filename, unsigned int lineNo) override { + result_t addFromFile(const string& filename, unsigned int lineNo, vector* row, + string* errorDescription) override { return RESULT_OK; } }; @@ -83,25 +83,25 @@ class TestReader : public MappedFileReader { public: TestReader(size_t expectedCols, size_t langCols) : MappedFileReader::MappedFileReader(false, ""), m_expectedCols(expectedCols), m_langCols(langCols) {} - result_t getFieldMap(vector& row, string& errorDescription, const string preferLanguage) const override { - if (row.size() == m_expectedCols+m_langCols) { + result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override { + if (row->size() == m_expectedCols+m_langCols) { cout << "get field map: split OK" << endl; if (m_langCols == 1) { - row[0] = SKIP_COLUMN; - size_t pos = row[1].find_last_of('.'); - row[1] = row[1].substr(0, pos); + (*row)[0] = SKIP_COLUMN; + size_t pos = (*row)[1].find_last_of('.'); + (*row)[1] = (*row)[1].substr(0, pos); } return RESULT_OK; } - cout << "get field map: error got " << static_cast(row.size()) << " columns, expected " << + cout << "get field map: error got " << static_cast(row->size()) << " columns, expected " << static_cast(m_expectedCols+m_langCols) << endl; return RESULT_ERR_EOF; } - result_t addFromFile(map& row, vector< map >& subRows, - string& errorDescription, const string filename, unsigned int lineNo) override { - if (row.empty() || (m_expectedCols == 3) != subRows.empty()) { + result_t addFromFile(const string& filename, unsigned int lineNo, map* row, + vector< map >* subRows, string* errorDescription) override { + if (row->empty() || (m_expectedCols == 3) != subRows->empty()) { cout << "read line " << static_cast(baseLine + lineNo) << ": read error: got " - << static_cast(row.size()) << "/3 main, " << static_cast(subRows.size()) + << static_cast(row->size()) << "/3 main, " << static_cast(subRows->size()) << (m_expectedCols == 3 ? "/0 sub" : "/>0 sub") << endl; return RESULT_ERR_EOF; } @@ -111,7 +111,7 @@ class TestReader : public MappedFileReader { } cout << "read line " << static_cast(baseLine + lineNo) << ": split OK" << endl; string resultline[3] = resultlines[lineNo - 1]; - if (row.empty()) { + if (row->empty()) { cout << " result empty"; if (resultline[0] == "") { cout << ": OK" << endl; @@ -127,7 +127,7 @@ class TestReader : public MappedFileReader { map& defaults = getDefaults()[""]; for (size_t colIdx = 0; colIdx < 3; colIdx++) { string col = colnames[colIdx]; - string got = row[col] + defaults[col]; + string got = (*row)[col] + defaults[col]; string expect = resultline[colIdx]; ostringstream type; type << "line " << static_cast(baseLine + lineNo) << " column \"" << col << "\""; @@ -137,17 +137,17 @@ class TestReader : public MappedFileReader { error = true; } } - if (row.size() > 3) { + if (row->size() > 3) { ostringstream type; type << "line " << static_cast(baseLine + lineNo); verify(false, type.str(), "", false, "", "extra column"); 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]; - row = subRows[subIdx]; - if (row.empty()) { + *row = (*subRows)[subIdx]; + if (row->empty()) { cout << " sub " << subIdx << " result empty"; if (resultline[0] == "") { cout << ": OK" << endl; @@ -161,7 +161,7 @@ class TestReader : public MappedFileReader { vector< map >& subDefaults = getSubDefaults()[""]; for (size_t colIdx = 0; colIdx < 2; colIdx++) { string col = resultsubline[colIdx*2]; - string got = row[col]; + string got = (*row)[col]; if (subIdx < subDefaults.size()) { got += subDefaults[subIdx][col]; } @@ -174,7 +174,7 @@ class TestReader : public MappedFileReader { error = true; } } - if (row.size() > 2) { + if (row->size() > 2) { ostringstream type; type << "line " << static_cast(baseLine + lineNo) << " sub " << subIdx; verify(false, type.str(), "", false, "", "extra sub column"); @@ -196,14 +196,14 @@ int main(int argc, char** argv) { size_t hash = 0, size = 0; time_t time = 0; 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] << " "; if (result != RESULT_OK) { cout << getResultCode(result) << ", " << errorDescription << endl; error = true; continue; } - FileReader::formatHash(hash, cout); + FileReader::formatHash(hash, &cout); cout << " " << size << " " << time << endl; } return error ? 1 : 0; @@ -226,7 +226,7 @@ int main(int argc, char** argv) { string errorDescription; while (ifs.peek() != EOF) { 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) { cout << " error " << getResultCode(result) << endl; error = true; @@ -267,7 +267,7 @@ int main(int argc, char** argv) { subDefaults[0]["subcol 2"] = ";default of sub 0 subcol 2"; while (ifs.peek() != EOF) { 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) { cout << " error " << getResultCode(result) << endl; error = true; diff --git a/src/lib/ebus/test/test_message.cpp b/src/lib/ebus/test/test_message.cpp index 0c54c6f6..f8afb969 100644 --- a/src/lib/ebus/test/test_message.cpp +++ b/src/lib/ebus/test/test_message.cpp @@ -54,7 +54,7 @@ DataFieldTemplates* templates = NULL; namespace ebusd { -DataFieldTemplates* getTemplates(const string filename) { +DataFieldTemplates* getTemplates(const string& filename) { if (filename == "") { // avoid compiler warning return templates; } @@ -71,7 +71,9 @@ int main() { unsigned int baseLine = __LINE__+1; string checks[][5] = { {"date,HDA:3,,,Datum", "", "", "", "template"}, + {"bdate:date,BDA,,,Datum", "", "", "", "template"}, {"time,VTI,,,", "", "", "", "template"}, + {"btime:time,BTI,,,Uhrzeit", "", "", "", "template"}, {"dcfstate,UCH,0=nosignal;1=ok;2=sync;3=valid,,", "", "", "", "template"}, {"temp,D2C,,°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", ""}, {"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,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", "", "ff15b50900", "00", ""}, {"*w,,,,,,b505,2d", "", "", "", ""}, @@ -147,12 +151,12 @@ int main() { istringstream dummystr("#"); string errorDescription; vector row; - templates->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row, false); + templates->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL); lineNo = 0; MessageMap* messages = new MessageMap(""); dummystr.clear(); dummystr.str("#"); - messages->readLineFromStream(dummystr, errorDescription, __FILE__, lineNo, row, false); + messages->readLineFromStream(__FILE__, false, &dummystr, &lineNo, &row, &errorDescription, NULL, NULL); vector< vector > defaultsRows; Message* message = NULL; vector mstrs; @@ -183,7 +187,7 @@ int main() { lineNo = baseLine + i; cout << "line " << (lineNo+1) << " "; 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) { cout << "\"" << check[0] << "\": template read error: " << getResultCode(result) << ", " << errorDescription << endl; @@ -197,7 +201,7 @@ int main() { } if (isstr.peek() == '*') { // 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) { cout << "\"" << check[0] << "\": default read error: " << getResultCode(result) << ", " << errorDescription << endl; error = true; @@ -279,7 +283,7 @@ int main() { } cout << "\"" << check[2] << "\": find OK" << endl; } else { - result = messages->readLineFromStream(isstr, errorDescription, __FILE__, lineNo, row); + result = messages->readLineFromStream(__FILE__, false, &isstr, &lineNo, &row, &errorDescription, NULL, NULL); if (failedCreate) { if (result == RESULT_OK) { cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; @@ -345,11 +349,11 @@ int main() { } ostringstream output; if (withMessageDump && !decodeJson) { - message->dump(output, NULL, true); + message->dump(NULL, true, &output); output << ": "; } - result = message->decodeLastData(output, - (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false); + result = message->decodeLastData(false, NULL, -1, + (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), &output); if (result != RESULT_OK) { cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: " << getResultCode(result) << endl; @@ -385,7 +389,7 @@ int main() { if (!message->isPassive() && (withInput || !decode)) { istringstream input(inputStr); MasterSymbolString writeMstr; - result = message->prepareMaster(0xff, writeMstr, input); + result = message->prepareMaster(0, 0xff, SYN, UI_FIELD_SEPARATOR, &input, &writeMstr); if (failedPrepare) { if (result == RESULT_OK) { cout << " \"" << inputStr << "\": failed prepare error: unexpectedly succeeded" << endl; diff --git a/src/tools/ebusctl.cpp b/src/tools/ebusctl.cpp index bce14be9..3e609f85 100644 --- a/src/tools/ebusctl.cpp +++ b/src/tools/ebusctl.cpp @@ -120,7 +120,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { return 0; } -string fetchData(ebusd::TCPSocket* socket, bool& listening) { +string fetchData(ebusd::TCPSocket* socket, bool listening) { char data[1024]; ssize_t datalen; ostringstream ostream;