src/core/command-line.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 3929 909b0a724ed3
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
mathieu@2581
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
mathieu@2581
     2
/*
mathieu@2581
     3
 * Copyright (c) 2008 INRIA
mathieu@2581
     4
 *
mathieu@2581
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@2581
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@2581
     7
 * published by the Free Software Foundation;
mathieu@2581
     8
 *
mathieu@2581
     9
 * This program is distributed in the hope that it will be useful,
mathieu@2581
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@2581
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@2581
    12
 * GNU General Public License for more details.
mathieu@2581
    13
 *
mathieu@2581
    14
 * You should have received a copy of the GNU General Public License
mathieu@2581
    15
 * along with this program; if not, write to the Free Software
mathieu@2581
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@2581
    17
 *
mathieu@2581
    18
 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@2581
    19
 */
mathieu@2575
    20
#include "command-line.h"
mathieu@2575
    21
#include "log.h"
mathieu@2575
    22
#include "config.h"
mathieu@2575
    23
#include "global-value.h"
mathieu@2965
    24
#include "type-id.h"
mathieu@2575
    25
#include "string.h"
mathieu@2575
    26
#include <stdlib.h>
raj@439
    27
mathieu@2575
    28
NS_LOG_COMPONENT_DEFINE ("CommandLine");
raj@439
    29
raj@439
    30
