Make CommandLine print boolean defaults as text.
authorPeter D. Barnes, Jr. <barnes26@llnl.gov>
Wed, 07 Aug 2013 10:36:45 -0700
changeset 10243 5f6bab1bf0f4
parent 10242 4952c9e4573a
child 10244 6310eb759a1f
Make CommandLine print boolean defaults as text. And - clarify the documentation - make example arguments more explicit - make "--boolArg" toggle the value, not set to true (this enables toggle on default true values)
src/core/examples/command-line-example.cc
src/core/model/command-line.cc
src/core/model/command-line.h
--- a/src/core/examples/command-line-example.cc	Thu Aug 15 14:45:42 2013 -0400
+++ b/src/core/examples/command-line-example.cc	Wed Aug 07 10:36:45 2013 -0700
@@ -18,7 +18,8 @@
  * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
  */
 
-#include <iostream>  // boolalpha
+#include <iostream>
+#include <iomanip>
 #include <string>
 
 #include "ns3/core-module.h"
@@ -27,11 +28,11 @@
 using namespace ns3;
 
 
-std::string g_val4="val4 default";
+std::string g_cbArg="cbArg default";
 
-bool SetVal4 (std::string val)
+bool SetCbArg (std::string val)
 {
-  g_val4 = val;
+  g_cbArg = val;
   return true;
 }
 
@@ -39,25 +40,28 @@
 int main (int argc, char *argv[])
 {
 
-  int         val1 = 1;
-  bool        val2 = false;
-  std::string val3 = "val3 default";
+  int         intArg  = 1;
+  bool        boolArg = false;
+  std::string strArg  = "strArg default";
   
   CommandLine cmd;
   cmd.Usage ("CommandLine example program.\n"
              "\n"
              "This little program demonstrates how to use CommandLine.");
-  cmd.AddValue ("val1", "an int argument",          val1);
-  cmd.AddValue ("val2", "a bool argument",          val2);
-  cmd.AddValue ("val3", "a string argument",        val3);
-  cmd.AddValue ("val4", "a string via callback", MakeCallback (SetVal4));
+  cmd.AddValue ("intArg",  "an int argument",       intArg);
+  cmd.AddValue ("boolArg", "a bool argument",       boolArg);
+  cmd.AddValue ("strArg",  "a string argument",     strArg);
+  cmd.AddValue ("cbArg",   "a string via callback", MakeCallback (SetCbArg));
   cmd.Parse (argc, argv);
 
-  std::cout << "val1:\t" << val1 << std::endl;
-  std::cout << "val2:\t"   << std::boolalpha << val2
-            << std::noboolalpha << std::endl;
-  std::cout << "val3:\t\"" << val3 << "\"" << std::endl;
-  std::cout << "val4:\t\"" << g_val4 << "\"" << std::endl;
+  std::cout << std::left
+            << std::setw (10) << "intArg:"         << intArg           << std::endl;
+  std::cout << std::setw (10) << "boolArg:"
+            << std::boolalpha                      << boolArg
+            << std::noboolalpha                                        << std::endl;
+  
+  std::cout << std::setw (10) << "strArg:" << "\"" << strArg  << "\""  << std::endl;
+  std::cout << std::setw (10) << "cbArg:"  << "\"" << g_cbArg << "\""  << std::endl;
 
   return 0;
 }
--- a/src/core/model/command-line.cc	Thu Aug 15 14:45:42 2013 -0400
+++ b/src/core/model/command-line.cc	Wed Aug 07 10:36:45 2013 -0700
@@ -21,7 +21,7 @@
 #include <algorithm>  // for transform
 #include <cctype>     // for tolower
 #include <cstdlib>    // for exit
-#include <iomanip>    // for setw
+#include <iomanip>    // for setw, boolalpha
 
 #include "command-line.h"
 #include "log.h"
@@ -152,7 +152,7 @@
   NS_LOG_FUNCTION (this);
 
   os << m_name << " [Program Arguments] [General Arguments]"
-     << std::endl;
+            << std::endl;
   
   if (m_usage.length ())
     {
@@ -174,16 +174,16 @@
       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;
+                    << 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;
@@ -226,7 +226,7 @@
   TypeId tid;
   if (!TypeId::LookupByNameFailSafe (type, &tid))
     {
-      NS_FATAL_ERROR ("Unknown type="<<type<<" in --PrintAttributes");
+      NS_FATAL_ERROR ("Unknown type=" << type << " in --PrintAttributes");
     }
 
   os << "Attributes for TypeId " << tid.GetName () << std::endl;
@@ -317,7 +317,7 @@
 {
   NS_LOG_FUNCTION (this << name << value);
 
-  NS_LOG_DEBUG ("Handle arg name="<<name<<" value="<<value);
+  NS_LOG_DEBUG ("Handle arg name=" << name << " value=" << value);
   if (name == "PrintHelp" || name == "help")
     {
       // method below never returns.
@@ -384,7 +384,7 @@
 }
 
 bool
-CommandLine::CallbackItem::Parse (std::string value)
+CommandLine::CallbackItem::Parse (const std::string value)
 {
   NS_LOG_FUNCTION (this);
   NS_LOG_DEBUG ("CommandLine::CallbackItem::Parse \"" << value << "\"");
@@ -418,13 +418,27 @@
 }
 
 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) || (src == "true") || (src == "t"))
