unified parsing of numeric values, documentation

This commit is contained in:
john30
2014-11-20 22:24:21 +01:00
parent 0283b0e121
commit 15cbb9bbd9
2 changed files with 51 additions and 44 deletions
+49 -42
View File
@@ -100,6 +100,31 @@ static const char* dayNames[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
#define NULL_VALUE "-" #define NULL_VALUE "-"
#define MAX_POS 16 #define MAX_POS 16
/**
* @brief Parse an unsigned int value.
* @param str the string to parse.
* @param base the numerical base.
* @param minValue the minimum resulting value.
* @param maxValue the maximum resulting value.
* @param result the variable in which to store an error code when parsing failed or the value is out of bounds.
*/
unsigned int parseInt(const char* str, int base, const unsigned int minValue, const unsigned int maxValue, result_t& result) {
char* strEnd = NULL;
unsigned int ret = strtoul(str, &strEnd, base);
if (strEnd == NULL || *strEnd != 0) {
result = RESULT_ERR_INVALID_ARG; // invalid value
return 0;
}
if (ret < minValue || ret > maxValue) {
result = RESULT_ERR_INVALID_ARG; // invalid value
return 0;
}
return ret;
}
result_t DataField::create(std::vector<std::string>::iterator& it, result_t DataField::create(std::vector<std::string>::iterator& it,
const std::vector<std::string>::iterator end, const std::vector<std::string>::iterator end,
const std::map< std::string, DataField*> templates, const std::map< std::string, DataField*> templates,
@@ -168,18 +193,9 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
if (++offsetCnt > 2) if (++offsetCnt > 2)
return RESULT_ERR_INVALID_ARG; //invalid pos definition return RESULT_ERR_INVALID_ARG; //invalid pos definition
const char* start = token.c_str(); unsigned int pos = parseInt(token.c_str(), 10, 1, MAX_POS + 1, result) - 1; // input is 1-based
char* end = NULL; if (result != RESULT_OK)
unsigned int pos = strtoul(start, &end, 10) - 1; // 1-based
if (end != start + strlen(start)) {
result = RESULT_ERR_INVALID_ARG; // invalid pos definition
break; break;
}
if (pos > MAX_POS) {
result = RESULT_ERR_INVALID_ARG; // invalid pos definition
break;
}
if (offsetCnt == 1) if (offsetCnt == 1)
offset = pos; offset = pos;
@@ -204,26 +220,22 @@ result_t DataField::create(std::vector<std::string>::iterator& it,
std::string divisorStr = *it++; std::string divisorStr = *it++;
if (divisorStr.empty() == false) { if (divisorStr.empty() == false) {
if (divisorStr.find_first_not_of("0123456789") == std::string::npos) { if (divisorStr.find_first_not_of("0123456789") == std::string::npos) {
const char* start = divisorStr.c_str(); divisor = parseInt(divisorStr.c_str(), 10, 1, 10000, result);
char* end = NULL; if (result != RESULT_OK)
divisor = strtoul(start, &end, 10);
if (end != start + strlen(start)) {
result = RESULT_ERR_INVALID_ARG;
break; break;
} }
}
else { else {
std::istringstream stream(divisorStr); std::istringstream stream(divisorStr);
while (std::getline(stream, token, VALUE_SEPARATOR) != 0) { while (std::getline(stream, token, VALUE_SEPARATOR) != 0) {
const char* start = token.c_str(); const char* str = token.c_str();
char* end = NULL; char* strEnd = NULL;
unsigned int id = strtoul(start, &end, 10); unsigned int id = strtoul(str, &strEnd, 10);
if (end == NULL || end == start || *end != '=') { if (strEnd == NULL || strEnd == str || *strEnd != '=') {
result = RESULT_ERR_INVALID_ARG; result = RESULT_ERR_INVALID_ARG;
break; break;
} }
values[id] = std::string(end + 1); values[id] = std::string(strEnd + 1);
} }
if (result != RESULT_OK) if (result != RESULT_OK)
break; break;
@@ -524,6 +536,7 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
incr = -1; incr = -1;
} }
result_t result;
size_t i = 0; size_t i = 0;
for (size_t offset = start; offset != end; offset += incr, i++) { for (size_t offset = start; offset != end; offset += incr, i++) {
switch (m_dataType.type) switch (m_dataType.type)
@@ -542,11 +555,10 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
if (input.eof() == true) if (input.eof() == true)
return RESULT_ERR_INVALID_ARG; // invalid hex value return RESULT_ERR_INVALID_ARG; // invalid hex value
str = token.c_str(); result_t result;
strEnd = NULL; value = parseInt(token.c_str(), 16, 0, 0xff, result);
value = strtoul(str, &strEnd, 16); if (result != RESULT_OK)
if (strEnd != str + strlen(str)) return result; // invalid hex value
return RESULT_ERR_INVALID_ARG; // invalid hex value
} }
break; break;
case bt_dat: case bt_dat:
@@ -554,11 +566,9 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
continue; // skip weekday in between continue; // skip weekday in between
if (std::getline(input, token, '.') == 0) if (std::getline(input, token, '.') == 0)
return RESULT_ERR_INVALID_ARG; // incomplete return RESULT_ERR_INVALID_ARG; // incomplete
str = token.c_str(); value = parseInt(token.c_str(), 10, 0, 9999, result);
strEnd = NULL; if (result != RESULT_OK)
value = strtoul(str, &strEnd, 10); return result; // invalid date part
if (strEnd != str + strlen(str))
return RESULT_ERR_INVALID_ARG; // invalid date part
if (i + 1 == m_length && value >= 2000) if (i + 1 == m_length && value >= 2000)
value -= 2000; value -= 2000;
else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12)) else if (value < 1 || (i == 0 && value > 31) || (i == 1 && value > 12))
@@ -567,12 +577,10 @@ result_t StringDataField::writeSymbols(std::istringstream& input,
case bt_tim: case bt_tim:
if (std::getline(input, token, ':') == 0) if (std::getline(input, token, ':') == 0)
return RESULT_ERR_INVALID_ARG; // incomplete return RESULT_ERR_INVALID_ARG; // incomplete
str = token.c_str(); value = parseInt(token.c_str(), 10, 0, 59, result);
strEnd = NULL; if (result != RESULT_OK)
value = strtoul(str, &strEnd, 10); return result; // invalid time part
if (strEnd != str + strlen(str)) if ((i == 0 && value > 24) || (i > 0 && ( last == 24 && value > 0) ))
return RESULT_ERR_INVALID_ARG; // invalid time part
if ((i == 0 && value > 24) || (i > 0 && (value > 59 || ( last == 24 && value > 0) )))
return RESULT_ERR_INVALID_ARG; // invalid time part return RESULT_ERR_INVALID_ARG; // invalid time part
if (m_length == 1) { // truncated time if (m_length == 1) { // truncated time
if (i == 0) { if (i == 0) {
@@ -775,11 +783,10 @@ result_t NumberDataField::writeSymbols(std::istringstream& input,
unsigned int value; unsigned int value;
const char* str = input.str().c_str(); const char* str = input.str().c_str();
size_t len = strlen(str);
if (strcasecmp(str, NULL_VALUE) == 0) if (strcasecmp(str, NULL_VALUE) == 0)
// replacement value // replacement value
value = m_dataType.replacement; value = m_dataType.replacement;
else if (len == 0) else if (str == NULL || *str == 0)
return RESULT_ERR_INVALID_ARG; // input too short return RESULT_ERR_INVALID_ARG; // input too short
else { else {
char* strEnd = NULL; char* strEnd = NULL;
@@ -793,13 +800,13 @@ result_t NumberDataField::writeSymbols(std::istringstream& input,
} }
else else
value = strtoul(str, &strEnd, 10); value = strtoul(str, &strEnd, 10);
if (strEnd != str + len) if (strEnd == NULL || *strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value return RESULT_ERR_INVALID_ARG; // invalid value
} }
else { else {
char* strEnd = NULL; char* strEnd = NULL;
double dvalue = strtod(str, &strEnd); double dvalue = strtod(str, &strEnd);
if (strEnd != str + len) if (strEnd == NULL || strEnd != 0)
return RESULT_ERR_INVALID_ARG; // invalid value return RESULT_ERR_INVALID_ARG; // invalid value
dvalue = round(dvalue * m_divisor); dvalue = round(dvalue * m_divisor);
if ((m_dataType.flags & SIG) != 0) { if ((m_dataType.flags & SIG) != 0) {
+2 -2
View File
@@ -88,11 +88,11 @@ public:
* @brief Factory method for creating new instances. * @brief Factory method for creating new instances.
* @param it the iterator to traverse for the definition parts. * @param it the iterator to traverse for the definition parts.
* @param end the iterator pointing to the end of the definition parts. * @param end the iterator pointing to the end of the definition parts.
* @param templates a map of DataField templates to be referenced by name. * @param templates a map of @a DataField templates to be referenced by name.
* @param returnField the variable in which to store the created instance. * @param returnField the variable in which to store the created instance.
* @param isSetMessage whether the field is part of a set message (default false). * @param isSetMessage whether the field is part of a set message (default false).
* @param dstAddress the destination bus address (default @a SYN for creating a template @a DataField). * @param dstAddress the destination bus address (default @a SYN for creating a template @a DataField).
* @return @a RESULT_OK on success, @a RESULT_ERR_EOF if the iterator is empty, or an error code. * @return @a RESULT_OK on success, or an error code.
* Note: the caller needs to free the created instance. * Note: the caller needs to free the created instance.
*/ */
static result_t create(std::vector<std::string>::iterator& it, const std::vector<std::string>::iterator end, static result_t create(std::vector<std::string>::iterator& it, const std::vector<std::string>::iterator end,