namespace ns3 {
raj@439
    31
mathieu@2575
    32
CommandLine::~CommandLine ()
gjc@1703
    33
{
mathieu@2575
    34
  for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
gjc@1703
    35
    {
mathieu@2575
    36
      delete *i;
gjc@1703
    37
    }
mathieu@2575
    38
  m_items.clear ();
gjc@1703
    39
}
gjc@1703
    40
mathieu@2575
    41
CommandLine::Item::~Item ()
mathieu@2575
    42
{}
raj@439
    43
raj@439
    44
void 
mathieu@2915
    45
CommandLine::Parse (int iargc, char *argv[]) const
raj@439
    46
{
mathieu@2575
    47
  int argc = iargc;
gjc@1533
    48
  for (argc--, argv++; argc > 0; argc--, argv++)
raj@439
    49
    {
raj@439
    50
      // remove "--" or "-" heading.
raj@439
    51
      std::string param = *argv;
raj@439
    52
      std::string::size_type cur = param.find ("--");
mathieu@2575
    53
      if (cur == 0)
mathieu@2575
    54
	{
mathieu@2575
    55
	  param = param.substr (2, param.size () - 2);
mathieu@2575
    56
	}
mathieu@2575
    57
      else
mathieu@2575
    58
	{
mathieu@2575
    59
	  cur = param.find ("-");
mathieu@2575
    60
	  if (cur == 0)
mathieu@2575
    61
	    {
mathieu@2575
    62
	      param = param.substr (1, param.size () - 1);
mathieu@2575
    63
	    }
mathieu@2575
    64
	  else
mathieu@2575
    65
	    {
mathieu@2575
    66
	      // invalid argument. ignore.
mathieu@2575
    67
	      continue;
mathieu@2575
    68
	    }
mathieu@2575
    69
	}
raj@439
    70
      cur = param.find ("=");
raj@439
    71
      std::string name, value;
raj@439
    72
      if (cur == std::string::npos)
raj@439
    73
        {
mathieu@2575
    74
	  name = param;
mathieu@2575
    75
	  value = "";
raj@439
    76
        }
raj@439
    77
      else
raj@439
    78
        {
mathieu@2575
    79
          name = param.substr (0, cur);
mathieu@2575
    80
          value = param.substr (cur + 1, param.size () - (cur+1));
raj@439
    81
        }
mathieu@2575
    82
      HandleArgument (name, value);
raj@439
    83
    }
raj@439
    84
}
raj@439
    85
mathieu@2575
    86
void
mathieu@2575
    87
CommandLine::PrintHelp (void) const
mathieu@2575
    88
{
mathieu@2575
    89
  std::cout << "--PrintHelp: Print this help message." << std::endl;
mathieu@2575
    90
  std::cout << "--PrintGroups: Print the list of groups." << std::endl;
mathieu@2575
    91
  std::cout << "--PrintTypeIds: Print all TypeIds." << std::endl;  
mathieu@2575
    92
  std::cout << "--PrintGroup=[group]: Print all TypeIds of group." << std::endl;
mathieu@2575
    93
  std::cout << "--PrintAttributes=[typeid]: Print all attributes of typeid." << std::endl;
mathieu@2575
    94
  std::cout << "--PrintGlobals: Print the list of globals." << std::endl;
mathieu@2575
    95
  if (!m_items.empty ())
mathieu@2575
    96
    {
mathieu@2575
    97
      std::cout << "User Arguments:" << std::endl;
mathieu@2575
    98
      for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
mathieu@2575
    99
	{
mathieu@2575
   100
	  std::cout << "    --" << (*i)->m_name << ": " << (*i)->m_help << std::endl;
mathieu@2575
   101
	}
mathieu@2575
   102
    }
mathieu@2575
   103
}
gjc@1702
   104
mathieu@2575
   105
void
mathieu@2575
   106
CommandLine::PrintGlobals (void) const
mathieu@2575
   107
{
mathieu@2575
   108
  for (GlobalValue::Iterator i = GlobalValue::Begin (); i != GlobalValue::End (); ++i)
mathieu@2575
   109
    {
mathieu@2575
   110
      std::cout << "    --" << (*i)->GetName () << "=[";
mathieu@2575
   111
      Ptr<const AttributeChecker> checker = (*i)->GetChecker ();
mathieu@2965
   112
      StringValue v;
mathieu@2965
   113
      (*i)->GetValue (v);
mathieu@2965
   114
      std::cout << v.Get () << "]:  "
mathieu@2575
   115
		<< (*i)->GetHelp () << std::endl;      
mathieu@2575
   116
    }
mathieu@2575
   117
}
gjc@1702
   118
mathieu@2575
   119
void
mathieu@2575
   120
CommandLine::PrintAttributes (std::string type) const
mathieu@2575
   121
{
mathieu@2575
   122
  TypeId tid;
mathieu@2575
   123
  if (!TypeId::LookupByNameFailSafe (type, &tid))
mathieu@2575
   124
    {
mathieu@2575
   125
      NS_FATAL_ERROR ("Unknown type="<<type<<" in --PrintAttributes");
mathieu@2575
   126
    }
mathieu@2693
   127
  for (uint32_t i = 0; i < tid.GetAttributeN (); ++i)
mathieu@2575
   128
    {
mathieu@2575
   129
      std::cout << "    --"<<tid.GetAttributeFullName (i)<<"=[";
mathieu@2575
   130
      Ptr<const AttributeChecker> checker = tid.GetAttributeChecker (i);
mathieu@2965
   131
      Ptr<const AttributeValue> initial = tid.GetAttributeInitialValue (i);
mathieu@2965
   132
      std::cout << initial->SerializeToString (checker) << "]:  "
mathieu@2575
   133
		<< tid.GetAttributeHelp (i) << std::endl;
mathieu@2575
   134
    }
mathieu@2575
   135
}
mathieu@2575
   136
mathieu@2575
   137
mathieu@2575
   138
void
mathieu@2575
   139
CommandLine::PrintGroup (std::string group) const
mathieu@2575
   140
{
mathieu@2575
   141
  for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
mathieu@2575
   142
    {
mathieu@2575
   143
      TypeId tid = TypeId::GetRegistered (i);
mathieu@2575
   144
      if (tid.GetGroupName () == group)
mathieu@2575
   145
	{
mathieu@2575
   146
	  std::cout << "    --PrintAttributes=" <<tid.GetName ()<<std::endl;
mathieu@2575
   147
	}
mathieu@2575
   148
    }
mathieu@2575
   149
}
mathieu@2575
   150
mathieu@2575
   151
void
mathieu@2575
   152
CommandLine::PrintTypeIds (void) const
mathieu@2575
   153
{
mathieu@2575
   154
  for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
mathieu@2575
   155
    {
mathieu@2575
   156
      TypeId tid = TypeId::GetRegistered (i);
mathieu@2575
   157
      std::cout << "    --PrintAttributes=" <<tid.GetName ()<<std::endl;
mathieu@2575
   158
    }
mathieu@2575
   159
}
mathieu@2575
   160
mathieu@2575
   161
void
mathieu@2575
   162
CommandLine::PrintGroups (void) const
mathieu@2575
   163
{
mathieu@2575
   164
  std::list<std::string> groups;
mathieu@2575
   165
  for (uint32_t i = 0; i < TypeId::GetRegisteredN (); ++i)
mathieu@2575
   166
    {
mathieu@2575
   167
      TypeId tid = TypeId::GetRegistered (i);
mathieu@2575
   168
      std::string group = tid.GetGroupName ();
mathieu@2575
   169
      if (group == "")
mathieu@2575
   170
	{
mathieu@2575
   171
	  continue;
mathieu@2575
   172
	}
mathieu@2575
   173
      bool found = false;
mathieu@2575
   174
      for (std::list<std::string>::const_iterator j = groups.begin (); j != groups.end (); ++j)
mathieu@2575
   175
	{
mathieu@2575
   176
	  if (*j == group)
mathieu@2575
   177
	    {
mathieu@2575
   178
	      found = true;
mathieu@2575
   179
	      break;
mathieu@2575
   180
	    }
mathieu@2575
   181
	}
mathieu@2575
   182
      if (!found)
mathieu@2575
   183
	{
mathieu@2575
   184
	  groups.push_back (group);
mathieu@2575
   185
	}
mathieu@2575
   186
    }
mathieu@2575
   187
  for (std::list<std::string>::const_iterator k = groups.begin (); k != groups.end (); ++k)
mathieu@2575
   188
    {
mathieu@2575
   189
      std::cout << "    --PrintGroup="<<*k<<std::endl;
mathieu@2575
   190
    }
mathieu@2575
   191
}
mathieu@2575
   192
mathieu@2575
   193
void
mathieu@2575
   194
CommandLine::HandleArgument (std::string name, std::string value) const
mathieu@2575
   195
{
mathieu@2575
   196
  NS_LOG_DEBUG ("Handle arg name="<<name<<" value="<<value);
mathieu@2575
   197
  if (name == "PrintHelp")
mathieu@2575
   198
    {
mathieu@2575
   199
      // method below never returns.
mathieu@2575
   200
      PrintHelp ();
mathieu@4490
   201
      exit (0);
mathieu@4490
   202
    } 
mathieu@4490
   203
  else if (name == "PrintGroups")
mathieu@2575
   204
    {
mathieu@2575
   205
      // method below never returns.
mathieu@2575
   206
      PrintGroups ();
mathieu@4490
   207
      exit (0);
mathieu@2575
   208
    }
mathieu@4490
   209
  else if (name == "PrintTypeIds")
mathieu@2575
   210
    {
mathieu@2575
   211
      // method below never returns.
mathieu@2575
   212
      PrintTypeIds ();
mathieu@4490
   213
      exit (0);
mathieu@2575
   214
    }
mathieu@4490
   215
  else if (name == "PrintGlobals")
mathieu@2575
   216
    {
mathieu@2575
   217
      // method below never returns.
mathieu@2575
   218
      PrintGlobals ();
mathieu@4490
   219
      exit (0);
mathieu@2575
   220
    }
mathieu@4490
   221
  else if (name == "PrintGroup")
mathieu@2575
   222
    {
mathieu@2575
   223
      // method below never returns.
mathieu@2575
   224
      PrintGroup (value);
mathieu@4490
   225
      exit (0);
mathieu@2575
   226
    }
mathieu@4490
   227
  else if (name == "PrintAttributes")
mathieu@2575
   228
    {
mathieu@2575
   229
      // method below never returns.
mathieu@2575
   230
      PrintAttributes (value);
mathieu@4490
   231
      exit (0);
mathieu@2575
   232
    }
mathieu@4490
   233
  else
mathieu@2575
   234
    {
mathieu@4490
   235
      for (Items::const_iterator i = m_items.begin (); i != m_items.end (); ++i)
mathieu@4490
   236
        {
mathieu@4490
   237
          if ((*i)->m_name == name)
mathieu@4490
   238
            {
mathieu@4490
   239
              if (!(*i)->Parse (value))
mathieu@4490
   240
                {
mathieu@4490
   241
                  std::cerr << "Invalid argument value: "<<name<<"="<<value << std::endl;
mathieu@4490
   242
                  exit (1);
mathieu@4490
   243
                }
mathieu@4490
   244
              else
mathieu@4490
   245
                {
mathieu@4490
   246
                  return;
mathieu@4490
   247
                }
mathieu@4490
   248
            }
mathieu@4490
   249
        }
mathieu@2575
   250
    }
mathieu@2965
   251
  if (!Config::SetGlobalFailSafe (name, StringValue (value))
mathieu@2965
   252
      && !Config::SetDefaultFailSafe (name, StringValue (value)))
gjc@2629
   253
    {
gjc@2629
   254
      std::cerr << "Invalid command-line arguments: --"<<name<<"="<<value<<std::endl;
gjc@2629
   255
      PrintHelp ();
mathieu@4490
   256
      exit (1);
gjc@2629
   257
    }
mathieu@2575
   258
}
mathieu@2575
   259
gjc@3929
   260
bool
gjc@3929
   261
CommandLine::CallbackItem::Parse (std::string value)
gjc@3929
   262
{
gjc@3929
   263
  NS_LOG_DEBUG ("CommandLine::CallbackItem::Parse \"" << value << "\"");
gjc@3929
   264
  return m_callback (value);
gjc@3929
   265
}
gjc@3929
   266
gjc@3929
   267
void
gjc@3929
   268
CommandLine::AddValue (const std::string &name,
gjc@3929
   269
                       const std::string &help,
gjc@3929
   270
                       Callback<bool, std::string> callback)
gjc@3929
   271
{
gjc@3929
   272
  NS_LOG_FUNCTION (this << name << help << "callback");
gjc@3929
   273
  CallbackItem *item = new CallbackItem ();
gjc@3929
   274
  item->m_name = name;
gjc@3929
   275
  item->m_help = help;
gjc@3929
   276
  item->m_callback = callback;
gjc@3929
   277
  m_items.push_back (item);
gjc@3929
   278
}
gjc@3929
   279
gjc@3929
   280
mathieu@2575
   281
} // namespace ns3
gjc@1702
   282
