split verbosity into 3 levels for read and find, allow inline rename for template references, added "indexed" request parameter for JSON, formatted

This commit is contained in:
john30
2016-10-08 19:38:20 +02:00
parent 0b42490573
commit bb19e57bea
6 changed files with 187 additions and 105 deletions
+90 -66
View File
@@ -55,8 +55,8 @@ result_t DataField::create(vector<string>::iterator& it,
bool hasPartStr = false;
string token;
// template: name,type[:len][,[divisor|values][,[unit][,[comment]]]]
// std: name,part,type[:len][,[divisor|values][,[unit][,[comment]]]]
// template: name,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
// std: name,part,basetype[:len]|template[:name][,[divisor|values][,[unit][,[comment]]]]
const string name = *it++; // name
if (it == end) {
if (!name.empty())
@@ -64,9 +64,9 @@ result_t DataField::create(vector<string>::iterator& it,
break;
}
if (isTemplate)
if (isTemplate) {
partType = pt_any;
else {
} else {
const char* partStr = (*it++).c_str(); // part
hasPartStr = partStr[0] != 0;
if (it == end) {
@@ -78,12 +78,10 @@ result_t DataField::create(vector<string>::iterator& it,
|| (isWriteMessage && !hasPartStr)
|| strcasecmp(partStr, "M") == 0) { // master data
partType = pt_masterData;
}
else if ((!isWriteMessage && !hasPartStr)
} else if ((!isWriteMessage && !hasPartStr)
|| strcasecmp(partStr, "S") == 0) { // slave data
partType = pt_slaveData;
}
else {
} else {
result = RESULT_ERR_INVALID_PART;
break;
}
@@ -94,10 +92,11 @@ result_t DataField::create(vector<string>::iterator& it,
firstComment = comment;
}
const string typeStr = *it++; // type[:len]
const string typeStr = *it++; // basetype[:len]|template[:name]
if (typeStr.empty()) {
if (!name.empty() || hasPartStr)
if (!name.empty() || hasPartStr) {
result = RESULT_ERR_MISSING_TYPE;
}
break;
}
@@ -105,9 +104,9 @@ result_t DataField::create(vector<string>::iterator& it,
if (it != end) {
const string divisorStr = *it++; // [divisor|values]
if (!divisorStr.empty()) {
if (divisorStr.find('=') == string::npos)
if (divisorStr.find('=') == string::npos) {
divisor = parseSignedInt(divisorStr.c_str(), 10, -MAX_DIVISOR, MAX_DIVISOR, result);
else {
} else {
istringstream stream(divisorStr);
while (getline(stream, token, VALUE_SEPARATOR)) {
FileReader::trim(token);
@@ -135,29 +134,32 @@ result_t DataField::create(vector<string>::iterator& it,
values[(unsigned int)id] = token;
}
}
if (result != RESULT_OK)
if (result != RESULT_OK) {
break;
}
}
}
if (it == end)
if (it == end) {
unit = "";
else {
} else {
const string str = *it++; // [unit]
if (strcasecmp(str.c_str(), NULL_VALUE) == 0)
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
unit = "";
else
} else {
unit = str;
}
}
if (it == end)
if (it == end) {
comment = "";
else {
} else {
const string str = *it++; // [comment]
if (strcasecmp(str.c_str(), NULL_VALUE) == 0)
if (strcasecmp(str.c_str(), NULL_VALUE) == 0) {
comment = "";
else
} else {
comment = str;
}
}
bool firstType = true;
@@ -165,29 +167,44 @@ result_t DataField::create(vector<string>::iterator& it,
while (result == RESULT_OK && getline(stream, token, VALUE_SEPARATOR)) {
FileReader::trim(token);
DataField* templ = templates->get(token);
unsigned char length;
if (templ == NULL) {
size_t pos = token.find(LENGTH_SEPARATOR);
if (pos == string::npos)
size_t pos = token.find(LENGTH_SEPARATOR);
if (templ == NULL && pos != string::npos) {
templ = templates->get(token.substr(0, pos));
}
if (templ == NULL) { // basetype[:len]
unsigned char length;
string typeName;
if (pos == string::npos) {
length = 0; // no length specified
else if (pos+2==token.length() && token[pos+1]=='*') {
length = REMAIN_LEN;
typeName = token;
} else {
length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, maxFieldLength, result);
if (result != RESULT_OK)
break;
if (pos+2==token.length() && token[pos+1]=='*') {
length = REMAIN_LEN;
} else {
length = (unsigned char)parseInt(token.substr(pos+1).c_str(), 10, 1, maxFieldLength, result);
if (result != RESULT_OK) {
break;
}
}
typeName = token.substr(0, pos);
}
transform(token.begin(), token.end(), token.begin(), ::toupper);
string typeName = token.substr(0, pos);
transform(typeName.begin(), typeName.end(), typeName.begin(), ::toupper);
SingleDataField* add = NULL;
result = SingleDataField::create(typeName, length, firstType ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, add);
if (add != NULL)
if (add != NULL) {
fields.push_back(add);
else if (result == RESULT_OK)
} else if (result == RESULT_OK) {
result = RESULT_ERR_NOTFOUND; // type not found
} else {
}
} else { // template[:name]
string fieldName;
bool lastType = stream.eof();
result = templ->derive((firstType && lastType) ? name : "", firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields);
if (pos != string::npos) { // replacement name specified
fieldName = token.substr(pos+1);
} else {
fieldName = (firstType && lastType) ? name : "";
}
result = templ->derive(fieldName, firstType ? comment : "", firstType ? unit : "", partType, divisor, values, fields);
}
firstType = false;
}
@@ -201,9 +218,9 @@ result_t DataField::create(vector<string>::iterator& it,
return result;
}
if (fields.size() == 1)
if (fields.size() == 1) {
returnField = fields[0];
else {
} else {
returnField = new DataFieldSet(firstName, firstComment, fields);
}
return RESULT_OK;
@@ -211,8 +228,9 @@ result_t DataField::create(vector<string>::iterator& it,
void DataField::dumpString(ostream& output, const string str, const bool prependFieldSeparator)
{
if (prependFieldSeparator)
if (prependFieldSeparator) {
output << FIELD_SEPARATOR;
}
if (str.find_first_of(FIELD_SEPARATOR) == string::npos) {
output << str;
} else {
@@ -326,9 +344,9 @@ result_t SingleDataField::read(const PartType partType,
ostringstream& output, OutputFormat outputFormat, signed char outputIndex,
bool leadingSeparator, const char* fieldName, signed char fieldIndex)
{
if (partType != m_partType)
if (partType != m_partType) {
return RESULT_OK;
}
switch (m_partType)
{
case pt_masterData:
@@ -349,39 +367,44 @@ result_t SingleDataField::read(const PartType partType,
}
if (outputFormat & OF_JSON) {
if (leadingSeparator)
if (leadingSeparator) {
output << ",";
if (outputIndex>=0 || m_name.empty())
}
if (outputIndex>=0 || m_name.empty() || !(outputFormat & OF_NAMES)) {
output << "\n \"" << static_cast<signed int>(outputIndex<0?0:outputIndex) << "\": {\"name\": \"" << m_name << "\"" << ", \"value\": ";
else
} else {
output << "\n \"" << m_name << "\": {\"value\": ";
}
} else {
if (leadingSeparator)
if (leadingSeparator) {
output << UI_FIELD_SEPARATOR;
if (outputFormat & OF_VERBOSE)
}
if (outputFormat & OF_NAMES) {
output << m_name << "=";
}
}
result_t result = readSymbols(data, m_partType==pt_masterData, offset, output, outputFormat);
if (result != RESULT_OK)
if (result != RESULT_OK) {
return result;
if (outputFormat & OF_VERBOSE) {
if (m_unit.length() > 0) {
if (outputFormat & OF_JSON)
output << ", \"unit\": \"" << m_unit << '"';
else
output << " " << m_unit;
}
if (m_comment.length() > 0) {
if (outputFormat & OF_JSON)
output << ", \"comment\": \"" << m_comment << '"';
else
output << " [" << m_comment << "]";
}
if ((outputFormat & OF_UNITS) && m_unit.length() > 0) {
if (outputFormat & OF_JSON) {
output << ", \"unit\": \"" << m_unit << '"';
} else {
output << " " << m_unit;
}
}
if (outputFormat & OF_JSON)
if ((outputFormat & OF_COMMENTS) && m_comment.length() > 0) {
if (outputFormat & OF_JSON) {
output << ", \"comment\": \"" << m_comment << '"';
} else {
output << " [" << m_comment << "]";
}
}
if (outputFormat & OF_JSON) {
output << "}";
}
return RESULT_OK;
}
@@ -389,9 +412,9 @@ result_t SingleDataField::write(istringstream& input,
const PartType partType, SymbolString& data,
unsigned char offset, char separator, unsigned char* length)
{
if (partType != m_partType)
if (partType != m_partType) {
return RESULT_OK;
}
switch (m_partType)
{
case pt_masterData:
@@ -805,11 +828,12 @@ result_t DataFieldSet::read(const PartType partType,
if (!found) {
return RESULT_EMPTY;
}
if (m_comment.length() > 0 && (outputFormat & OF_VERBOSE)) {
if (outputFormat & OF_JSON)
if ((outputFormat & OF_COMMENTS) && m_comment.length() > 0) {
if (outputFormat & OF_JSON) {
output << ",\"comment\": \"" << m_comment << '"';
else
} else {
output << " [" << m_comment << "]";
}
}
return RESULT_OK;
+5 -3
View File
@@ -77,9 +77,11 @@ using namespace std;
typedef int OutputFormat;
/* the bit flags for @a OutputFormat. */
static const unsigned int OF_VERBOSE = 0x01; //!< verbose format (names, values, units, and comments).
static const unsigned int OF_NUMERIC = 0x02; //!< numeric format (keep numeric value of value=name pairs).
static const unsigned int OF_JSON = 0x04; //!< JSON format.
static const unsigned int OF_NAMES = 0x01; //!< include names.
static const unsigned int OF_UNITS = 0x02; //!< include units.
static const unsigned int OF_COMMENTS = 0x04; //!< include comments.
static const unsigned int OF_NUMERIC = 0x08; //!< numeric format (keep numeric value of value=name pairs).
static const unsigned int OF_JSON = 0x10; //!< JSON format.
/** the message part in which a data field is stored. */
enum PartType {
+27 -12
View File
@@ -365,16 +365,18 @@ int main()
{"x,,bi3:2,0=off;1=on","on", "10feffff0108", "00", ""},
{"x,,bi3:2,0=off;1=on","off","10feffff0100", "00", ""},
{"x,,bi3:2,0=off;1=on","1", "10feffff0108", "00", "n"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "v"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vn"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "j"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=on ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvv"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","x=1 ja/nein [Wahrheitswert]", "10feffff0108", "00", "vvvn"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\"}", "10feffff0108", "00", "vj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "vj"},
{",,bi3:2,0=off;1=on,ja/nein,Wahrheitswert", "\n \"0\": {\"name\": \"\", \"value\": \"on\"}", "10feffff0108", "00", "j"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1}", "10feffff0108", "00", "nj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": \"on\", \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1}", "10feffff0108", "00", "vnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"x\": {\"value\": 1, \"unit\": \"ja/nein\", \"comment\": \"Wahrheitswert\"}", "10feffff0108", "00", "vvvnj"},
{"x,,bi3:2,0=off;1=on,ja/nein,Wahrheitswert","\n \"0\": {\"name\": \"x\", \"value\": 1}", "10feffff0108", "00", "nj"},
{"x,,uch,1=test;2=high;3=off;0x10=on","on","10feffff0110", "00", ""},
{"x,s,uch","3","1050ffff00", "0103", ""},
{"x,,d2b,,°C,Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "v"},
{"x,,d2b,,°C,Aussentemperatur","x=18.004 °C [Aussentemperatur]","10fe0700090112", "00", "vvv"},
{"x,,bti,,,,y,,bda,,,,z,,bdy", "21:04:58;26.10.2014;Sun","10fe0700085804212610061406", "00", ""}, // combination
{"x,,bi3,,,,y,,bi5", "1;0", "10feffff0108", "00", ""}, // bit combination
{"x,,bi3,,,,y,,bi5", "1;1", "10feffff0128", "00", ""}, // bit combination
@@ -393,6 +395,8 @@ int main()
{"x,,trelrel","18.004;19.008","10fe07000401120213", "00", ""}, // reference to template struct
{"x,,temp,,,,y,,d1c","18.004;9.5","10fe070003011213", "00", ""}, // reference to template, normal def
{"x,,temp;HEX:2","18.004;13 14","10fe07000401121314", "00", ""}, // reference to template and base type
{"x,,temp;HEX:2","temp=18.004;=13 14","10fe07000401121314", "00", "v"}, // reference to template and base type
{"x,,temp:degrees;HEX:2","degrees=18.004;=13 14","10fe07000401121314", "00", "v"}, // reference to template and base type
};
DataFieldTemplates* templates = new DataFieldTemplates();
DataField* fields = NULL;
@@ -421,9 +425,20 @@ int main()
bool failedReadMatch = flags.find('R') != string::npos;
bool failedWrite = flags.find('w') != string::npos;
bool failedWriteMatch = flags.find('W') != string::npos;
bool verbose = flags.find('v') != string::npos;
OutputFormat verbosity = 0;
if (flags.find("v") != string::npos) {
verbosity |= OF_NAMES;
}
if (flags.find("vv") != string::npos) {
verbosity |= OF_UNITS;
}
if (flags.find("vvv") != string::npos) {
verbosity |= OF_COMMENTS;
}
if (flags.find('j') != string::npos) {
verbosity |= OF_JSON;
}
bool numeric = flags.find('n') != string::npos;
bool json = flags.find('j') != string::npos;
bool isTemplate = flags.find('t') != string::npos;
string item;
vector<string> entries;
@@ -490,9 +505,9 @@ int main()
cout << " parse \"" << sstr.getDataStr(true, false).substr(0, 2) << "\" error: " << getResultCode(result) << endl;
error = true;
}
result = fields->read(pt_masterData, mstr, 0, output, (verbose?OF_VERBOSE:0)|(numeric?OF_NUMERIC:0)|(json?OF_JSON:0), -1, false);
result = fields->read(pt_masterData, mstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, false);
if (result >= RESULT_OK) {
result = fields->read(pt_slaveData, sstr, 0, output, (verbose?OF_VERBOSE:0)|(numeric?OF_NUMERIC:0)|(json?OF_JSON:0), -1, !output.str().empty());
result = fields->read(pt_slaveData, sstr, 0, output, verbosity|(numeric?OF_NUMERIC:0), -1, !output.str().empty());
}
if (failedRead)
if (result >= RESULT_OK) {
@@ -513,7 +528,7 @@ int main()
verify(failedReadMatch, "read", check[2], match, expectStr, output.str());
}
if (!verbose && !json) {
if (verbosity==0) {
istringstream input(expectStr);
result = fields->write(input, pt_masterData, writeMstr, 0);
if (result >= RESULT_OK)
+1 -1
View File
@@ -337,7 +337,7 @@ int main()
for (unsigned char index=0; index<message->getCount(); index++) {
message->storeLastData(*mstrs[index], *sstrs[index]);
}
result = message->decodeLastData(output, (decodeVerbose?OF_VERBOSE:0)|(decodeJson?OF_JSON:0), false);
result = message->decodeLastData(output, (decodeVerbose?OF_NAMES|OF_UNITS|OF_COMMENTS:0)|(decodeJson?OF_NAMES|OF_JSON:0), false);
if (result != RESULT_OK) {
cout << " \"" << check[2] << "\" / \"" << check[3] << "\": decode error: "
<< getResultCode(result) << endl;