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:
committed by
Tom Henderson
parent
d244597a2b
commit
a65112aa5d
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user