gjc@1702
   283
#ifdef RUN_SELF_TESTS
mathieu@2575
   284
gjc@1702
   285
#include "test.h"
mathieu@2575
   286
#include <stdarg.h>
gjc@1702
   287
mathieu@2575
   288
using namespace ns3;
gjc@1702
   289
gjc@1702
   290
class CommandLineTest : public Test
gjc@1702
   291
{
gjc@1702
   292
public:
mathieu@2575
   293
  CommandLineTest ();
mathieu@2575
   294
  virtual bool RunTests (void);
mathieu@2575
   295
private:
mathieu@2575
   296
  void Parse (const CommandLine &cmd, int n, ...);
gjc@1702
   297
};
gjc@1702
   298
mathieu@2575
   299
CommandLineTest::CommandLineTest ()
mathieu@2575
   300
  : Test ("CommandLine")
mathieu@2575
   301
{}
mathieu@2575
   302
void
mathieu@2575
   303
CommandLineTest::Parse (const CommandLine &cmd, int n, ...)
mathieu@2575
   304
{
mathieu@2575
   305
  char **args = new char* [n+1];
gjc@2612
   306
  args[0] = (char *) "Test";
mathieu@2575
   307
  va_list ap;
mathieu@2575
   308
  va_start (ap, n);
mathieu@2575
   309
  int i = 0;
mathieu@2575
   310
  while (i < n)
mathieu@2575
   311
    {
mathieu@2575
   312
      char *arg = va_arg (ap, char *);
mathieu@2575
   313
      args[i+1] = arg;
mathieu@2575
   314
      i++;
mathieu@2575
   315
    }
mathieu@2575
   316
  int argc = n + 1;
mathieu@2575
   317
  cmd.Parse (argc, args);
mathieu@2575
   318
  delete [] args;
mathieu@2575
   319
}
mathieu@2575
   320
