559 lines
13 KiB
C++
559 lines
13 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2008 INRIA
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
|
*/
|
|
|
|
#include <algorithm> // for transform
|
|
#include <cctype> // for tolower
|
|
#include <cstdlib> // for exit
|
|
#include <iomanip> // for setw, boolalpha
|
|
#include <set>
|
|
#include <sstream>
|
|
|
|
#include "command-line.h"
|
|
#include "des-metrics.h"
|
|
#include "log.h"
|
|
#include "config.h"
|
|
#include "global-value.h"
|
|
#include "system-path.h"
|
|
#include "type-id.h"
|
|
#include "string.h"
|
|
|
|
|
|
/**
|
|
* \file
|
|
* \ingroup commandline
|
|
* CommandLine class implementation.
|
|
*/
|
|
|
|
namespace ns3 {
|
|
|
|
NS_LOG_COMPONENT_DEFINE ("CommandLine");
|
|
|
|
CommandLine::CommandLine ()
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
}
|
|
CommandLine::CommandLine (const CommandLine &cmd)
|
|
{
|
|
Copy (cmd);
|
|
}
|
|
CommandLine &
|
|
CommandLine::operator = (const CommandLine &cmd)
|
|
{
|
|
Clear ();
|
|
Copy (cmd);
|
|
return *this;
|
|
}
|
|
CommandLine::~CommandLine ()
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
Clear ();
|
|
}
|
|
void
|
|
CommandLine::Copy (const CommandLine &cmd)
|
|
{
|
|
NS_LOG_FUNCTION (&cmd);
|
|
|
|
for (Items::const_iterator i = cmd.m_items.begin ();
|
|
i != cmd.m_items.end (); ++i)
|
|
{
|
|
m_items.push_back (*i);
|
|
}
|
|
m_usage = cmd.m_usage;
|
|
m_name = cmd.m_name;
|
|
}
|
|
void
|
|
CommandLine::Clear (void)
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
|
|
{
|
|
delete *i;
|
|
}
|
|
m_items.clear ();
|
|
m_usage = "";
|
|
m_name = "";
|
|
}
|
|
|
|
void
|
|
CommandLine::Usage (const std::string usage)
|
|
{
|
|
m_usage = usage;
|
|
}
|
|
|
|
std::string
|
|
CommandLine::GetName () const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
CommandLine::Item::~Item ()
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
}
|
|
|
|
void
|
|
CommandLine::Parse (int argc, char *argv[])
|
|
{
|
|
NS_LOG_FUNCTION (this << argc << argv);
|
|
|
|
m_name = SystemPath::Split (argv[0]).back ();
|
|
|
|
int iargc = argc;
|
|
for (iargc--; iargc > 0; iargc--)
|
|
{
|
|
// remove "--" or "-" heading.
|
|
std::string param = argv[iargc];
|
|
std::string::size_type cur = param.find ("--");
|
|
if (cur == 0)
|
|
{
|
|
param = param.substr (2, param.size () - 2);
|
|
}
|
|
else
|
|
{
|
|
cur = param.find ("-");
|
|
if (cur == 0)
|
|
{
|
|
param = param.substr (1, param.size () - 1);
|
|
}
|
|
else
|
|
{
|
|
// invalid argument. ignore.
|
|
continue;
|
|
}
|
|
}
|
|
cur = param.find ("=");
|
|
std::string name, value;
|
|
if (cur == std::string::npos)
|
|
{
|
|
name = param;
|
|
value = "";
|
|
}
|
|
else
|
|
{
|
|
name = param.substr (0, cur);
|
|
value = param.substr (cur + 1, param.size () - (cur+1));
|
|
}
|
|
HandleArgument (name, value);
|
|
}
|
|
|
|
#ifdef ENABLE_DES_METRICS
|
|
DesMetrics::Get ()->Initialize (argc, argv);
|
|
#endif
|
|
|
|
}
|
|
|
|
void
|
|
CommandLine::PrintHelp (std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
os << m_name << " [Program Arguments] [General Arguments]"
|
|
<< std::endl;
|
|
|
|
if (m_usage.length ())
|
|
{
|
|
os << std::endl;
|
|
os << m_usage << std::endl;
|
|
}
|
|
|
|
if (!m_items.empty ())
|
|
{
|
|
size_t width = 0;
|
|
for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
|
|
{
|
|
width = std::max (width, (*i)->m_name.size ());
|
|
}
|
|
width += 3;
|
|
|
|
os << std::endl;
|
|
os << "Program Arguments:" << std::endl;
|
|
for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
|
|
{
|
|
os << " --"
|
|
<< std::left << std::setw (width) << ( (*i)->m_name + ":")
|
|
<< std::right
|
|
<< (*i)->m_help;
|
|
|
|
if ( (*i)->HasDefault ())
|
|
{
|
|
os << " [" << (*i)->GetDefault () << "]";
|
|
}
|
|
os << std::endl;
|
|
}
|
|
}
|
|
|
|
os << std::endl;
|
|
os
|
|
<< "General Arguments:\n"
|
|
<< " --PrintGlobals: Print the list of globals.\n"
|
|
<< " --PrintGroups: Print the list of groups.\n"
|
|
<< " --PrintGroup=[group]: Print all TypeIds of group.\n"
|
|
<< " --PrintTypeIds: Print all TypeIds.\n"
|
|
<< " --PrintAttributes=[typeid]: Print all attributes of typeid.\n"
|
|
<< " --PrintHelp: Print this help message.\n"
|
|
<< std::endl;
|
|
}
|
|
|
|
void
|
|
CommandLine::PrintGlobals (std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
os << "Global values:" << std::endl;
|
|
|
|
// Sort output
|
|
std::vector<std::string> globals;
|
|
|
|
for (GlobalValue::Iterator i = GlobalValue::Begin ();
|
|
i != GlobalValue::End ();
|
|
++i)
|
|
{
|
|
std::stringstream ss;
|
|
ss << " --" << (*i)->GetName () << "=[";
|
|
Ptr<const AttributeChecker> checker = (*i)->GetChecker ();
|
|
StringValue v;
|
|
(*i)->GetValue (v);
|
|
ss << v.Get () << "]" << std::endl;
|
|
ss << " " << (*i)->GetHelp () << std::endl;
|
|
globals.push_back (ss.str ());
|
|
}
|
|
std::sort (globals.begin (), globals.end ());
|
|
for (std::vector<std::string>::const_iterator it = globals.begin ();
|
|
it < globals.end ();
|
|
++it)
|
|
{
|
|
os << *it;
|
|
}
|
|
}
|
|
|
|
void
|
|
CommandLine::PrintAttributes (std::ostream &os, const std::string &type) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
TypeId tid;
|
|
if (!TypeId::LookupByNameFailSafe (type, &tid))
|
|
{
|
|
NS_FATAL_ERROR ("Unknown type=" << type << " in --PrintAttributes");
|
|
}
|
|
|
|
os << "Attributes for TypeId " << tid.GetName () << std::endl;
|
|
|
|
// Sort output
|
|
std::vector<std::string> attributes;
|
|
|
|
for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
|
|
{
|
|
std::stringstream ss;
|
|
ss << " --" << tid.GetAttributeFullName (i) << "=[";
|
|
struct TypeId::AttributeInformation info = tid.GetAttribute (i);
|
|
ss << info.initialValue->SerializeToString (info.checker) << "]"
|
|
<< std::endl;
|
|
ss << " " << info.help << std::endl;
|
|
attributes.push_back (ss.str ());
|
|
}
|
|
std::sort (attributes.begin (), attributes.end ());
|
|
for (std::vector<std::string>::const_iterator it = attributes.begin ();
|
|
it < attributes.end ();
|
|
++it)
|
|
{
|
|
os << *it;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CommandLine::PrintGroup (std::ostream &os, const std::string &group) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
os << "TypeIds in group " << group << ":" << std::endl;
|
|
|
|
// Sort output
|
|
std::vector<std::string> groupTypes;
|
|
|
|
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
|
|
{
|
|
std::stringstream ss;
|
|
TypeId tid = TypeId::GetRegistered (i);
|
|
if (tid.GetGroupName () == group)
|
|
{
|
|
ss << " " <<tid.GetName () << std::endl;
|
|
}
|
|
groupTypes.push_back (ss.str ());
|
|
}
|
|
std::sort (groupTypes.begin (), groupTypes.end ());
|
|
for (std::vector<std::string>::const_iterator it = groupTypes.begin ();
|
|
it < groupTypes.end ();
|
|
++it)
|
|
{
|
|
os << *it;
|
|
}
|
|
}
|
|
|
|
void
|
|
CommandLine::PrintTypeIds (std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
os << "Registered TypeIds:" << std::endl;
|
|
|
|
// Sort output
|
|
std::vector<std::string> types;
|
|
|
|
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
|
|
{
|
|
std::stringstream ss;
|
|
TypeId tid = TypeId::GetRegistered (i);
|
|
ss << " " << tid.GetName () << std::endl;
|
|
types.push_back (ss.str ());
|
|
}
|
|
std::sort (types.begin (), types.end ());
|
|
for (std::vector<std::string>::const_iterator it = types.begin ();
|
|
it < types.end ();
|
|
++it)
|
|
{
|
|
os << *it;
|
|
}
|
|
}
|
|
|
|
void
|
|
CommandLine::PrintGroups (std::ostream &os) const
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
|
|
std::set<std::string> groups;
|
|
for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
|
|
{
|
|
TypeId tid = TypeId::GetRegistered (i);
|
|
groups.insert (tid.GetGroupName ());
|
|
}
|
|
|
|
os << "Registered TypeId groups:" << std::endl;
|
|
// Sets are already sorted
|
|
for (std::set<std::string>::const_iterator k = groups.begin ();
|
|
k != groups.end ();
|
|
++k)
|
|
{
|
|
os << " " << *k << std::endl;
|
|
}
|
|
}
|
|
|
|
void
|
|
CommandLine::HandleArgument (const std::string &name, const std::string &value) const
|
|
{
|
|
NS_LOG_FUNCTION (this << name << value);
|
|
|
|
NS_LOG_DEBUG ("Handle arg name=" << name << " value=" << value);
|
|
if (name == "PrintHelp" || name == "help")
|
|
{
|
|
// method below never returns.
|
|
PrintHelp (std::cout);
|
|
std::exit (0);
|
|
}
|
|
else if (name == "PrintGroups")
|
|
{
|
|
// method below never returns.
|
|
PrintGroups (std::cout);
|
|
std::exit (0);
|
|
}
|
|
else if (name == "PrintTypeIds")
|
|
{
|
|
// method below never returns.
|
|
PrintTypeIds (std::cout);
|
|
std::exit (0);
|
|
}
|
|
else if (name == "PrintGlobals")
|
|
{
|
|
// method below never returns.
|
|
PrintGlobals (std::cout);
|
|
std::exit (0);
|
|
}
|
|
else if (name == "PrintGroup")
|
|
{
|
|
// method below never returns.
|
|
PrintGroup (std::cout, value);
|
|
std::exit (0);
|
|
}
|
|
else if (name == "PrintAttributes")
|
|
{
|
|
// method below never returns.
|
|
PrintAttributes (std::cout, value);
|
|
std::exit (0);
|
|
}
|
|
else
|
|
{
|
|
for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
|
|
{
|
|
if ((*i)->m_name == name)
|
|
{
|
|
if (!(*i)->Parse (value))
|
|
{
|
|
std::cerr << "Invalid argument value: "
|
|
<< name << "=" << value << std::endl;
|
|
std::exit (1);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!Config::SetGlobalFailSafe (name, StringValue (value))
|
|
&& !Config::SetDefaultFailSafe (name, StringValue (value)))
|
|
{
|
|
std::cerr << "Invalid command-line arguments: --"
|
|
<< name << "=" << value << std::endl;
|
|
PrintHelp (std::cerr);
|
|
std::exit (1);
|
|
}
|
|
}
|
|
|
|
bool
|
|
CommandLine::CallbackItem::Parse (const std::string value)
|
|
{
|
|
NS_LOG_FUNCTION (this);
|
|
NS_LOG_DEBUG ("CommandLine::CallbackItem::Parse \"" << value << "\"");
|
|
return m_callback (value);
|
|
}
|
|
|
|
void
|
|
CommandLine::AddValue (const std::string &name,
|
|
const std::string &help,
|
|
Callback<bool, std::string> callback)
|
|
{
|
|
NS_LOG_FUNCTION (this << &name << &help << &callback);
|
|
CallbackItem *item = new CallbackItem ();
|
|
item->m_name = name;
|
|
item->m_help = help;
|
|
item->m_callback = callback;
|
|
m_items.push_back (item);
|
|
}
|
|
|
|
void
|
|
CommandLine::AddValue (const std::string &name,
|
|
const std::string &attributePath)
|
|
{
|
|
NS_LOG_FUNCTION (this << name << attributePath);
|
|
// Attribute name is last token
|
|
size_t colon = attributePath.rfind ("::");
|
|
const std::string typeName = attributePath.substr (0, colon);
|
|
NS_LOG_DEBUG ("typeName: '" << typeName << "', colon: " << colon);
|
|
|
|
TypeId tid;
|
|
if (!TypeId::LookupByNameFailSafe (typeName, &tid))
|
|
{
|
|
NS_FATAL_ERROR ("Unknown type=" << typeName);
|
|
}
|
|
|
|
const std::string attrName = attributePath.substr (colon + 2);
|
|
struct TypeId::AttributeInformation info;
|
|
if (!tid.LookupAttributeByName (attrName, &info))
|
|
{
|
|
NS_FATAL_ERROR ("Attribute not found: " << attributePath);
|
|
}
|
|
|
|
std::stringstream ss;
|
|
ss << info.help
|
|
<< " (" << attributePath << ") ["
|
|
<< info.initialValue->SerializeToString (info.checker) << "]";
|
|
|
|
AddValue (name, ss.str (),
|
|
MakeBoundCallback (CommandLine::HandleAttribute, attributePath)) ;
|
|
}
|
|
|
|
|
|
/* static */
|
|
bool
|
|
CommandLine::HandleAttribute (const std::string name,
|
|
const std::string value)
|
|
{
|
|
bool success = true;
|
|
if (!Config::SetGlobalFailSafe (name, StringValue (value))
|
|
&& !Config::SetDefaultFailSafe (name, StringValue (value)))
|
|
{
|
|
success = false;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
bool
|
|
CommandLine::Item::HasDefault () const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::string
|
|
CommandLine::Item::GetDefault () const
|
|
{
|
|
return "";
|
|
}
|
|
|
|
template <>
|
|
std::string
|
|
CommandLineHelper::GetDefault<bool> (const bool & val)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << std::boolalpha << val;
|
|
return oss.str ();
|
|
}
|
|
|
|
template <>
|
|
bool
|
|
CommandLineHelper::UserItemParse<bool> (const std::string value, bool & val)
|
|
{
|
|
std::string src = value;
|
|
std::transform(src.begin(), src.end(), src.begin(), ::tolower);
|
|
|
|
if (src.length () == 0)
|
|
{
|
|
val = ! val;
|
|
return true;
|
|
}
|
|
else if ( (src == "true") || (src == "t") )
|
|
{
|
|
val = true;
|
|
return true;
|
|
}
|
|
else if ( (src == "false") || (src == "f"))
|
|
{
|
|
val = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
std::istringstream iss;
|
|
iss.str (src);
|
|
iss >> val;
|
|
return !iss.bad () && !iss.fail ();
|
|
}
|
|
}
|
|
|
|
std::ostream &
|
|
operator << (std::ostream & os, const CommandLine & cmd)
|
|
{
|
|
cmd.PrintHelp (os);
|
|
return os;
|
|
}
|
|
|
|
} // namespace ns3
|