add value range and step support, fix value list validation
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
if (value < getMinValue() || value > getMaxValue()) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
result_t ret = checkValueRange(value);
|
||||
if (ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
return writeRawValue(value, offset, length, output, usedLength);
|
||||
}
|
||||
|
||||
+64
-6
@@ -273,6 +273,7 @@ result_t DataField::create(bool isWriteMessage, bool isTemplate, bool isBroadcas
|
||||
|
||||
string divisorStr = pluck("divisor", &row);
|
||||
string valuesStr = pluck("values", &row);
|
||||
string rangeStr = pluck("range", &row);
|
||||
if (divisorStr.empty() && valuesStr.empty()) {
|
||||
divisorStr = pluck("divisor/values", &row); // [divisor|values]
|
||||
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);
|
||||
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) {
|
||||
result = RESULT_ERR_NOTFOUND;
|
||||
*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);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (values->begin()->first < numType->getMinValue() || values->rbegin()->first > numType->getMaxValue()) {
|
||||
return RESULT_ERR_OUT_OF_RANGE;
|
||||
for (auto& it : *values) {
|
||||
result_t ret = numType->checkValueRange(it.first);
|
||||
if (ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
*returnField = new ValueListDataField(name, attributes, numType, partType, byteCount, *values);
|
||||
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);
|
||||
if (!values.empty()) {
|
||||
if (values.begin()->first < num->getMinValue() || values.rbegin()->first > num->getMaxValue()) {
|
||||
return RESULT_ERR_INVALID_ARG; // cannot use divisor != 1 for value list field
|
||||
for (auto& it : values) {
|
||||
result_t ret = num->checkValueRange(it.first);
|
||||
if (ret != RESULT_OK) {
|
||||
return RESULT_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
fields->push_back(new ValueListDataField(useName, *attributes,
|
||||
num, partType, m_length, values));
|
||||
@@ -922,8 +980,8 @@ result_t ConstantDataField::readSymbols(const SymbolString& input, size_t offset
|
||||
if (result != RESULT_OK) {
|
||||
return result;
|
||||
}
|
||||
string value = coutput.str();
|
||||
FileReader::trim(&value);
|
||||
string value = coutput.str();
|
||||
FileReader::trim(&value);
|
||||
if (m_verify) {
|
||||
if (value != m_value) {
|
||||
return RESULT_ERR_OUT_OF_RANGE;
|
||||
|
||||
+247
-138
@@ -700,8 +700,16 @@ bool NumberDataType::dump(OutputFormat outputFormat, size_t length, AppendDiviso
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
if (ret && (outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
|
||||
*output << ", \"precision\": " << static_cast<unsigned>(getPrecision());
|
||||
if ((outputFormat & OF_JSON) && (outputFormat & OF_ALL_ATTRS)) {
|
||||
if (ret) {
|
||||
*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;
|
||||
}
|
||||
@@ -747,23 +755,119 @@ result_t NumberDataType::derive(int divisor, size_t bitCount, const NumberDataTy
|
||||
} else {
|
||||
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) {
|
||||
*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,
|
||||
m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
|
||||
}
|
||||
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) {
|
||||
*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,
|
||||
m_minValue, m_maxValue, divisor, m_baseType ? m_baseType : this);
|
||||
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);
|
||||
}
|
||||
DataTypeList::getInstance()->addCleanup(*derived);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
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 {
|
||||
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,
|
||||
@@ -830,22 +934,10 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
return RESULT_EMPTY;
|
||||
}
|
||||
|
||||
bool negative;
|
||||
if (hasFlag(SIG)) { // signed value
|
||||
negative = (value & (1 << (m_bitCount - 1))) != 0;
|
||||
if (!hasFlag(EXP)) {
|
||||
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;
|
||||
bool negative = false;
|
||||
result_t ret = checkValueRange(value, &negative);
|
||||
if (ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
int signedValue;
|
||||
if (m_bitCount == 32) {
|
||||
@@ -865,7 +957,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
val /= static_cast<float>(m_divisor);
|
||||
}
|
||||
}
|
||||
*output = static_cast<float>(val);
|
||||
*output = val;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (!negative) {
|
||||
@@ -895,7 +987,7 @@ result_t NumberDataType::getFloatFromRawValue(unsigned int value, float* output)
|
||||
}
|
||||
|
||||
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);
|
||||
// initialize output
|
||||
*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;
|
||||
}
|
||||
|
||||
bool negative;
|
||||
if (hasFlag(SIG)) { // signed value
|
||||
negative = (value & (1 << (m_bitCount - 1))) != 0;
|
||||
if (!hasFlag(EXP)) {
|
||||
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;
|
||||
bool negative = false;
|
||||
result_t ret = checkValueRange(value, &negative);
|
||||
if (!skipRangeCheck && ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
int signedValue;
|
||||
if (m_bitCount == 32) {
|
||||
@@ -1055,7 +1135,7 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
|
||||
} else {
|
||||
if (m_divisor == 1) {
|
||||
if (hasFlag(SIG)) {
|
||||
long signedValue = static_cast<long>(val); // TODO static_c?
|
||||
long signedValue = static_cast<long>(val);
|
||||
if (signedValue < 0 && m_bitCount != 32) {
|
||||
value = (unsigned int)(signedValue + (1 << m_bitCount));
|
||||
} else {
|
||||
@@ -1091,106 +1171,108 @@ result_t NumberDataType::getRawValueFromFloat(float val, unsigned int* output) c
|
||||
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;
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t NumberDataType::parseInput(const string inputStr, unsigned int* parsedValue) const {
|
||||
unsigned int value;
|
||||
|
||||
if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) {
|
||||
value = m_replacement; // replacement value
|
||||
} else if (inputStr.empty()) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
} else {
|
||||
if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
const char* str = inputStr.c_str();
|
||||
char* strEnd = nullptr;
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue /= -m_divisor;
|
||||
} else if (m_divisor > 1) {
|
||||
dvalue *= m_divisor;
|
||||
}
|
||||
value = floatToUint(static_cast<float>(dvalue));
|
||||
if (value == 0xffffffff) {
|
||||
return RESULT_ERR_INVALID_NUM;
|
||||
}
|
||||
} else {
|
||||
unsigned int maxBit = m_bitCount != 32 ? 1 << m_bitCount : 0;
|
||||
const char* str = inputStr.c_str();
|
||||
char* strEnd = nullptr;
|
||||
if (m_divisor == 1) {
|
||||
if (hasFlag(SIG)) {
|
||||
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) {
|
||||
value = (unsigned int)(signedValue + maxBit);
|
||||
} else {
|
||||
value = (unsigned int)signedValue;
|
||||
}
|
||||
} else {
|
||||
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 != '.')) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
} else {
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (errno == ERANGE || strEnd == nullptr || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue = round(dvalue / -m_divisor);
|
||||
} else {
|
||||
dvalue = round(dvalue * m_divisor);
|
||||
}
|
||||
if (hasFlag(SIG)) {
|
||||
double max = exp2(m_bitCount - 1);
|
||||
if (dvalue < -max || dvalue >= max) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
if (dvalue < 0 && m_bitCount != 32) {
|
||||
value = static_cast<int>(dvalue + (1 << m_bitCount));
|
||||
} else {
|
||||
value = static_cast<int>(dvalue);
|
||||
}
|
||||
} else {
|
||||
if (dvalue < 0.0 || dvalue >= exp2(m_bitCount)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
value = (unsigned int)dvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
result_t ret = checkValueRange(value);
|
||||
if (ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
*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();
|
||||
if (!hasFlag(REQ) && (isIgnored() || inputStr == NULL_VALUE)) {
|
||||
value = m_replacement; // replacement value
|
||||
} else if (inputStr.empty()) {
|
||||
return RESULT_ERR_EOF; // input too short
|
||||
} else if (hasFlag(EXP)) { // IEEE 754 binary32
|
||||
const char* str = inputStr.c_str();
|
||||
char* strEnd = nullptr;
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue /= -m_divisor;
|
||||
} else if (m_divisor > 1) {
|
||||
dvalue *= m_divisor;
|
||||
}
|
||||
value = floatToUint(static_cast<float>(dvalue));
|
||||
if (value == 0xffffffff) {
|
||||
return RESULT_ERR_INVALID_NUM;
|
||||
}
|
||||
} else {
|
||||
const char* str = inputStr.c_str();
|
||||
char* strEnd = nullptr;
|
||||
if (m_divisor == 1) {
|
||||
if (hasFlag(SIG)) {
|
||||
long signedValue = strtol(str, &strEnd, 10);
|
||||
if (signedValue < 0 && m_bitCount != 32) {
|
||||
value = (unsigned int)(signedValue + (1 << m_bitCount));
|
||||
} else {
|
||||
value = (unsigned int)signedValue;
|
||||
}
|
||||
} else {
|
||||
value = (unsigned int)strtoul(str, &strEnd, 10);
|
||||
}
|
||||
if (strEnd == nullptr || strEnd == str || (*strEnd != 0 && *strEnd != '.')) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
} else {
|
||||
double dvalue = strtod(str, &strEnd);
|
||||
if (strEnd == nullptr || strEnd == str || *strEnd != 0) {
|
||||
return RESULT_ERR_INVALID_NUM; // invalid value
|
||||
}
|
||||
if (m_divisor < 0) {
|
||||
dvalue = round(dvalue / -m_divisor);
|
||||
} else {
|
||||
dvalue = round(dvalue * m_divisor);
|
||||
}
|
||||
if (hasFlag(SIG)) {
|
||||
if (dvalue < -exp2((8 * static_cast<double>(length)) - 1)
|
||||
|| dvalue >= exp2((8 * static_cast<double>(length)) - 1)) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
if (dvalue < 0 && m_bitCount != 32) {
|
||||
value = static_cast<int>(dvalue + (1 << m_bitCount));
|
||||
} else {
|
||||
value = static_cast<int>(dvalue);
|
||||
}
|
||||
} else {
|
||||
if (dvalue < 0.0 || dvalue >= exp2(8 * static_cast<double>(length))) {
|
||||
return RESULT_ERR_OUT_OF_RANGE; // value out of range
|
||||
}
|
||||
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 = parseInput(inputStr, &value);
|
||||
if (ret != RESULT_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return writeRawValue(value, offset, length, output, usedLength);
|
||||
}
|
||||
|
||||
@@ -1207,6 +1289,7 @@ DataTypeList::DataTypeList() {
|
||||
// unsigned decimal in BCD, 0000 - 9999 (fixed length)
|
||||
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("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
|
||||
// >= 1 byte character string filled up with 0x00 (null terminated string)
|
||||
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: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("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
|
||||
// unsigned number (fraction 1/2), 0 - 100 (0x00 - 0xc8, replacement 0xff)
|
||||
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));
|
||||
// unsigned integer, 0 - 65534, big endian
|
||||
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
|
||||
add(new NumberDataType("SIN", 16, SIG, 0x8000, 0x8001, 0x7fff, 1));
|
||||
// signed integer, -32767 - +32767, big endian
|
||||
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
|
||||
add(new NumberDataType("U3N", 24, 0, 0xffffff, 0, 0xfffffe, 1));
|
||||
// unsigned 3 bytes int, 0 - 16777214, big endian
|
||||
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
|
||||
add(new NumberDataType("S3N", 24, SIG, 0x800000, 0x800001, 0x7fffff, 1));
|
||||
// signed 3 bytes int, -8388607 - +8388607, big endian
|
||||
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
|
||||
add(new NumberDataType("ULG", 32, 0, 0xffffffff, 0, 0xfffffffe, 1));
|
||||
// unsigned integer, 0 - 4294967294, big endian
|
||||
add(new NumberDataType("ULR", 32, REV, 0xffffffff, 0, 0xfffffffe, 1));
|
||||
// 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));
|
||||
// signed integer, -2147483647 - +2147483647, big endian
|
||||
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("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)
|
||||
@@ -1350,11 +1458,12 @@ void DataTypeList::clear() {
|
||||
m_typesById.clear();
|
||||
}
|
||||
|
||||
result_t DataTypeList::add(const DataType* dataType) {
|
||||
if (m_typesById.find(dataType->getId()) != m_typesById.end()) {
|
||||
result_t DataTypeList::add(const DataType* dataType, const string derivedKey) {
|
||||
string key = derivedKey.empty() ? dataType->getId() : derivedKey;
|
||||
if (m_typesById.find(key) != m_typesById.end()) {
|
||||
return RESULT_ERR_DUPLICATE_NAME; // duplicate key
|
||||
}
|
||||
m_typesById[dataType->getId()] = dataType;
|
||||
m_typesById[key] = dataType;
|
||||
m_cleanupTypes.push_back(dataType);
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
+55
-4
@@ -481,7 +481,25 @@ class NumberDataType : public DataType {
|
||||
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
|
||||
unsigned int minValue, unsigned int maxValue, int divisor,
|
||||
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) {}
|
||||
|
||||
/**
|
||||
@@ -496,7 +514,7 @@ class NumberDataType : public DataType {
|
||||
*/
|
||||
NumberDataType(const string& id, size_t bitCount, uint16_t flags, unsigned int replacement,
|
||||
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) {}
|
||||
|
||||
/**
|
||||
@@ -527,6 +545,18 @@ class NumberDataType : public DataType {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -546,6 +576,14 @@ class NumberDataType : public DataType {
|
||||
*/
|
||||
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.
|
||||
* @param outputFormat the @a OutputFormat options to use.
|
||||
@@ -598,10 +636,19 @@ class NumberDataType : public DataType {
|
||||
* @param value the numeric raw value.
|
||||
* @param outputFormat the @a OutputFormat options to use.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
@@ -628,6 +675,9 @@ class NumberDataType : public DataType {
|
||||
/** the maximum raw value. */
|
||||
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). */
|
||||
const int m_divisor;
|
||||
|
||||
@@ -680,10 +730,11 @@ class DataTypeList {
|
||||
/**
|
||||
* Adds a @a DataType instance to this map.
|
||||
* @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.
|
||||
* 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.
|
||||
|
||||
@@ -53,15 +53,18 @@ void verify(bool expectFailMatch, string type, string input,
|
||||
|
||||
class TestReader : public MappedFileReader {
|
||||
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),
|
||||
m_fields(nullptr) {}
|
||||
m_withRange(withRange), m_fields(nullptr) {}
|
||||
result_t getFieldMap(const string& preferLanguage, vector<string>* 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");
|
||||
if (m_withRange) {
|
||||
row->push_back("range");
|
||||
}
|
||||
row->push_back("unit");
|
||||
row->push_back("comment");
|
||||
return RESULT_OK;
|
||||
@@ -86,6 +89,7 @@ class TestReader : public MappedFileReader {
|
||||
const DataFieldTemplates* m_templates;
|
||||
const bool m_isSet;
|
||||
const bool m_isMasterDest;
|
||||
const bool m_withRange;
|
||||
public:
|
||||
const DataField* m_fields;
|
||||
};
|
||||
@@ -101,7 +105,7 @@ int main() {
|
||||
// entry: definition, decoded value, master data, slave data, flags
|
||||
// definition: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
|
||||
unsigned int baseLine = __LINE__+1;
|
||||
string checks[][5] = {
|
||||
string checks[][6] = {
|
||||
{"x,,ign:10", "", "10fe07000a00000000000000000000", "00", ""},
|
||||
{"x,,ign:*", "", "10fe07000a00000000000000000000", "00", "W"},
|
||||
{"x,,ign,2", "", "", "", "c"},
|
||||
@@ -344,6 +348,13 @@ int main() {
|
||||
{"x,,uch,==48", "", "10feffff01ab", "00", "rW"},
|
||||
{"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", "0", "10feffff0100", "00", ""},
|
||||
{"x,,sch", "-1", "10feffff01ff", "00", ""},
|
||||
@@ -352,6 +363,15 @@ int main() {
|
||||
{"x,,sch", "127", "10feffff017f", "00", ""},
|
||||
{"x,,sch,10", "-9.0", "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", "0", "10feffff0100", "00", ""},
|
||||
{"x,,d1b", "-1", "10feffff01ff", "00", ""},
|
||||
@@ -429,6 +449,12 @@ int main() {
|
||||
{"x,,flt", "-", "10feffff020080", "00", ""},
|
||||
{"x,,flt", "-32.767", "10feffff020180", "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.000", "10feffff020000", "00", ""},
|
||||
{"x,,flr", "-0.001", "10feffff02ffff", "00", ""},
|
||||
@@ -445,6 +471,11 @@ int main() {
|
||||
{"x,,exp", "0.25", "10feffff040000803e", "00", ""},
|
||||
{"x,,exp", "0.95", "10feffff043333733f", "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.0", "10feffff0400000000", "00", ""},
|
||||
{"x,,exr", "-0.001", "10feffff04ba83126f", "00", ""},
|
||||
@@ -577,6 +608,12 @@ int main() {
|
||||
continue;
|
||||
}
|
||||
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 testFields = flags.find('F') != string::npos;
|
||||
bool failedCreate = flags.find('c') != string::npos;
|
||||
@@ -584,6 +621,7 @@ int main() {
|
||||
bool failedReadMatch = flags.find('R') != string::npos;
|
||||
bool failedWrite = 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";
|
||||
ssize_t findIndex = -1;
|
||||
if (flags.find('i') != string::npos) {
|
||||
@@ -599,6 +637,9 @@ int main() {
|
||||
if (flags.find("vvv") != string::npos) {
|
||||
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) {
|
||||
verbosity |= OF_JSON;
|
||||
}
|
||||
@@ -620,7 +661,8 @@ int main() {
|
||||
}
|
||||
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;
|
||||
dummystr.clear();
|
||||
dummystr.str("#");
|
||||
@@ -638,6 +680,9 @@ int main() {
|
||||
if (result == RESULT_OK) {
|
||||
cout << "\"" << check[0] << "\": failed create error: unexpectedly succeeded" << endl;
|
||||
error = true;
|
||||
} else if (!errStr.empty() && errorDescription != errStr) {
|
||||
cout << "\"" << check[0] << "\": failed create error: unexpected result \"" << errorDescription << "\" instead of \"" << errStr << "\"" << endl;
|
||||
error = true;
|
||||
} else {
|
||||
cout << "\"" << check[0] << "\": failed create OK" << endl;
|
||||
}
|
||||
@@ -680,6 +725,10 @@ int main() {
|
||||
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
|
||||
<< "< error: unexpectedly succeeded" << endl;
|
||||
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 {
|
||||
cout << " failed read " << fields->getName(-1) << " >" << check[2] << " " << check[3]
|
||||
<< "< OK" << endl;
|
||||
@@ -744,6 +793,10 @@ int main() {
|
||||
cout << " failed write " << fields->getName(-1) << " >"
|
||||
<< expectStr << "< error: unexpectedly succeeded" << endl;
|
||||
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 {
|
||||
cout << " failed write " << fields->getName(-1) << " >"
|
||||
<< expectStr << "< OK" << endl;
|
||||
@@ -760,6 +813,13 @@ int main() {
|
||||
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;
|
||||
fields = nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user