+  if (src.length () == 0)
+    {
+      val = ! val;
+      return true;
+    }
+  else if ( (src == "true") || (src == "t") )
     {
       val = true;
       return true;
--- a/src/core/model/command-line.h	Thu Aug 15 14:45:42 2013 -0400
+++ b/src/core/model/command-line.h	Wed Aug 07 10:36:45 2013 -0700
@@ -44,8 +44,25 @@
  * \brief Parse command-line arguments
  *
  * Instances of this class can be used to parse command-line 
- * arguments: programs can register new arguments with
- * CommandLine::AddValue.
+ * arguments.  Programs can register a general usage message with
+ * CommandLine::Usage, and arguments with CommandLine::AddValue.
+ * POD argument variables will be set directly; more general arguments
+ * can be processed via a Callback.
+ *
+ * CommandLine also provides handlers for these standard arguments:
+ * \code
+ *   --PrintGlobals:              Print the list of globals.
+ *   --PrintGroups:               Print the list of groups.
+ *   --PrintGroup=[group]:        Print all TypeIds of group.
+ *   --PrintTypeIds:              Print all TypeIds.
+ *   --PrintAttributes=[typeid]:  Print all attributes of typeid.
+ *   --PrintHelp:                 Print this help message.
+ * \endcode
+ * 
+ * The more common \c --help is a synonym for \c --PrintHelp; an example
+ * is given below.
+ *
+ * Finally, CommandLine processes Attribute and GlobalValue arguments.
  *
  * In use, arguments are given in the form
  * \code
@@ -55,18 +72,20 @@
  * Toggles, corresponding to boolean arguments, can be given in any of
  * the forms
  * \code
- *   --toggle-1 --toggle-2=1 --toggle-3=t --toggle-4=true
+ *   --toggle1 --toggle2=1 --toggle3=t --toggle4=true
  * \endcode
- * all of which set the corresponding boolean variable to true.
+ * The first form changes the state of toggle1 from its default; 
+ * all the rest set the corresponding boolean variable to true.
+ * \c 0, \c f and \c false are accepted to set the variable to false.
  *
- * In addition, this class can be used to set the
- * initial value of every attribute in the system with the 
+ * CommandLine can set the initial value of every attribute in the system
+ * with the 
  * \c --TypeIdName::AttributeName=value syntax, for example
  * \code
  *   --Application::StartTime=3s
  * \endcode
  *
- * This class can also be used to set the value of every GlobalValue
+ * CommandLine can also set the value of every GlobalValue
  * in the system with the \c --GlobalValueName=value syntax, for example
  * \code
  *   --SchedulerType=HeapScheduler
@@ -76,33 +95,37 @@
  * The heart of that example is this code:
  *
  * \code
- *  int         var1 = 1;
- *  bool        var2 = false;
- *  std::string var3 = "";
+ *    int         intArg  = 1;
+ *    bool        boolArg = false;
+ *    std::string strArg  = "strArg default";
  *  
  *  CommandLine cmd;
  *  cmd.Usage ("CommandLine example program.\n"
  *             "\n"
  *             "This little program demonstrates how to use CommandLine.");
- *  cmd.AddValue ("val1", "an int argument",          val1);
- *  cmd.AddValue ("val2", "a bool argument",          val2);
- *  cmd.AddValue ("val3", "a string argument",        val3);
+ *    cmd.AddValue ("intArg",  "an int argument",       intArg);
+ *    cmd.AddValue ("boolArg", "a bool argument",       boolArg);
+ *    cmd.AddValue ("strArg",  "a string argument",     strArg);
+ *    cmd.AddValue ("cbArg",   "a string via callback", MakeCallback (SetCbArg));
  *  cmd.Parse (argc, argv);
  * \endcode
- * after which it prints the values of each variable.
+ * after which it prints the values of each variable.  (The \c SetCbArg function
+ * is not shown.)
  *
  * Here is the output from a few runs of that program:
  *
  * \code
  *   $ ./waf --run="command-line-example"
- *   val1:   1
- *   val2:   0
- *   val3:   ""
+ *   intArg:   1
+ *   boolArg:  false
+ *   strArg:   "strArg default"
+ *   cbArg:    "cbArg default"
  *
- *   $ ./waf --run="command-line-example --val1=2 --val2 --val3=Hello"
- *   val1:   2
- *   val2:   1
- *   val3:   "Hello"
+ *   $ ./waf --run="command-line-example --intArg=2 --boolArg --strArg=Hello --cbArg=World"
+ *   intArg:   2
+ *   boolArg:  true
+ *   strArg:   "Hello"
+ *   cbArg:    "World"
  *   
  *   $ ./waf --run="command-line-example --help"
  *   ns3-dev-command-line-example-debug [Program Arguments] [General Arguments]
@@ -112,9 +135,10 @@
  *   This little program demonstrates how to use CommandLine.
  *   
  *   Program Arguments:
- *       --val1:     an int argument
- *       --val2:     a bool argument
- *       --val3:     a string argument
+ *       --intArg:   an int argument [1]
+ *       --boolArg:  a bool argument [false]
+ *       --strArg:   a string argument [strArg default]
+ *       --cbArg:    a string via callback
  *   
  *   General Arguments:
  *       --PrintGlobals:              Print the list of globals.
@@ -149,7 +173,7 @@
   /**
    * Supply the program usage and documentation.
    *
-   * \param usage Program usage message to write with help.
+   * \param usage Program usage message to write with \c --help.
    */
   void Usage (const std::string usage);
   
@@ -172,9 +196,12 @@
    * Add a program argument, using a Callback to parse the value
    *
    * \param name the name of the program-supplied argument
-   * \param help the help text used by \c \-\-PrintHelp
-   * \param callback a Callback function that will be invoked to parse
-   * and collect the value.  This is normally used by language bindings.
+   * \param help the help text used by \c --help
+   * \param callback a Callback function that will be invoked to parse and
+   *   store the value.
+   *
+   * The callback should have the signature
+   * <tt>bool callback (const std::string value)</tt>
    */
   void AddValue (const std::string &name,
                  const std::string &help,
@@ -237,7 +264,7 @@
      * \param value the string representation
      * \return true if parsing the value succeeded
      */
-    virtual bool Parse (std::string value) = 0;
+    virtual bool Parse (const std::string value) = 0;
     /**
      * \return true if this item have a default value?
      */
@@ -262,7 +289,7 @@
      * \param value the string representation
      * \return true if parsing the value succeeded
      */
-    virtual bool Parse (std::string value);
+    virtual bool Parse (const std::string value);
 
     bool HasDefault () const;
     std::string GetDefault () const;
@@ -284,7 +311,7 @@
      * \param value the string representation
      * \return true if parsing the value succeeded
      */
-    virtual bool Parse (std::string value);
+    virtual bool Parse (const std::string value);
     Callback<bool, std::string> m_callback;  /**< The Callback */
   };
 
@@ -329,15 +356,19 @@
   std::string m_name;                   /**< The program name */
 };  // class CommandLine
 