bool 
mathieu@2575
   321
CommandLineTest::RunTests (void)
mathieu@2575
   322
{
mathieu@2575
   323
  bool result = true;
gjc@1702
   324
mathieu@2575
   325
  bool myBool = false;
mathieu@2575
   326
  uint32_t myUint32 = 10;
mathieu@2575
   327
  std::string myStr = "MyStr";
mathieu@2575
   328
  int32_t myInt32 = -1;
mathieu@2575
   329
  CommandLine cmd;
gjc@1702
   330
mathieu@2575
   331
  cmd.AddValue ("my-bool", "help", myBool);
mathieu@2575
   332
  Parse (cmd, 1, "--my-bool=0");
mathieu@2575
   333
  NS_TEST_ASSERT_EQUAL (myBool, false);
mathieu@2575
   334
  Parse (cmd, 1, "--my-bool=1");
mathieu@2575
   335
  NS_TEST_ASSERT_EQUAL (myBool, true);
mathieu@2575
   336
mathieu@2575
   337
  cmd.AddValue ("my-uint32", "help", myUint32);
mathieu@2575
   338
  Parse (cmd, 2, "--my-bool=0", "--my-uint32=9");
mathieu@2575
   339
  NS_TEST_ASSERT_EQUAL (myUint32, 9);
mathieu@2575
   340
mathieu@2575
   341
  cmd.AddValue ("my-str", "help", myStr);
mathieu@2575
   342
  Parse (cmd, 2, "--my-bool=0", "--my-str=XX");
mathieu@2575
   343
  NS_TEST_ASSERT_EQUAL (myStr, "XX");
mathieu@2575
   344
mathieu@2575
   345
  cmd.AddValue ("my-int32", "help", myInt32);
mathieu@2575
   346
  Parse (cmd, 2, "--my-bool=0", "--my-int32=-3");
mathieu@2575
   347
  NS_TEST_ASSERT_EQUAL (myInt32, -3);
mathieu@2575
   348
  Parse (cmd, 2, "--my-bool=0", "--my-int32=+2");
mathieu@2575
   349
  NS_TEST_ASSERT_EQUAL (myInt32, +2);
mathieu@2575
   350
mathieu@2575
   351
  return result;
mathieu@2575
   352
}
mathieu@2575
   353
mathieu@2575
   354
mathieu@2575
   355
static CommandLineTest g_cmdLineTest;
gjc@1702
   356
gjc@1702
   357
#endif /* RUN_SELF_TESTS */