add value range and step support, fix value list validation

This commit is contained in:
John
2025-01-06 22:08:49 +01:00
parent 88b039e58e
commit e795ce604a
5 changed files with 433 additions and 154 deletions
+3 -2
View File
@@ -135,8 +135,9 @@ result_t TemParamDataType::writeSymbols(const size_t offset, const size_t length
value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6 value = (grp << 7) | num; // grp in bits 7...11, num in bits 0...6
} }
} }
if (value < getMinValue() || value > getMaxValue()) { result_t ret = checkValueRange(value);
return RESULT_ERR_OUT_OF_RANGE; // value out of range if (ret != RESULT_OK) {
return ret;
} }
return writeRawValue(value, offset, length, output, usedLength); return writeRawValue(value, offset, length, output, usedLength);
} }
+62 -4
View File
@@ -273,6 +273,7 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
string divisorStr = pluck("divisor", &row); string divisorStr = pluck("divisor", &row);
string valuesStr = pluck("values", &row); string valuesStr = pluck("values", &row);
string rangeStr = pluck("range", &row);
if (divisorStr.empty() && valuesStr.empty()) { if (divisorStr.empty() && valuesStr.empty()) {
divisorStr = pluck("divisor/values", &row); // [divisor|values] divisorStr = pluck("divisor/values", &row); // [divisor|values]
if (divisorStr.find('=') != string::npos) { if (divisorStr.find('=') != string::npos) {
@@ -365,6 +366,57 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
} }
transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper); transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper);
const DataType* dataType = DataTypeList::getInstance()->get(typeName, length == REMAIN_LEN ? 0 : length); const DataType* dataType = DataTypeList::getInstance()->get(typeName, length == REMAIN_LEN ? 0 : length);
if (dataType && dataType->isNumeric() && !rangeStr.empty()) {
const NumberDataType* numType = reinterpret_cast<const NumberDataType*>(dataType);
if (divisor != 1 && divisor != 0) {
result = numType->derive(divisor, numType->getBitCount(), &numType);
divisor = 1;
}
// either from-to or from-to:step
size_t sepPos = rangeStr.find('-', 1);
string part = rangeStr.substr(0, sepPos);
FileReader::trim(&part);
unsigned int from;
if (result == RESULT_OK) {
result = numType->parseInput(part, &from);
}
unsigned int to = from;
unsigned int inc = 0;
if (result == RESULT_OK) {
part = rangeStr.substr(sepPos+1);
FileReader::trim(&part);
sepPos = part.find(':');
if (sepPos != string::npos) {
string incStr = part.substr(sepPos + 1);
FileReader::trim(&incStr);
part = part.substr(0, sepPos);
FileReader::trim(&part);
result = numType->parseInput(incStr, &inc);
}
if (result == RESULT_OK) {
result = numType->parseInput(part, &to);
}
}
float ffrom = 0, fto = 0;
if (result == RESULT_OK) {
result = numType->getFloatFromRawValue(from, &ffrom);
}
if (result == RESULT_OK) {
result = numType->getFloatFromRawValue(to, &fto);
}
if (result == RESULT_OK && ffrom > fto) {
result = RESULT_ERR_INVALID_LIST;
}
if (result == RESULT_OK) {
result = numType->derive(from, to, inc, &numType);
};
if (result != RESULT_OK) {
*errorDescription = "\""+rangeStr+"\" in field "+formatInt(fieldIndex);
result = RESULT_ERR_OUT_OF_RANGE;
break;
}
dataType = numType;
}
if (!dataType) { if (!dataType) {
result = RESULT_ERR_NOTFOUND; result = RESULT_ERR_NOTFOUND;
*errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex); *errorDescription = "field type "+typeName+" in field "+formatInt(fieldIndex);
@@ -512,8 +564,11 @@ result_t SingleDataField::create(const string& name, const map<string, string>&
*returnField = new SingleDataField(name, attributes, numType, partType, byteCount); *returnField = new SingleDataField(name, attributes, numType, partType, byteCount);
return RESULT_OK; return RESULT_OK;
} }
if (values->begin()->first < numType->getMinValue() || values->rbegin()->first > numType->getMaxValue()) { for (auto& it : *values) {
return RESULT_ERR_OUT_OF_RANGE; result_t ret = numType->checkValueRange(it.first);
if (ret != RESULT_OK) {
return ret;
}
} }
*returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, *values); *returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, *values);
return RESULT_OK; return RESULT_OK;
@@ -775,8 +830,11 @@ result_t ValueListDataField::derive(const string& name, PartType partType, int d
} }
const NumberDataType* num = reinterpret_cast<const NumberDataType*>(m_dataType); const NumberDataType* num = reinterpret_cast<const NumberDataType*>(m_dataType);
if (!values.empty()) { if (!values.empty()) {
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) { for (auto& it : values) {
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field result_t ret = num->checkValueRange(it.first);
if (ret != RESULT_OK) {
return RESULT_ERR_INVALID_ARG;
}
} }
fields->push_back(new ValueListDataField(useName, *attributes, fields->push_back(new ValueListDataField(useName, *attributes,
num, partType, m_length, values)); num, partType, m_length, values));
+183 -74
View File
@@ -700,9 +700,17 @@ bool NumberDataType::dump(OutputFormat outputFormat, size_t length, AppendDiviso
ret = true; ret = true;
} }
} }
if (ret && (outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) { if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
if (ret) {
*output << ", \"precision\": " << static_cast<unsigned>(getPrecision()); *output << ", \"precision\": " << static_cast<unsigned>(getPrecision());
} }
*output << ", \"min\": ";
getMinMax(false, OF_JSON, output);
*output << ", \"max\": ";
getMinMax(true, OF_JSON, output);
*output << ", \"step\": ";
getStep(OF_JSON, output);
}
return ret; return ret;
} }
@@ -747,6 +755,11 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
} else { } else {
return RESULT_ERR_INVALID_ARG; return RESULT_ERR_INVALID_ARG;
} }
ostringstream str;
str << m_id << ',' << static_cast<unsigned>(bitCount) << ',' << static_cast<signed>(divisor);
string key = str.str();
*derived = static_cast<const NumberDataType*>(DataTypeList::getInstance()->get(key));
if (*derived == nullptr) {
if (m_bitCount < 8) { if (m_bitCount < 8) {
*derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement, *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_firstBit, divisor, m_baseType ? m_baseType : this); m_firstBit, divisor, m_baseType ? m_baseType : this);
@@ -754,16 +767,107 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
*derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement, *derived = new NumberDataType(m_id, bitCount, m_flags, m_replacement,
m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this); m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
} }
DataTypeList::getInstance()->addCleanup(*derived); DataTypeList::getInstance()->add(*derived, key);
}
return RESULT_OK;
}
result_t NumberDataType::derive(unsigned int min, unsigned int max, unsigned int inc, const NumberDataType** derived)
const {
if (m_bitCount < 8) {
return RESULT_ERR_INVALID_ARG;
}
if (min == m_minValue && max == m_maxValue && (inc == 0 || inc == m_incValue)) {
*derived = this;
return RESULT_OK;
}
if (checkValueRange(min) != RESULT_OK || checkValueRange(max) != RESULT_OK) {
return RESULT_ERR_OUT_OF_RANGE;
}
ostringstream str;
str << m_id << ',' << static_cast<unsigned>(m_bitCount) << ',' << static_cast<signed>(m_divisor)
<< ',' << static_cast<unsigned>(min)<< ',' << static_cast<unsigned>(max)<< ',' << static_cast<unsigned>(inc);
string key = str.str();
*derived = static_cast<const NumberDataType*>(DataTypeList::getInstance()->get(key));
if (*derived == nullptr) {
*derived = new NumberDataType(m_id, m_bitCount, m_flags, m_replacement,
min, max, inc, m_divisor, m_baseType ? m_baseType : this);
DataTypeList::getInstance()->add(*derived, key);
}
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const { result_t NumberDataType::getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const {
return readFromRawValue(getMax ? m_maxValue : m_minValue, outputFormat, output); return readFromRawValue(getMax ? m_maxValue : m_minValue, outputFormat, output, true);
} }
result_t NumberDataType::getStep(const OutputFormat outputFormat, ostream* output) const { result_t NumberDataType::getStep(const OutputFormat outputFormat, ostream* output) const {
return readFromRawValue(hasFlag(EXP) ? floatToUint(1.0f) : 1, outputFormat, output); return readFromRawValue(m_incValue ? m_incValue : hasFlag(EXP) ? floatToUint(1.0f) : 1, outputFormat, output, true);
}
result_t NumberDataType::checkValueRange(unsigned int value, bool* pnegative) const {
bool negative;
if (hasFlag(SIG)) { // signed value
unsigned int negBit = 1 << (m_bitCount - 1);
negative = (value & negBit) != 0;
if (hasFlag(EXP)) {
float fval = uintToFloat(value, negative);
if (!isfinite(fval)) {
return RESULT_EMPTY;
}
float cval = uintToFloat(m_minValue, (m_minValue & negBit) != 0);
if (!isfinite(cval)) {
return RESULT_EMPTY;
}
if (fval < cval) {
return RESULT_ERR_OUT_OF_RANGE;
}
cval = uintToFloat(m_maxValue, (m_maxValue & negBit) != 0);
if (!isfinite(cval)) {
return RESULT_EMPTY;
}
if (fval > cval) {
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
if (m_minValue & negBit) {
// negative min
if (negative && value < m_minValue) {
// e.g. SCH val=0xfc=-4 min=0xff=-1
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
// positive min
if (negative || value < m_minValue) {
// e.g. SCH val=0xfc=-4 min=0x01=+1
// e.g. SCH val=0x00=0 min=0x01=+1
return RESULT_ERR_OUT_OF_RANGE;
}
}
if (m_maxValue & negBit) {
// negative max
if (!negative || value > m_maxValue) {
// e.g. SCH val=0x00=0 max=0xff=-1
// e.g. SCH val=0xff=-1 max=0xfe=-2
return RESULT_ERR_OUT_OF_RANGE;
}
} else {
// positive max
if (!negative && value > m_maxValue) {
// e.g. SCH val=0x04=+4 max=0x01=+1
return RESULT_ERR_OUT_OF_RANGE;
}
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE;
} else {
negative = false;
}
if (pnegative) {
*pnegative = negative;
}
return RESULT_OK;
} }
result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input, result_t NumberDataType::readRawValue(size_t offset, size_t length, const SymbolString& input,
@@ -830,22 +934,10 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
return RESULT_EMPTY; return RESULT_EMPTY;
} }
bool negative; bool negative = false;
if (hasFlag(SIG)) { // signed value result_t ret = checkValueRange(value, &negative);
negative = (value & (1 << (m_bitCount - 1))) != 0; if (ret != RESULT_OK) {
if (!hasFlag(EXP)) { return ret;
if (negative) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} else {
negative = false;
} }
int signedValue; int signedValue;
if (m_bitCount == 32) { if (m_bitCount == 32) {
@@ -865,7 +957,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
val /= static_cast<float>(m_divisor); val /= static_cast<float>(m_divisor);
} }
} }
*output = static_cast<float>(val); *output = val;
return RESULT_OK; return RESULT_OK;
} }
if (!negative) { if (!negative) {
@@ -895,7 +987,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
} }
result_t NumberDataType::readFromRawValue(unsigned int value, result_t NumberDataType::readFromRawValue(unsigned int value,
OutputFormat outputFormat, ostream* output) const { OutputFormat outputFormat, ostream* output, bool skipRangeCheck) const {
size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8); size_t length = (m_bitCount < 8) ? 1 : (m_bitCount/8);
// initialize output // initialize output
*output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6); *output << setw(0) << std::resetiosflags(output->flags()) << dec << std::skipws << setprecision(6);
@@ -909,22 +1001,10 @@ result_t NumberDataType::readFromRawValue(unsigned int value,
return RESULT_OK; return RESULT_OK;
} }
bool negative; bool negative = false;
if (hasFlag(SIG)) { // signed value result_t ret = checkValueRange(value, &negative);
negative = (value & (1 << (m_bitCount - 1))) != 0; if (!skipRangeCheck && ret != RESULT_OK) {
if (!hasFlag(EXP)) { return ret;
if (negative) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} else {
negative = false;
} }
int signedValue; int signedValue;
if (m_bitCount == 32) { if (m_bitCount == 32) {
@@ -1055,7 +1135,7 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
} else { } else {
if (m_divisor == 1) { if (m_divisor == 1) {
if (hasFlag(SIG)) { if (hasFlag(SIG)) {
long signedValue = static_cast<long>(val); // TODO static_c? long signedValue = static_cast<long>(val);
if (signedValue < 0 && m_bitCount != 32) { if (signedValue < 0 && m_bitCount != 32) {
value = (unsigned int)(signedValue + (1 << m_bitCount)); value = (unsigned int)(signedValue + (1 << m_bitCount));
} else { } else {
@@ -1091,37 +1171,28 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
value = (unsigned int)dvalue; value = (unsigned int)dvalue;
} }
} }
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
result_t ret = checkValueRange(value);
if (ret != RESULT_OK) {
return ret;
} }
*output = value; *output = value;
return RESULT_OK; return RESULT_OK;
} }
result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input, result_t NumberDataType::parseInput(const string inputStr, unsigned int* parsedValue) const {
SymbolString* output, size_t* usedLength) const {
unsigned int value; unsigned int value;
const string inputStr = input->str();
if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) { if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) {
value = m_replacement; // replacement value value = m_replacement; // replacement value
} else if (inputStr.empty()) { } else if (inputStr.empty()) {
return RESULT_ERR_EOF; // input too short return RESULT_ERR_EOF; // input too short
} else if (hasFlag(EXP)) { // IEEE 754 binary32 } else {
if (hasFlag(EXP)) { // IEEE 754 binary32
const char* str = inputStr.c_str(); const char* str = inputStr.c_str();
char* strEnd = nullptr; char* strEnd = nullptr;
double dvalue = strtod(str, &strEnd); double dvalue = strtod(str, &strEnd);
if (strEnd == nullptr || strEnd == str || *strEnd != 0) { if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value return RESULT_ERR_INVALID_NUM; // invalid value
} }
if (m_divisor < 0) { if (m_divisor < 0) {
@@ -1134,25 +1205,32 @@ result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstrea
return RESULT_ERR_INVALID_NUM; return RESULT_ERR_INVALID_NUM;
} }
} else { } else {
unsigned int maxBit = m_bitCount != 32 ? 1 << m_bitCount : 0;
const char* str = inputStr.c_str(); const char* str = inputStr.c_str();
char* strEnd = nullptr; char* strEnd = nullptr;
if (m_divisor == 1) { if (m_divisor == 1) {
if (hasFlag(SIG)) { if (hasFlag(SIG)) {
long signedValue = strtol(str, &strEnd, 10); long signedValue = strtol(str, &strEnd, 0);
if (errno == ERANGE || (maxBit && (signedValue < -(maxBit/2L) || signedValue >= maxBit/2L))) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
}
if (signedValue < 0 && m_bitCount != 32) { if (signedValue < 0 && m_bitCount != 32) {
value = (unsigned int)(signedValue + (1 << m_bitCount)); value = (unsigned int)(signedValue + maxBit);
} else { } else {
value = (unsigned int)signedValue; value = (unsigned int)signedValue;
} }
} else { } else {
value = (unsigned int)strtoul(str, &strEnd, 10); value = (unsigned int)strtoul(str, &strEnd, 0);
if (errno == ERANGE || (maxBit && value >= maxBit)) {
return RESULT_ERR_OUT_OF_RANGE;
}
} }
if (strEnd == nullptr || strEnd == str || (*strEnd != 0 && *strEnd != '.')) { if (strEnd == nullptr || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
return RESULT_ERR_INVALID_NUM; // invalid value return RESULT_ERR_INVALID_NUM; // invalid value
} }
} else { } else {
double dvalue = strtod(str, &strEnd); double dvalue = strtod(str, &strEnd);
if (strEnd == nullptr || strEnd == str || *strEnd != 0) { if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
return RESULT_ERR_INVALID_NUM; // invalid value return RESULT_ERR_INVALID_NUM; // invalid value
} }
if (m_divisor < 0) { if (m_divisor < 0) {
@@ -1161,8 +1239,8 @@ result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstrea
dvalue = round(dvalue * m_divisor); dvalue = round(dvalue * m_divisor);
} }
if (hasFlag(SIG)) { if (hasFlag(SIG)) {
if (dvalue < -exp2((8 * static_cast<double>(length)) - 1) double max = exp2(m_bitCount - 1);
|| dvalue >= exp2((8 * static_cast<double>(length)) - 1)) { if (dvalue < -max || dvalue >= max) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
if (dvalue < 0 && m_bitCount != 32) { if (dvalue < 0 && m_bitCount != 32) {
@@ -1171,26 +1249,30 @@ result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstrea
value = static_cast<int>(dvalue); value = static_cast<int>(dvalue);
} }
} else { } else {
if (dvalue < 0.0 || dvalue >= exp2(8 * static_cast<double>(length))) { if (dvalue < 0.0 || dvalue >= exp2(m_bitCount)) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
value = (unsigned int)dvalue; value = (unsigned int)dvalue;
} }
} }
if (hasFlag(SIG)) { // signed value
if ((value & (1 << (m_bitCount - 1))) != 0) { // negative signed value
if (value < m_minValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
} else if (value > m_maxValue) { result_t ret = checkValueRange(value);
return RESULT_ERR_OUT_OF_RANGE; // value out of range if (ret != RESULT_OK) {
return ret;
} }
} else if (value < m_minValue || value > m_maxValue) {
return RESULT_ERR_OUT_OF_RANGE; // value out of range
} }
*parsedValue = value;
return RESULT_OK;
} }
result_t NumberDataType::writeSymbols(size_t offset, size_t length, istringstream* input,
SymbolString* output, size_t* usedLength) const {
unsigned int value;
const string inputStr = input->str();
result_t ret = parseInput(inputStr, &value);
if (ret != RESULT_OK) {
return ret;
}
return writeRawValue(value, offset, length, output, usedLength); return writeRawValue(value, offset, length, output, usedLength);
} }
@@ -1207,6 +1289,7 @@ DataTypeList::DataTypeList() {
// unsigned decimal in BCD, 0000 - 9999 (fixed length) // unsigned decimal in BCD, 0000 - 9999 (fixed length)
add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1)); add(new NumberDataType("PIN", 16, FIX|BCD|REV, 0xffff, 0, 0x9999, 1));
add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254 add(new NumberDataType("UCH", 8, 0, 0xff, 0, 0xfe, 1)); // unsigned integer, 0 - 254
add(new NumberDataType("U1L", 8, REQ, 0, 0, 0xff, 1)); // unsigned 1-byte, 0 - 255 (no replacement)
add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data add(new StringDataType("IGN", MAX_LEN*8, IGN|ADJ, 0)); // >= 1 byte ignored data
// >= 1 byte character string filled up with 0x00 (null terminated string) // >= 1 byte character string filled up with 0x00 (null terminated string)
add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0)); add(new StringDataType("NTS", MAX_LEN*8, ADJ, 0));
@@ -1264,6 +1347,7 @@ DataTypeList::DataTypeList() {
add(new NumberDataType("HCD:2", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999 add(new NumberDataType("HCD:2", 16, HCD|BCD|REQ, 0, 0, 9999, 1)); // unsigned decimal in HCD, 0 - 9999
add(new NumberDataType("HCD:3", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999 add(new NumberDataType("HCD:3", 24, HCD|BCD|REQ, 0, 0, 999999, 1)); // unsigned decimal in HCD, 0 - 999999
add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127 add(new NumberDataType("SCH", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
add(new NumberDataType("S1L", 8, SIG|REQ, 0, 0x80, 0x7f, 1)); // signed integer, -128 - +127 (no replacement)
add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127 add(new NumberDataType("D1B", 8, SIG, 0x80, 0x81, 0x7f, 1)); // signed integer, -127 - +127
// unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff) // unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2)); add(new NumberDataType("D1C", 8, 0, 0xff, 0x00, 0xc8, 2));
@@ -1283,26 +1367,50 @@ DataTypeList::DataTypeList() {
add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1)); add(new NumberDataType("UIN", 16, 0, 0xffff, 0, 0xfffe, 1));
// unsigned integer, 0 - 65534, big endian // unsigned integer, 0 - 65534, big endian
add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1)); add(new NumberDataType("UIR", 16, REV, 0xffff, 0, 0xfffe, 1));
// unsigned integer, 0 - 65535, little endian (no replacement)
add(new NumberDataType("U2L", 16, REQ, 0, 0, 0xffff, 1));
// unsigned integer, 0 - 65535, big endian (no replacement)
add(new NumberDataType("U2B", 16, REQ|REV, 0, 0, 0xffff, 1));
// signed integer, -32767 - +32767, little endian // signed integer, -32767 - +32767, little endian
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1)); add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
// signed integer, -32767 - +32767, big endian // signed integer, -32767 - +32767, big endian
add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1)); add(new NumberDataType("SIR", 16, SIG|REV, 0x8000, 0x8001, 0x7fff, 1));
// signed integer, -32768 - +32767, little endian (no replacement)
add(new NumberDataType("S2L", 16, SIG|REQ, 0, 0x8000, 0x7fff, 1));
// signed integer, -32768 - +32767, big endian (no replacement)
add(new NumberDataType("S2B", 16, SIG|REQ|REV, 0, 0x8000, 0x7fff, 1));
// unsigned 3 bytes int, 0 - 16777214, little endian // unsigned 3 bytes int, 0 - 16777214, little endian
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1)); add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
// unsigned 3 bytes int, 0 - 16777214, big endian // unsigned 3 bytes int, 0 - 16777214, big endian
add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1)); add(new NumberDataType("U3R", 24, REV, 0xffffff, 0, 0xfffffe, 1));
// unsigned 3 bytes int, 0 - 16777215, little endian (no replacement)
add(new NumberDataType("U3L", 24, REQ, 0, 0, 0xffffff, 1));
// unsigned 3 bytes int, 0 - 16777215, big endian (no replacement)
add(new NumberDataType("U3B", 24, REQ|REV, 0, 0, 0xffffff, 1));
// signed 3 bytes int, -8388607 - +8388607, little endian // signed 3 bytes int, -8388607 - +8388607, little endian
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0x7fffff, 1)); add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0x7fffff, 1));
// signed 3 bytes int, -8388607 - +8388607, big endian // signed 3 bytes int, -8388607 - +8388607, big endian
add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0x7fffff, 1)); add(new NumberDataType("S3R", 24, SIG|REV, 0x800000, 0x800001, 0x7fffff, 1));
// signed 3 bytes int, -8388608 - +8388607, little endian (no replacement)
add(new NumberDataType("S3L", 24, SIG|REQ, 0, 0x800000, 0x7fffff, 1));
// signed 3 bytes int, -8388608 - +8388607, big endian (no replacement)
add(new NumberDataType("S3B", 24, SIG|REQ|REV, 0, 0x800000, 0x7fffff, 1));
// unsigned integer, 0 - 4294967294, little endian // unsigned integer, 0 - 4294967294, little endian
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1)); add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
// unsigned integer, 0 - 4294967294, big endian // unsigned integer, 0 - 4294967294, big endian
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1)); add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
// signed integer, -2147483647 - +2147483647, little endian // signed integer, -2147483647 - +2147483647, little endian
// unsigned integer, 0 - 4294967295, little endian (no replacement)
add(new NumberDataType("U4L", 32, REQ, 0, 0, 0xffffffff, 1));
// unsigned integer, 0 - 4294967295, big endian (no replacement)
add(new NumberDataType("U4B", 32, REQ|REV, 0, 0, 0xffffffff, 1));
add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0x7fffffff, 1)); add(new NumberDataType("SLG", 32, SIG, 0x80000000, 0x80000001, 0x7fffffff, 1));
// signed integer, -2147483647 - +2147483647, big endian // signed integer, -2147483647 - +2147483647, big endian
add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0x7fffffff, 1)); add(new NumberDataType("SLR", 32, SIG|REV, 0x80000000, 0x80000001, 0x7fffffff, 1));
// signed integer, -2147483648 - +2147483647, little endian (no replacement)
add(new NumberDataType("S4L", 32, SIG|REQ, 0, 0x80000000, 0x7fffffff, 1));
// signed integer, -2147483648 - +2147483647, big endian (no replacement)
add(new NumberDataType("S4B", 32, SIG|REQ|REV, 0, 0x80000000, 0x7fffffff, 1));
add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6) add(new NumberDataType("BI0", 7, ADJ|REQ, 0, 0, 1)); // bit 0 (up to 7 bits until bit 6)
add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7) add(new NumberDataType("BI1", 7, ADJ|REQ, 0, 1, 1)); // bit 1 (up to 7 bits until bit 7)
add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7) add(new NumberDataType("BI2", 6, ADJ|REQ, 0, 2, 1)); // bit 2 (up to 6 bits until bit 7)
@@ -1350,11 +1458,12 @@ void DataTypeList::clear() {
m_typesById.clear(); m_typesById.clear();
} }
result_t DataTypeList::add(const DataType* dataType) { result_t DataTypeList::add(const DataType* dataType, const string derivedKey) {
if (m_typesById.find(dataType->getId()) != m_typesById.end()) { string key = derivedKey.empty() ? dataType->getId() : derivedKey;
if (m_typesById.find(key) != m_typesById.end()) {
return RESULT_ERR_DUPLICATE_NAME; // duplicate key return RESULT_ERR_DUPLICATE_NAME; // duplicate key
} }
m_typesById[dataType->getId()] = dataType; m_typesById[key] = dataType;
m_cleanupTypes.push_back(dataType); m_cleanupTypes.push_back(dataType);
return RESULT_OK; return RESULT_OK;
} }
+55 -4
View File
@@ -481,7 +481,25 @@ class NumberDataType : public DataType {
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
unsigned int minValue, unsigned int maxValue, int divisor, unsigned int minValue, unsigned int maxValue, int divisor,
const NumberDataType* baseType = nullptr) const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), : DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_incValue(0),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {}
/**
* Constructs a new instance for multiple of 8 bits with increment value.
* @param id the type identifier.
* @param bitCount the number of bits (maximum length if #ADJ flag is set).
* @param flags the combination of flags (like #BCD).
* @param replacement the replacement value (no replacement if equal to minValue).
* @param minValue the minimum raw value.
* @param maxValue the maximum raw value.
* @param incValue the smallest step value for increment/decrement, or 0 for auto.
* @param divisor the divisor (negative for reciprocal).
* @param baseType the base @a NumberDataType for derived instances, or nullptr.
*/
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
unsigned int minValue, unsigned int maxValue, unsigned int incValue, int divisor,
const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(minValue), m_maxValue(maxValue), m_incValue(incValue),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {} m_divisor(divisor == 0 ? 1 : divisor), m_precision(calcPrecision(divisor)), m_firstBit(0), m_baseType(baseType) {}
/** /**
@@ -496,7 +514,7 @@ class NumberDataType : public DataType {
*/ */
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement, NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
int16_t firstBit, int divisor, const NumberDataType* baseType = nullptr) int16_t firstBit, int divisor, const NumberDataType* baseType = nullptr)
: DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), : DataType(id, bitCount, flags|NUM, replacement), m_minValue(0), m_maxValue((1 << bitCount)-1), m_incValue(0),
m_divisor(divisor == 0 ? 1 : divisor), m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {} m_divisor(divisor == 0 ? 1 : divisor), m_precision(0), m_firstBit(firstBit), m_baseType(baseType) {}
/** /**
@@ -527,6 +545,18 @@ class NumberDataType : public DataType {
*/ */
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;
/**
* Derive a new @a NumberDataType from this.
* @param min the minimum raw value.
* @param max the minimum raw value.
* @param inc the smallest step value for increment/decrement, or 0 to keep the current increment (or calculate
* automatically).
* @param derived the derived @a NumberDataType, or this if derivation is
* not necessary.
* @return @a RESULT_OK on success, or an error code.
*/
virtual result_t derive(unsigned int min, unsigned int max, unsigned int inc, const NumberDataType** derived) const;
/** /**
* @return the minimum raw value. * @return the minimum raw value.
*/ */
@@ -546,6 +576,14 @@ class NumberDataType : public DataType {
*/ */
result_t getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const; result_t getMinMax(bool getMax, const OutputFormat outputFormat, ostream* output) const;
/**
* Check the value against the minimum and maximum value.
* @param value the raw value.
* @param negative optional variable in which to store the negative flag.
* @return @a RESULT_OK on success, or an error code.
*/
result_t checkValueRange(unsigned int value, bool* negative = nullptr) const;
/** /**
* Get the smallest step value for increment/decrement. * Get the smallest step value for increment/decrement.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
@@ -598,10 +636,19 @@ class NumberDataType : public DataType {
* @param value the numeric raw value. * @param value the numeric raw value.
* @param outputFormat the @a OutputFormat options to use. * @param outputFormat the @a OutputFormat options to use.
* @param output the ostream to append the formatted value to. * @param output the ostream to append the formatted value to.
* @param skipRangeCheck whether to skip the value range check.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
*/ */
result_t readFromRawValue(unsigned int value, result_t readFromRawValue(unsigned int value,
OutputFormat outputFormat, ostream* output) const; OutputFormat outputFormat, ostream* output, bool skipRangeCheck = false) const;
/**
* Internal method for parsing an input string to the coorresponding raw value.
* @param inputStr the input string to parse the formatted value from.
* @param parsedValue the variable in which to store the parsed raw value.
* @return @a RESULT_OK on success, or an error code.
*/
result_t parseInput(const string inputStr, unsigned int* parsedValue) const;
/** /**
* Internal method for writing the numeric raw value to a @a SymbolString. * Internal method for writing the numeric raw value to a @a SymbolString.
@@ -628,6 +675,9 @@ class NumberDataType : public DataType {
/** the maximum raw value. */ /** the maximum raw value. */
const unsigned int m_maxValue; const unsigned int m_maxValue;
/** the smallest step value for increment/decrement, or 0 for auto. */
const unsigned int m_incValue;
/** the divisor (negative for reciprocal). */ /** the divisor (negative for reciprocal). */
const int m_divisor; const int m_divisor;
@@ -680,10 +730,11 @@ class DataTypeList {
/** /**
* Adds a @a DataType instance to this map. * Adds a @a DataType instance to this map.
* @param dataType the @a DataType instance to add. * @param dataType the @a DataType instance to add.
* @param derivedKey optional speicla key for derived instances.
* @return @a RESULT_OK on success, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller may not free the added instance on success. * Note: the caller may not free the added instance on success.
*/ */
result_t add(const DataType* dataType); result_t add(const DataType* dataType, const string derivedKey = "");
/** /**
* Adds a @a DataType instance for later cleanup. * Adds a @a DataType instance for later cleanup.
+64 -4
View File
@@ -53,15 +53,18 @@ void verify(bool expectFailMatch, string type, string input,
class TestReader : public MappedFileReader { class TestReader : public MappedFileReader {
public: public:
TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest) TestReader(DataFieldTemplates* templates, bool isSet, bool isMasterDest, bool withRange)
: MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest), : MappedFileReader::MappedFileReader(true), m_templates(templates), m_isSet(isSet), m_isMasterDest(isMasterDest),
m_fields(nullptr) {} m_withRange(withRange), m_fields(nullptr) {}
result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override { result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override {
if (row->empty()) { if (row->empty()) {
row->push_back("*name"); row->push_back("*name");
row->push_back("part"); row->push_back("part");
row->push_back("type"); row->push_back("type");
row->push_back("divisor/values"); row->push_back("divisor/values");
if (m_withRange) {
row->push_back("range");
}
row->push_back("unit"); row->push_back("unit");
row->push_back("comment"); row->push_back("comment");
return RESULT_OK; return RESULT_OK;
@@ -86,6 +89,7 @@ class TestReader : public MappedFileReader {
const DataFieldTemplates* m_templates; const DataFieldTemplates* m_templates;
const bool m_isSet; const bool m_isSet;
const bool m_isMasterDest; const bool m_isMasterDest;
const bool m_withRange;
public: public:
const DataField* m_fields; const DataField* m_fields;
}; };
@@ -101,7 +105,7 @@ int main() {
// entry: definition, decoded value, master data, slave data, flags // entry: definition, decoded value, master data, slave data, flags
// definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]] // definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
unsigned int baseLine = __LINE__+1; unsigned int baseLine = __LINE__+1;
string checks[][5] = { string checks[][6] = {
{"x,,ign:10", "", "10fe07000a00000000000000000000", "00", ""}, {"x,,ign:10", "", "10fe07000a00000000000000000000", "00", ""},
{"x,,ign:*", "", "10fe07000a00000000000000000000", "00", "W"}, {"x,,ign:*", "", "10fe07000a00000000000000000000", "00", "W"},
{"x,,ign,2", "", "", "", "c"}, {"x,,ign,2", "", "", "", "c"},
@@ -344,6 +348,13 @@ int main() {
{"x,,uch,==48", "", "10feffff01ab", "00", "rW"}, {"x,,uch,==48", "", "10feffff01ab", "00", "rW"},
{"x,,uch,=48", "", "10feffff0130", "00", ""}, {"x,,uch,=48", "", "10feffff0130", "00", ""},
{"x,,uch,==48", "", "10feffff0130", "00", ""}, {"x,,uch,==48", "", "10feffff0130", "00", ""},
{"x,,uch,,1-3", "2", "10feffff0102", "00", "-"},
{"x,,uch,,1-3", "4", "10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,uch,,1-3", "2", "10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,uch,,0x1-0x3", "4","10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,uch,,0x1-0x3", "2","10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,uch", "\n \"x\": {\"value\": 2}", "10feffff0102", "00", "-jV", "\n { \"name\": \"x\", \"slave\": false, \"type\": \"UCH\", \"isbits\": false, \"isadjustable\": false, \"isignored\": false, \"isreverse\": false, \"length\": 1, \"result\": \"number\", \"min\": 0, \"max\": 254, \"step\": 1, \"unit\": \"\", \"comment\": \"\"}"},
{"x,,uch,,1-3:2", "\n \"x\": {\"value\": 2}", "10feffff0102", "00", "-jV", "\n { \"name\": \"x\", \"slave\": false, \"type\": \"UCH\", \"isbits\": false, \"isadjustable\": false, \"isignored\": false, \"isreverse\": false, \"length\": 1, \"result\": \"number\", \"min\": 1, \"max\": 3, \"step\": 2, \"unit\": \"\", \"comment\": \"\"}"},
{"x,,sch", "-90", "10feffff01a6", "00", ""}, {"x,,sch", "-90", "10feffff01a6", "00", ""},
{"x,,sch", "0", "10feffff0100", "00", ""}, {"x,,sch", "0", "10feffff0100", "00", ""},
{"x,,sch", "-1", "10feffff01ff", "00", ""}, {"x,,sch", "-1", "10feffff01ff", "00", ""},
@@ -352,6 +363,15 @@ int main() {
{"x,,sch", "127", "10feffff017f", "00", ""}, {"x,,sch", "127", "10feffff017f", "00", ""},
{"x,,sch,10", "-9.0", "10feffff01a6", "00", ""}, {"x,,sch,10", "-9.0", "10feffff01a6", "00", ""},
{"x,,sch,-10", "-900", "10feffff01a6", "00", ""}, {"x,,sch,-10", "-900", "10feffff01a6", "00", ""},
{"x,,sch,,1-3", "2", "10feffff0102", "00", "-"},
{"x,,sch,,1-500", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-130-1", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-127-127", "-", "10feffff0180", "00", "-"},
{"x,,sch,,-127-128", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,-128-127", "-", "10feffff0180", "00", "-c"},
{"x,,sch,,1-3", "4", "10feffff0102", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,sch,,1-3", "2", "10feffff0104", "00", "-rW:ERR: argument value out of valid range"},
{"x,,sch,,-3--1", "-4", "10feffff01fe", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,d1b", "-90", "10feffff01a6", "00", ""}, {"x,,d1b", "-90", "10feffff01a6", "00", ""},
{"x,,d1b", "0", "10feffff0100", "00", ""}, {"x,,d1b", "0", "10feffff0100", "00", ""},
{"x,,d1b", "-1", "10feffff01ff", "00", ""}, {"x,,d1b", "-1", "10feffff01ff", "00", ""},
@@ -429,6 +449,12 @@ int main() {
{"x,,flt", "-", "10feffff020080", "00", ""}, {"x,,flt", "-", "10feffff020080", "00", ""},
{"x,,flt", "-32.767", "10feffff020180", "00", ""}, {"x,,flt", "-32.767", "10feffff020180", "00", ""},
{"x,,flt", "32.767", "10feffff02ff7f", "00", ""}, {"x,,flt", "32.767", "10feffff02ff7f", "00", ""},
{"x,,flt,,1-3", "2.000", "10feffff02d007", "00", "-"},
{"x,,flt,,1-3", "4.000", "10feffff02d007", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,flt,,1-3", "2.000", "10feffff02a00f", "00", "-rW:ERR: argument value out of valid range"},
{"x,,flt,,-3--1", "-4", "10feffff0230f8", "00", "-Rw:ERR: argument value out of valid range"}, // -4:60f0, -2:30f8
{"x,,flt,,-3.1--1.0", "-4", "10feffff0230f8", "00", "-Rw:ERR: argument value out of valid range"},
{"x,,flt,,-3.1--1.0", "-2", "10feffff0260f0", "00", "-rW:ERR: argument value out of valid range"},
{"x,,flr", "-0.090", "10feffff02ffa6", "00", ""}, {"x,,flr", "-0.090", "10feffff02ffa6", "00", ""},
{"x,,flr", "0.000", "10feffff020000", "00", ""}, {"x,,flr", "0.000", "10feffff020000", "00", ""},
{"x,,flr", "-0.001", "10feffff02ffff", "00", ""}, {"x,,flr", "-0.001", "10feffff02ffff", "00", ""},
@@ -445,6 +471,11 @@ int main() {
{"x,,exp", "0.25", "10feffff040000803e", "00", ""}, {"x,,exp", "0.25", "10feffff040000803e", "00", ""},
{"x,,exp", "0.95", "10feffff043333733f", "00", ""}, {"x,,exp", "0.95", "10feffff043333733f", "00", ""},
{"x,,exp", "0.65", "10feffff046666263f", "00", ""}, {"x,,exp", "0.65", "10feffff046666263f", "00", ""},
{"x,,exp", "0.065", "10feffff04b81e853d", "00", ""},
{"x,,exp,,0-0.65", "0.65", "10feffff046666263f", "00", "-"},
{"x,,exp,,0-0.5", "0.65", "10feffff046666263f", "00", "-rw:ERR: argument value out of valid range"},
{"x,,exp,10,0-0.065", "0.0650000", "10feffff046666263f", "00", "-"},
{"x,,exp,10,0-0.05", "0.0650000", "10feffff046666263f", "00", "-rw:ERR: argument value out of valid range"},
{"x,,exr", "-0.09", "10feffff04bdb851ec", "00", ""}, {"x,,exr", "-0.09", "10feffff04bdb851ec", "00", ""},
{"x,,exr", "0.0", "10feffff0400000000", "00", ""}, {"x,,exr", "0.0", "10feffff0400000000", "00", ""},
{"x,,exr", "-0.001", "10feffff04ba83126f", "00", ""}, {"x,,exr", "-0.001", "10feffff04ba83126f", "00", ""},
@@ -577,6 +608,12 @@ int main() {
continue; continue;
} }
string flags = check[4]; string flags = check[4];
size_t colon = flags.find(':');
string errStr;
if (colon != string::npos) {
errStr = flags.substr(colon+1);
flags = flags.substr(0, colon);
}
bool isSet = flags.find('s') != string::npos; bool isSet = flags.find('s') != string::npos;
bool testFields = flags.find('F') != string::npos; bool testFields = flags.find('F') != string::npos;
bool failedCreate = flags.find('c') != string::npos; bool failedCreate = flags.find('c') != string::npos;
@@ -584,6 +621,7 @@ int main() {
bool failedReadMatch = flags.find('R') != string::npos; bool failedReadMatch = flags.find('R') != string::npos;
bool failedWrite = flags.find('w') != string::npos; bool failedWrite = flags.find('w') != string::npos;
bool failedWriteMatch = flags.find('W') != string::npos; bool failedWriteMatch = flags.find('W') != string::npos;
string withDump = check[5]; // optional
const char* findName = flags.find('I') == string::npos ? nullptr : "x"; const char* findName = flags.find('I') == string::npos ? nullptr : "x";
ssize_t findIndex = -1; ssize_t findIndex = -1;
if (flags.find('i') != string::npos) { if (flags.find('i') != string::npos) {
@@ -599,6 +637,9 @@ int main() {
if (flags.find("vvv") != string::npos) { if (flags.find("vvv") != string::npos) {
verbosity |= OF_COMMENTS; verbosity |= OF_COMMENTS;
} }
if (flags.find("V") != string::npos) {
verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS|OF_ALL_ATTRS;
}
if (flags.find('j') != string::npos) { if (flags.find('j') != string::npos) {
verbosity |= OF_JSON; verbosity |= OF_JSON;
} }
@@ -620,7 +661,8 @@ int main() {
} }
continue; continue;
} }
TestReader reader{templates, isSet, mstr[1] == BROADCAST || isMaster(mstr[1])}; bool withRange = flags.find('-') != string::npos;
TestReader reader{templates, isSet, mstr[1] == BROADCAST || isMaster(mstr[1]), withRange};
lineNo = 0; lineNo = 0;
dummystr.clear(); dummystr.clear();
dummystr.str("#"); dummystr.str("#");
@@ -638,6 +680,9 @@ int main() {
if (result == RESULT_OK) { if (result == RESULT_OK) {
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl; cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
error = true; error = true;
} else if (!errStr.empty() && errorDescription != errStr) {
cout << "\"" << check[0] << "\": failed create error: unexpected result \"" << errorDescription << "\" instead of \"" << errStr << "\"" << endl;
error = true;
} else { } else {
cout << "\"" << check[0] << "\": failed create OK" << endl; cout << "\"" << check[0] << "\": failed create OK" << endl;
} }
@@ -680,6 +725,10 @@ int main() {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpectedly succeeded" << endl; << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else if (!errStr.empty() && getResultCode(result) != errStr) {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< error: unexpected result \"";
cout << getResultCode(result) << "\" instead of \"" << errStr << "\"" << endl;
} else { } else {
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3] cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
<< "< OK" << endl; << "< OK" << endl;
@@ -744,6 +793,10 @@ int main() {
cout << " failed write " << fields->getName(-1) << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< error: unexpectedly succeeded" << endl; << expectStr << "< error: unexpectedly succeeded" << endl;
error = true; error = true;
} else if (!errStr.empty() && getResultCode(result) != errStr) {
cout << " failed write " << fields->getName(-1) << " >"
<< "< error: unexpected result \"";
cout << getResultCode(result) << "\" instead of \"" << errStr << "\"" << endl;
} else { } else {
cout << " failed write " << fields->getName(-1) << " >" cout << " failed write " << fields->getName(-1) << " >"
<< expectStr << "< OK" << endl; << expectStr << "< OK" << endl;
@@ -760,6 +813,13 @@ int main() {
writeMstr.getStr() + " " + writeSstr.getStr()); writeMstr.getStr() + " " + writeSstr.getStr());
} }
} }
if (!withDump.empty()) {
output.clear();
output.str("");
fields->dump(false, verbosity, &output);
bool match = output.str() == withDump;
verify(false, "dump", withDump, match, withDump, output.str());
}
delete fields; delete fields;
fields = nullptr; fields = nullptr;
} }