+
+/** \ingroup commandline
+ *  \defgroup commandlinehelper Helpers to specialize on bool
+ */
 /**
- * \ingroup commandline
- * Helpers for CommandLine
+ * \ingroup commandlinehelper
+ * \brief Helpers for CommandLine to specialize on bool
  */
 namespace CommandLineHelper {
 
   /**
-   * \ingroup commandline
-   * \brief Helper to specialize UserItem on bool
+   * \ingroup commandlinehelper
+   * \brief Helper to specialize UserItem::Parse on bool
    *
    * \param value the argument name
    * \param val the argument location
@@ -350,6 +381,20 @@
   bool UserItemParse<bool> (const std::string value, bool & val);
   /**@}*/
 
+  /**
+   * \ingroup commandlinehelper
+   * \brief Helper to specialize UserItem::GetDefault on bool
+   *
+   * \param val the argument value
+   * \return the string representation of value
+   * @{
+   */
+  template <typename T>
+  std::string GetDefault (const T & val);
+  template <>
+  std::string GetDefault<bool> (const bool & val);
+  /**@}*/
+
 }  // namespace CommandLineHelper
     
   
@@ -388,15 +433,22 @@
 std::string
 CommandLine::UserItem<T>::GetDefault () const
 {
+  return CommandLineHelper::GetDefault<T> (*m_valuePtr);
+}
+
+template <typename T>
+std::string
+CommandLineHelper::GetDefault (const T & val)
+{
   std::ostringstream oss;
-  oss << *m_valuePtr;
+  oss << val;
   return oss.str ();
 }
 
 
 template <typename T>
 bool
-CommandLine::UserItem<T>::Parse (std::string value)
+CommandLine::UserItem<T>::Parse (const std::string value)
 {
   return CommandLineHelper::UserItemParse<T> (value, *m_valuePtr);
 }
@@ -411,26 +463,6 @@
   return !iss.bad () && !iss.fail ();
 }
 
-/**
- * \brief Overloaded operator << to print program usage (shortcut for CommandLine::PrintHelper)
- * \see CommandLine::PrintHelper
- *
- * Example usage:
- * @code
- *       CommandLine cmd;
- *       cmd.Parse (argc, argv);
- *       ...
- *
- *       std::cerr << cmd;
- * @endcode
- */
-inline std::ostream &
-operator << (std::ostream &os, const CommandLine &cmd)
-{
-  cmd.PrintHelp (os);
-  return os;
-}
-
 } // namespace ns3
 
 #endif /* COMMAND_LINE_H */