Bug 289: CommandLine::AddValue is not wrapped
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Wed, 26 Nov 2008 12:11:11 +0000
changeset 3929 909b0a724ed3
parent 3928 c05de2ba481f
child 3931 ccc0b1372100
child 3933 3c149230e98a
Bug 289: CommandLine::AddValue is not wrapped
bindings/python/callbacks_list.py
bindings/python/ns3_module_core.py
bindings/python/ns3module_helpers.cc
bindings/python/ns3modulegen_core_customizations.py
bindings/python/ns3modulescan.py
bindings/python/wscript
src/core/command-line.cc
src/core/command-line.h
utils/python-unit-tests.py
--- a/bindings/python/callbacks_list.py	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/callbacks_list.py	Wed Nov 26 12:11:11 2008 +0000
@@ -5,6 +5,7 @@
     ['void', 'ns3::Ptr<ns3::Socket>', 'unsigned int', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
     ['void', 'ns3::Ptr<ns3::Socket>', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
     ['bool', 'ns3::Ptr<ns3::Socket>', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
+    ['bool', 'std::string', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
     ['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType'],
     ['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::empty', 'ns3::empty'],
     ['void', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType'],
--- a/bindings/python/ns3_module_core.py	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/ns3_module_core.py	Wed Nov 26 12:11:11 2008 +0000
@@ -12,7 +12,7 @@
     ## callback.h: ns3::CallbackImplBase [class]
     module.add_class('CallbackImplBase', allow_subclassing=True, memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
     ## command-line.h: ns3::CommandLine [class]
-    module.add_class('CommandLine')
+    module.add_class('CommandLine', allow_subclassing=True)
     ## system-mutex.h: ns3::CriticalSection [class]
     module.add_class('CriticalSection')
     ## global-value.h: ns3::GlobalValue [class]
@@ -350,6 +350,10 @@
     cls.add_constructor([param('ns3::CommandLine const &', 'arg0')])
     ## command-line.h: ns3::CommandLine::CommandLine() [constructor]
     cls.add_constructor([])
+    ## command-line.h: void ns3::CommandLine::AddValue(std::string const & name, std::string const & help, ns3::Callback<bool, std::string, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty> callback) [member function]
+    cls.add_method('AddValue', 
+                   'void', 
+                   [param('std::string const &', 'name'), param('std::string const &', 'help'), param('ns3::Callback< bool, std::string, ns3::empty, ns3::empty, ns3::empty, ns3::empty, ns3::empty >', 'callback')])
     return
 
 def register_Ns3CriticalSection_methods(root_module, cls):
--- a/bindings/python/ns3module_helpers.cc	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/ns3module_helpers.cc	Wed Nov 26 12:11:11 2008 +0000
@@ -1,3 +1,4 @@
+#include "ns3/ref-count-base.h"
 #include "ns3module.h"
 
 
@@ -220,3 +221,61 @@
     
     return (PyObject *) py_tid;
 }
+
+
+class CommandLinePythonValueSetter : public ns3::RefCountBase
+{
+    PyObject *m_namespace;
+    std::string m_variable;
+public:
+    CommandLinePythonValueSetter (PyObject *ns, std::string const &variable) {
+        Py_INCREF(ns);
+        m_namespace = ns;
+        m_variable = variable;
+    }
+    bool Parse (std::string value) {
+        PyObject *pyvalue = PyString_FromStringAndSize (value.data(), value.size());
+        PyObject_SetAttrString (m_namespace, m_variable.c_str(), pyvalue);
+        if (PyErr_Occurred()) {
+            PyErr_Print();
+            return false;
+        }
+        return true;
+    }
+    virtual ~CommandLinePythonValueSetter () {
+        Py_DECREF (m_namespace);
+        m_namespace = NULL;
+    }
+    
+};
+
+PyObject *
+_wrap_CommandLine_AddValue(PyNs3CommandLine *self, PyObject *args, PyObject *kwargs,
+                           PyObject **return_exception)
+{
+    const char *name, *help, *variable = NULL;
+    PyObject *py_namespace = NULL;
+    const char *keywords[] = {"name", "help", "variable", "namespace", NULL};
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ss|sO", (char **) keywords, &name, &help, &variable, &py_namespace)) {
+        PyObject *exc_type, *traceback;
+        PyErr_Fetch(&exc_type, return_exception, &traceback);
+        Py_XDECREF(exc_type);
+        Py_XDECREF(traceback);
+        return NULL;
+    }
+    
+    if (variable == NULL) {
+        variable = name;
+    }
+    if (py_namespace == NULL) {
+        py_namespace = (PyObject *) self;
+    }
+
+    ns3::Ptr<CommandLinePythonValueSetter> setter = ns3::Create<CommandLinePythonValueSetter> (py_namespace, variable);
+    self->obj->AddValue (name, help, ns3::MakeCallback (&CommandLinePythonValueSetter::Parse, setter));
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
--- a/bindings/python/ns3modulegen_core_customizations.py	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/ns3modulegen_core_customizations.py	Wed Nov 26 12:11:11 2008 +0000
@@ -292,6 +292,8 @@
     CommandLine = module['ns3::CommandLine']
     CommandLine.add_method('Parse', None, [ArgvParam(None, 'argv')],
                            is_static=False)
+    CommandLine.add_custom_method_wrapper("AddValue", "_wrap_CommandLine_AddValue",
+                                          flags=["METH_VARARGS", "METH_KEYWORDS"])
 
 
 def Object_customizations(module):
@@ -523,5 +525,5 @@
     TypeId = module['ns3::TypeId']
     TypeId.add_custom_method_wrapper("LookupByNameFailSafe", "_wrap_TypeId_LookupByNameFailSafe",
                                      flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"])
-    
 
+
--- a/bindings/python/ns3modulescan.py	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/ns3modulescan.py	Wed Nov 26 12:11:11 2008 +0000
@@ -56,6 +56,11 @@
         'automatic_type_narrowing': 'true',
         'allow_subclassing': 'false',
         },
+
+    '::ns3::CommandLine': {
+        'allow_subclassing': 'true', # needed so that AddValue is able to set attributes on the object
+        },
+
     'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': {
         'ignore': None,
         },
--- a/bindings/python/wscript	Wed Nov 26 11:45:53 2008 +0000
+++ b/bindings/python/wscript	Wed Nov 26 12:11:11 2008 +0000
@@ -309,6 +309,7 @@
    t1 > t2;
 }
 
+
 }
 """
     outfile.close()
--- a/src/core/command-line.cc	Wed Nov 26 11:45:53 2008 +0000
+++ b/src/core/command-line.cc	Wed Nov 26 12:11:11 2008 +0000
@@ -253,6 +253,27 @@
     }
 }
 
+bool
+CommandLine::CallbackItem::Parse (std::string value)
+{
+  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);
+}
+
+
 } // namespace ns3
 
 #ifdef RUN_SELF_TESTS
--- a/src/core/command-line.h	Wed Nov 26 11:45:53 2008 +0000
+++ b/src/core/command-line.h	Wed Nov 26 12:11:11 2008 +0000
@@ -24,6 +24,8 @@
 #include <sstream>
 #include <list>
 
+#include "ns3/callback.h"
+
 namespace ns3 {
 
 /**
@@ -56,6 +58,17 @@
 		 const std::string &help,
 		 T &value);
 
+
+  /**
+   * \param name the name of the user-supplied argument
+   * \param help some help text used by --PrintHelp
+   * \param callback a callback function that will be invoked to parse
+   * and collect the value.  This normally used by language bindings.
+   */
+  void AddValue (const std::string &name,
+		 const std::string &help,
+                 Callback<bool, std::string> callback);
+
   /**
    * \param argc the 'argc' variable: number of arguments (including the
    *        main program name as first element).
@@ -82,6 +95,13 @@
     virtual bool Parse (std::string value);
     T *m_valuePtr;
   };
+  class CallbackItem : public Item
+  {
+  public:
+    virtual bool Parse (std::string value);
+    Callback<bool, std::string> m_callback;
+  };
+
   void HandleArgument (std::string name, std::string value) const;
   void PrintHelp (void) const;
   void PrintGlobals (void) const;
--- a/utils/python-unit-tests.py	Wed Nov 26 11:45:53 2008 +0000
+++ b/utils/python-unit-tests.py	Wed Nov 26 12:11:11 2008 +0000
@@ -123,5 +123,26 @@
         
         self.assertRaises(KeyError, ns3.TypeId.LookupByNameFailSafe, "__InvalidTypeName__")
 
+    def testCommandLine(self):
+        cmd = ns3.CommandLine()
+        cmd.AddValue("Test1", "this is a test option")
+        cmd.AddValue("Test2", "this is a test option")
+        cmd.AddValue("Test3", "this is a test option", variable="test_xxx")
+        cmd.Test1 = None
+        cmd.Test2 = None
+        cmd.test_xxx = None
+        class Foo:
+            pass
+        foo = Foo()
+        foo.test_foo = None
+        cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo)
+        
+        cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"])
+
+        self.assertEqual(cmd.Test1, "value1")
+        self.assertEqual(cmd.Test2, "value2")
+        self.assertEqual(cmd.test_xxx, "123")
+        self.assertEqual(foo.test_foo, "xpto")
+
 if __name__ == '__main__':
     unittest.main()