Add features for human-editable RawTextConfig files

Features include: ignore # (hash) prefixed comment lines,
ignore blank lines, allow multi-line values.  The latter
feature is particularly useful for entering large arrays
of values that may be set to a container structure.
This commit is contained in:
Jared Dulmage
2019-08-23 14:59:50 -06:00
committed by Tom Henderson
parent d244597a2b
commit a65112aa5d
2 changed files with 64 additions and 31 deletions

View File

@@ -26,6 +26,10 @@
#include "ns3/log.h"
#include "ns3/config.h"
#include <sstream>
#include <algorithm>
#include <functional>
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("RawTextConfig");
@@ -45,14 +49,14 @@ RawTextConfigSave::~RawTextConfigSave ()
delete m_os;
m_os = 0;
}
void
void
RawTextConfigSave::SetFilename (std::string filename)
{
NS_LOG_FUNCTION (this << filename);
m_os = new std::ofstream ();
m_os->open (filename.c_str (), std::ios::out);
}
void
void
RawTextConfigSave::Default (void)
{
NS_LOG_FUNCTION (this);
@@ -77,7 +81,7 @@ private:
RawTextDefaultIterator iterator = RawTextDefaultIterator (m_os);
iterator.Iterate ();
}
void
void
RawTextConfigSave::Global (void)
{
NS_LOG_FUNCTION (this);
@@ -89,7 +93,7 @@ RawTextConfigSave::Global (void)
*m_os << "global " << (*i)->GetName () << " \"" << value.Get () << "\"" << std::endl;
}
}
void
void
RawTextConfigSave::Attributes (void)
{
NS_LOG_FUNCTION (this);
@@ -127,7 +131,7 @@ RawTextConfigLoad::~RawTextConfigLoad ()
m_is = 0;
}
}
void
void
RawTextConfigLoad::SetFilename (std::string filename)
{
NS_LOG_FUNCTION (this << filename);
@@ -138,69 +142,96 @@ std::string
RawTextConfigLoad::Strip (std::string value)
{
std::string::size_type start = value.find ("\"");
std::string::size_type end = value.find ("\"", 1);
NS_ASSERT (start == 0);
NS_ASSERT (end == value.size () - 1);
NS_ASSERT_MSG (start != std::string::npos, "Ill-formed attribute value: " << value);
std::string::size_type end = value.find ("\"", start + 1);
NS_ASSERT_MSG (end != std::string::npos, "Ill-formed attribute value: " << value);
return value.substr (start+1, end-start-1);
}
void
void
RawTextConfigLoad::Default (void)
{
NS_LOG_FUNCTION (this);
m_is->clear ();
m_is->seekg (0);
std::string type, name, value;
*m_is >> type >> name >> value;
while (m_is->good ())
for (std::string line; std::getline (*m_is, line);)
{
if (!ParseLine (line, type, name, value)) continue; // comment
NS_LOG_DEBUG ("type=" << type << ", name=" << name << ", value=" << value);
value = Strip (value);
if (type == "default")
{
Config::SetDefault (name, StringValue (value));
}
*m_is >> type >> name >> value;
Config::SetDefault (name, StringValue (value));
name.clear ();
type.clear ();
}
}
void
void
RawTextConfigLoad::Global (void)
{
NS_LOG_FUNCTION (this);
m_is->clear ();
m_is->seekg (0);
std::string type, name, value;
*m_is >> type >> name >> value;
while (m_is->good ())
for (std::string line; std::getline (*m_is, line);)
{
if (!ParseLine (line, type, name, value)) continue; // comment
NS_LOG_DEBUG ("type=" << type << ", name=" << name << ", value=" << value);
value = Strip (value);
if (type == "global")
{
Config::SetGlobal (name, StringValue (value));
}
*m_is >> type >> name >> value;
Config::SetGlobal (name, StringValue (value));
name.clear ();
type.clear ();
}
}
void
void
RawTextConfigLoad::Attributes (void)
{
NS_LOG_FUNCTION (this);
m_is->clear ();
m_is->seekg (0);
std::string type, path, value;
*m_is >> type >> path >> value;
while (m_is->good ())
std::string type, name, value;
for (std::string line; std::getline (*m_is, line);)
{
NS_LOG_DEBUG ("type=" << type << ", path=" << path << ", value=" << value);
if (!ParseLine (line, type, name, value)) continue;
NS_LOG_DEBUG ("type=" << type << ", name=" << name << ", value=" << value);
value = Strip (value);
if (type == "value")
{
Config::Set (path, StringValue (value));
}
*m_is >> type >> path >> value;
Config::Set (name, StringValue (value));
name.clear ();
type.clear ();
}
}
bool
RawTextConfigLoad::ParseLine (const std::string &line, std::string &type, std::string &name, std::string &value)
{
if (line.front () == '#')
return false; // comment line
if (line.empty () || line == std::string (line.size (), ' '))
return false; // blank line
// for multiline values, append line to value if type and name not empty
if (type.empty () || name.empty ())
{
std::istringstream iss (line);
std::ostringstream rem;
iss >> type >> name >> rem.rdbuf ();
value = rem.str (); // remaining line, includes embedded spaces
}
else
{
value.append (line);
}
// look for two quotes
return std::count (value.begin (), value.end (), '"') == 2;
}
} // namespace ns3

View File

@@ -61,6 +61,8 @@ public:
virtual void Global (void);
virtual void Attributes (void);
private:
virtual bool ParseLine (const std::string &line, std::string &type, std::string &name, std::string &value);
/**
* Strip out attribute value
* \param value the input string