added decode/encode commands, use [DD]* instead of Dx in help

This commit is contained in:
john30
2018-04-08 13:48:54 +02:00
parent bee1fc5b8a
commit 1955e4862f
5 changed files with 197 additions and 35 deletions
+123
View File
@@ -44,6 +44,11 @@ static const char* defaultTemplateFieldMap[] = {
"*name", "type", "divisor/values", "unit", "comment",
};
/** the default field map for fields only. */
static const char* defaultFieldsFieldMap[] = {
"*type", "divisor/values", "unit", "comment",
};
string AttributedItem::formatInt(size_t value) {
ostringstream stream;
@@ -1129,6 +1134,124 @@ result_t DataFieldSet::write(char separator, size_t offset, istringstream* input
}
result_t LoadableDataFieldSet::getFieldMap(const string& preferLanguage, vector<string>* row,
string* errorDescription) const {
// *type,divisor/values,unit,comment
if (row->empty()) {
for (const auto& col : defaultFieldsFieldMap) {
row->push_back(col);
}
return RESULT_OK;
}
map<string, size_t> seen;
for (size_t col = 0; col < row->size(); col++) {
string &name = (*row)[col];
string lowerName = name;
tolower(&lowerName);
trim(&lowerName);
bool toDataFields;
if (!lowerName.empty() && lowerName[0] == '*') {
lowerName.erase(0, 1);
toDataFields = true;
} else {
toDataFields = col == 0;
}
if (lowerName.empty()) {
*errorDescription = "missing name in column " + AttributedItem::formatInt(col);
return RESULT_ERR_INVALID_ARG;
}
if (toDataFields) {
if (!seen.empty() && seen.find("type") == seen.end()) {
*errorDescription = "missing field type";
return RESULT_ERR_EOF; // require at least name and type
}
seen.clear();
}
size_t langPos = lowerName.find_last_of('.');
if (langPos != string::npos && langPos > 0 && langPos == lowerName.length()-3) {
string lang = lowerName.substr(langPos+1);
lowerName.erase(langPos);
map<string, size_t>::iterator previous = seen.find(lowerName);
if (previous != seen.end()) {
if (lang != preferLanguage) {
// skip this column
name = SKIP_COLUMN;
continue;
}
// replace previous
(*row)[previous->second] = SKIP_COLUMN;
seen.erase(lowerName);
}
} else {
map<string, size_t>::iterator previous = seen.find(lowerName);
if (previous != seen.end()) {
*errorDescription = "duplicate field " + name;
return RESULT_ERR_INVALID_ARG;
}
}
name = toDataFields ? "*"+lowerName : lowerName;
seen[lowerName] = col;
}
if (seen.find("type") == seen.end()) {
*errorDescription = "missing field type";
return RESULT_ERR_EOF; // require at least type
}
return RESULT_OK;
}
result_t LoadableDataFieldSet::addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
vector< map<string, string> >* subRows, string* errorDescription, bool replace) {
const DataField* field = NULL;
result_t result = DataField::create(false, false, false, MAX_POS, m_templates, subRows, errorDescription, &field);
if (result != RESULT_OK) {
return result;
}
if (!field) {
return RESULT_ERR_INVALID_ARG;
}
map<string, string> names;
for (auto check : m_fields) {
if (check->isIgnored()) {
continue;
}
string name = check->getName(-1);
if (!name.empty()) {
names[name] = name;
}
}
if (field->isSet()) {
const DataFieldSet* fieldSet = dynamic_cast<const DataFieldSet*>(field);
for (auto sfield : fieldSet->m_fields) {
m_fields.push_back(sfield);
if (sfield->isIgnored()) {
m_ignoredCount++;
continue;
}
string name = sfield->getName(-1);
if (name.empty() || names.find(name) != names.end()) {
m_uniqueNames = false;
} else {
names[name] = name;
}
}
} else {
const SingleDataField* sfield = dynamic_cast<const SingleDataField*>(field);
m_fields.push_back(sfield);
if (sfield->isIgnored()) {
m_ignoredCount++;
} else {
string name = sfield->getName(-1);
if (name.empty() || names.find(name) != names.end()) {
m_uniqueNames = false;
} else {
names[name] = name;
}
}
}
return result;
}
DataFieldTemplates::DataFieldTemplates(const DataFieldTemplates& other)
: MappedFileReader::MappedFileReader(false) {
for (const auto it : other.m_fieldsByName) {
+38 -1
View File
@@ -203,6 +203,12 @@ class DataField : public AttributedItem {
*/
virtual const DataField* clone() const = 0;
/**
* Return whether this is a @a DataFieldSet.
* @return true if this is a @a DataFieldSet.
*/
virtual bool isSet() const { return false; };
/**
* Factory method for creating new instances.
* @param isWriteMessage whether the field is part of a write message (default false).
@@ -589,6 +595,7 @@ class ConstantDataField : public SingleDataField {
* A set of @a DataField instances.
*/
class DataFieldSet : public DataField {
friend class LoadableDataFieldSet;
public:
/**
* Get the @a DataFieldSet for parsing the identification message (service 0x07 0x04).
@@ -636,6 +643,9 @@ class DataFieldSet : public DataField {
// @copydoc
const DataFieldSet* clone() const override;
// @copydoc
bool isSet() const override { return true; };
// @copydoc
size_t getLength(PartType partType, size_t maxLength) const override;
@@ -692,8 +702,9 @@ class DataFieldSet : public DataField {
/** the @a DataFieldSet containing the ident message @a SingleDataField instances, or NULL. */
static DataFieldSet* s_identFields;
protected:
/** the @a vector of @a SingleDataField instances part of this set. */
const vector<const SingleDataField*> m_fields;
vector<const SingleDataField*> m_fields;
/** whether all fields have a unique name. */
bool m_uniqueNames;
@@ -703,6 +714,32 @@ class DataFieldSet : public DataField {
};
/**
* A special @a DataFieldSet that supports loading via @a MappedFileReader.
*/
class LoadableDataFieldSet : public DataFieldSet, public MappedFileReader {
public:
/**
* Constructs a new instance.
* @param name the field name.
* @param fields the @a vector of @a SingleDataField instances part of this set.
*/
LoadableDataFieldSet(const string& name, DataFieldTemplates* templates)
: DataFieldSet(name, vector<const SingleDataField*>()), MappedFileReader(false), m_templates(templates) {
}
// @copydoc
result_t getFieldMap(const string& preferLanguage, vector<string>* row, string* errorDescription) const override;
// @copydoc
result_t addFromFile(const string& filename, unsigned int lineNo, map<string, string>* row,
vector< map<string, string> >* subRows, string* errorDescription, bool replace) override;
private:
DataFieldTemplates* m_templates;
};
/**
* A map of template @a DataField instances.
*/