Add ability to specify multiple apps to run on each node

refs: #2933

Change-Id: Ic5d47bb3e9ab830f01b55be37848aa680174cf32
diff --git a/bin/minindn b/bin/minindn
index 2699bfd..9b183a0 100755
--- a/bin/minindn
+++ b/bin/minindn
@@ -200,8 +200,10 @@
 
     for host in net.hosts:
         if 'app' in host.params:
-            if host.params['app'] != '_':
-                host.cmd(host.params['app'])
+            if host.params['app'] != '':
+                app = host.params['app']
+                print "Starting " + app + " on node " + host.name
+                print(host.cmd(app))
 
     # Load experiment
     if experimentName is not None:
diff --git a/bin/minindnedit b/bin/minindnedit
index c6e4945..bb6e030 100755
--- a/bin/minindnedit
+++ b/bin/minindnedit
@@ -197,10 +197,13 @@
             # Start command
             #print self.isRouter
             if self.isRouter == 'False':
-                    Label(self.propFrame, text="Start Command:").grid(row=5, sticky=E)
-                    self.startEntry = Entry(self.propFrame)
-                    self.startEntry.grid(row=5, column=1, sticky='nswe', columnspan=3)
-                    Label(self.propFrame, text="[full path]").grid(row=5, column=2, sticky=W)
+                    Label(self.propFrame, text="Start Command(s):").grid(row=5, sticky=E)
+                    self.scrollbar = Scrollbar(self.propFrame, orient="horizontal")
+                    self.startEntry = Entry(self.propFrame, xscrollcommand=self.scrollbar.set,)
+                    self.startEntry.grid(row=5, column=1)
+                    self.scrollbar.grid(row=6, column=1, sticky=N+S+E+W)
+                    self.scrollbar.config(command=self.startEntry.xview)
+                    Label(self.propFrame, text="[Use bash syntax]").grid(row=5, column=2, sticky=W)
                     if 'startCommand' in self.prefValues:
                         self.startEntry.insert(0, str(self.prefValues['startCommand']))
             else:
@@ -711,7 +714,8 @@
                 hOpts=self.hostOpts[name]
                 template.write(name + ': ')
                 if 'startCommand' in hOpts:
-                        template.write(hOpts['startCommand'] + ' ')
+                        cmds = hOpts['startCommand'].replace("\"", "\\\"")
+                        template.write('apps="%s" ' % cmds)
                 else:
                         template.write('_ ')
                 if 'cache' in hOpts:
diff --git a/ndn/conf_parser.py b/ndn/conf_parser.py
index 395c6d7..b6b6ca3 100644
--- a/ndn/conf_parser.py
+++ b/ndn/conf_parser.py
@@ -1,4 +1,5 @@
 import ConfigParser, re
+import shlex
 
 class confNDNHost():
 
@@ -58,9 +59,7 @@
 
         name = item[0]
 
-        rest = item[1].split()
-
-        app = rest.pop(0)
+        rest = shlex.split(item[1])
 
         uris = rest
         params = {}
@@ -77,6 +76,10 @@
                 cache = uri.split('=')[1]
             elif re.match("mem",uri):
                 mem = uri.split('=')[1]
+            elif re.match("app",uri):
+                app = uri.split('=')[1]
+            elif re.match("_", uri):
+                app = ""
             else:
                 params[uri.split('=')[0]] = uri.split('=')[1]