From 702b0ad636ee11a10d175bc57d6d4e86ba151e1d Mon Sep 17 00:00:00 2001
From: Gareth Tribello <gareth.tribello@gmail.com>
Date: Thu, 9 Aug 2012 16:21:36 +0200
Subject: [PATCH] Added parsing for command line tools that works like actions.
  This makes command line tools easy to document in the same manner as Actions
 are easy to document

---
 regtest/rt-mpi0/config  |   2 +-
 regtest/rt-mpi1/config  |   2 +-
 regtest/rt0/config      |   2 +-
 regtest/rt1/config      |   2 +-
 regtest/rt10/config     |   2 +-
 regtest/rt11/config     |   2 +-
 regtest/rt12/config     |   2 +-
 regtest/rt14/config     |   2 +-
 regtest/rt15/config     |   2 +-
 regtest/rt16/config     |   2 +-
 regtest/rt17/config     |   2 +-
 regtest/rt18/config     |   2 +-
 regtest/rt19-mpi/config |   2 +-
 regtest/rt19/config     |   2 +-
 regtest/rt2/config      |   2 +-
 regtest/rt20-mpi/config |   2 +-
 regtest/rt20/config     |   2 +-
 regtest/rt21/config     |   2 +-
 regtest/rt22/config     |   2 +-
 regtest/rt23/config     |   2 +-
 regtest/rt24/config     |   2 +-
 regtest/rt25/config     |   2 +-
 regtest/rt26/config     |   2 +-
 regtest/rt27/config     |   2 +-
 regtest/rt28/config     |   2 +-
 regtest/rt29/config     |   2 +-
 regtest/rt3/config      |   2 +-
 regtest/rt30/config     |   2 +-
 regtest/rt31/config     |   2 +-
 regtest/rt32/config     |   2 +-
 regtest/rt33/config     |   2 +-
 regtest/rt34/config     |   2 +-
 regtest/rt35/config     |   2 +-
 regtest/rt36/config     |   2 +-
 regtest/rt37/config     |   2 +-
 regtest/rt4/config      |   2 +-
 regtest/rt5/config      |   2 +-
 regtest/rt6/config      |   2 +-
 regtest/rt7/config      |   2 +-
 regtest/rt8/config      |   2 +-
 regtest/rt9/config      |   2 +-
 src/ActionRegister.cpp  |   2 +-
 src/CLTool.cpp          | 193 ++++++++++++++++++++++++++++++++++++++++
 src/CLTool.h            |  62 +++++++++++--
 src/CLToolDriver.cpp    | 193 +++++++++++++++++-----------------------
 src/CLToolInfo.cpp      |  76 +++++++---------
 src/CLToolMain.cpp      |   8 +-
 src/CLToolManual.cpp    |  87 ++++++++----------
 src/CLToolRegister.cpp  |  19 +++-
 src/CLToolRegister.h    |  13 ++-
 src/CLToolSimpleMD.cpp  | 176 ++++++++++++++++++------------------
 src/Keywords.cpp        |  76 +++++++++++++++-
 src/Keywords.h          |  10 ++-
 src/Tools.cpp           |   6 ++
 src/Tools.h             |   2 +
 55 files changed, 651 insertions(+), 354 deletions(-)
 create mode 100644 src/CLTool.cpp

diff --git a/regtest/rt-mpi0/config b/regtest/rt-mpi0/config
index 28f95533b..714d1d6dd 100644
--- a/regtest/rt-mpi0/config
+++ b/regtest/rt-mpi0/config
@@ -1,5 +1,5 @@
 mpiprocs=4
 type=driver
 # this is to test a different name
-arg="--plumed=plumed.dat --timestep=0.05 trajectory.xyz --dump-forces ff"
+arg="--plumed=plumed.dat --timestep=0.05 --ixyz trajectory.xyz --dump-forces ff"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt-mpi1/config b/regtest/rt-mpi1/config
index 30fb3be36..fd743c293 100644
--- a/regtest/rt-mpi1/config
+++ b/regtest/rt-mpi1/config
@@ -1,5 +1,5 @@
 mpiprocs=4
 type=driver
 # this is to test a different name
-arg="--plumed=plumed.dat --timestep=0.05 trajectory.xyz --dump-forces ff  --debug-pd"
+arg="--plumed=plumed.dat --timestep=0.05 --ixyz trajectory.xyz --dump-forces ff  --debug-pd"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt0/config b/regtest/rt0/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt0/config
+++ b/regtest/rt0/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt1/config b/regtest/rt1/config
index f2791e103..d343ccfdc 100644
--- a/regtest/rt1/config
+++ b/regtest/rt1/config
@@ -3,4 +3,4 @@
 # to avoid problems with the numerical derivatives (it is exactly at the border between
 # two images)
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
diff --git a/regtest/rt10/config b/regtest/rt10/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt10/config
+++ b/regtest/rt10/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt11/config b/regtest/rt11/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt11/config
+++ b/regtest/rt11/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt12/config b/regtest/rt12/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt12/config
+++ b/regtest/rt12/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt14/config b/regtest/rt14/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt14/config
+++ b/regtest/rt14/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt15/config b/regtest/rt15/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt15/config
+++ b/regtest/rt15/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt16/config b/regtest/rt16/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt16/config
+++ b/regtest/rt16/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt17/config b/regtest/rt17/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt17/config
+++ b/regtest/rt17/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt18/config b/regtest/rt18/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt18/config
+++ b/regtest/rt18/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt19-mpi/config b/regtest/rt19-mpi/config
index ecb920ffc..36dba8dbc 100644
--- a/regtest/rt19-mpi/config
+++ b/regtest/rt19-mpi/config
@@ -1,5 +1,5 @@
 mpiprocs=4
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt19/config b/regtest/rt19/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt19/config
+++ b/regtest/rt19/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt2/config b/regtest/rt2/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt2/config
+++ b/regtest/rt2/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt20-mpi/config b/regtest/rt20-mpi/config
index ecb920ffc..36dba8dbc 100644
--- a/regtest/rt20-mpi/config
+++ b/regtest/rt20-mpi/config
@@ -1,5 +1,5 @@
 mpiprocs=4
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt20/config b/regtest/rt20/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt20/config
+++ b/regtest/rt20/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt21/config b/regtest/rt21/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt21/config
+++ b/regtest/rt21/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt22/config b/regtest/rt22/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt22/config
+++ b/regtest/rt22/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt23/config b/regtest/rt23/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt23/config
+++ b/regtest/rt23/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt24/config b/regtest/rt24/config
index 47df6596d..192611df2 100644
--- a/regtest/rt24/config
+++ b/regtest/rt24/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt25/config b/regtest/rt25/config
index 47df6596d..192611df2 100644
--- a/regtest/rt25/config
+++ b/regtest/rt25/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt26/config b/regtest/rt26/config
index e592546b3..0a8ccbb18 100644
--- a/regtest/rt26/config
+++ b/regtest/rt26/config
@@ -1,3 +1,3 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt27/config b/regtest/rt27/config
index e592546b3..0a8ccbb18 100644
--- a/regtest/rt27/config
+++ b/regtest/rt27/config
@@ -1,3 +1,3 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt28/config b/regtest/rt28/config
index e441f5aec..ae36d62c2 100644
--- a/regtest/rt28/config
+++ b/regtest/rt28/config
@@ -1,3 +1,3 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
diff --git a/regtest/rt29/config b/regtest/rt29/config
index e441f5aec..ae36d62c2 100644
--- a/regtest/rt29/config
+++ b/regtest/rt29/config
@@ -1,3 +1,3 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
diff --git a/regtest/rt3/config b/regtest/rt3/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt3/config
+++ b/regtest/rt3/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt30/config b/regtest/rt30/config
index ee245fbbb..980c469ec 100644
--- a/regtest/rt30/config
+++ b/regtest/rt30/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt31/config b/regtest/rt31/config
index ee245fbbb..980c469ec 100644
--- a/regtest/rt31/config
+++ b/regtest/rt31/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt32/config b/regtest/rt32/config
index ee245fbbb..980c469ec 100644
--- a/regtest/rt32/config
+++ b/regtest/rt32/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz ala12_trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt33/config b/regtest/rt33/config
index 7d0e9d21d..b3efe6c3c 100644
--- a/regtest/rt33/config
+++ b/regtest/rt33/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 amyloid.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz amyloid.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt34/config b/regtest/rt34/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt34/config
+++ b/regtest/rt34/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt35/config b/regtest/rt35/config
index cbf38b9c3..45386cb93 100644
--- a/regtest/rt35/config
+++ b/regtest/rt35/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 ../../trajectories/diala_traj_nm.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz ../../trajectories/diala_traj_nm.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt36/config b/regtest/rt36/config
index 20af628e0..fce7937b0 100644
--- a/regtest/rt36/config
+++ b/regtest/rt36/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt37/config b/regtest/rt37/config
index cbf38b9c3..45386cb93 100644
--- a/regtest/rt37/config
+++ b/regtest/rt37/config
@@ -1,2 +1,2 @@
 type=driver
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 ../../trajectories/diala_traj_nm.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz ../../trajectories/diala_traj_nm.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
diff --git a/regtest/rt4/config b/regtest/rt4/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt4/config
+++ b/regtest/rt4/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt5/config b/regtest/rt5/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt5/config
+++ b/regtest/rt5/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt6/config b/regtest/rt6/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt6/config
+++ b/regtest/rt6/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt7/config b/regtest/rt7/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt7/config
+++ b/regtest/rt7/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt8/config b/regtest/rt8/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt8/config
+++ b/regtest/rt8/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/regtest/rt9/config b/regtest/rt9/config
index 623ad3cc5..a87726a91 100644
--- a/regtest/rt9/config
+++ b/regtest/rt9/config
@@ -1,4 +1,4 @@
 type=driver
 # this is to test a different name
-arg="--plumed plumed.dat --stride 10 --timestep 0.005 trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
+arg="--plumed plumed.dat --stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%10.6f"
 extra_files="../trajectories/trajectory.xyz"
diff --git a/src/ActionRegister.cpp b/src/ActionRegister.cpp
index fd976193c..87d0081c6 100644
--- a/src/ActionRegister.cpp
+++ b/src/ActionRegister.cpp
@@ -89,7 +89,7 @@ Action* ActionRegister::create(const ActionOptions&ao){
 bool ActionRegister::printManual( const std::string& action ){
   if ( check(action) ){
      Keywords keys; mk[action](keys); 
-     keys.print_html(); keys.destroyData();
+     keys.print_html(true); keys.destroyData();
      return true;
   } else {
      return false;
diff --git a/src/CLTool.cpp b/src/CLTool.cpp
new file mode 100644
index 000000000..6a4b749d1
--- /dev/null
+++ b/src/CLTool.cpp
@@ -0,0 +1,193 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 The plumed team
+   (see the PEOPLE file at the root of the distribution for a list of names)
+
+   See http://www.plumed-code.org for more information.
+
+   This file is part of plumed, version 2.0.
+
+   plumed is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   plumed 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#include "CLTool.h"
+
+using namespace PLMD;
+
+Keywords CLToolOptions::emptyKeys;
+
+CLToolOptions::CLToolOptions(const std::string &name): 
+line(1,name), 
+keys(emptyKeys) 
+{
+}
+
+CLToolOptions::CLToolOptions(const CLToolOptions& co, const Keywords& k):
+line(co.line), 
+keys(k) 
+{
+}
+
+void CLTool::registerKeywords( Keywords& keys ){
+  keys.addFlag("--help",false,"print this help");
+}
+
+CLTool::CLTool(const CLToolOptions& co ): 
+name(co.line[0]),
+keywords(co.keys),
+inputdata(unset)
+{
+}
+
+void CLTool::parseFlag( const std::string&key, bool&t ){
+  plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
+  plumed_massert(keywords.style(key,"flag"),"keyword " + key + " has not been registered as a flag");
+  plumed_assert(inputData.count(key)>0); 
+  if( inputData[key]=="true") t=true;
+  else if( inputData[key]=="false") t=false;
+  else plumed_assert(0);
+}
+
+bool CLTool::readInput( int argc, char**argv, FILE* in, FILE*out ){
+  plumed_massert( inputdata!=unset,"You have not specified where your tool reads its input. "
+                                   "If it is from the command line (like driver) add inputdata=commandline to the "
+                                   "tools constructor. If it reads everything from an input file (like simplemd) "
+                                   "add inputdata=ifile to the tools constructor");
+  if(inputdata==commandline) return readCommandLineArgs( argc, argv, out );
+  if(inputdata==ifile) return readInputFile( argc, argv, in, out );
+  readInput( argc, argv, in, out );   // This allows the user to specify the particular form for input
+  return true;
+}
+
+bool CLTool::readCommandLineArgs( int argc, char**argv, FILE*out ){
+  plumed_assert(inputdata==commandline);
+  std::string prefix(""), a(""), thiskey;
+
+  // Set all flags to default false
+  for(int k=0;k<keywords.size();++k){
+      thiskey=keywords.get(k);
+      if( keywords.style(thiskey,"flag") ) inputData.insert(std::pair<std::string,std::string>(thiskey,"false"));
+  }
+
+  // Read command line arguments
+  bool printhelp=false;
+  for(int i=1;i<argc;i++){
+      a=prefix+argv[i];
+      if(a.length()==0) continue;
+      if(a=="-h" || a=="--help"){
+         printhelp=true;
+      } else {
+         bool found=false;
+         for(int k=0;k<keywords.size();++k){
+           thiskey=keywords.get(k);
+           if( keywords.style(thiskey,"flag") ){
+               if( a==thiskey ){ found=true; inputData[thiskey]="true"; }
+           } else {
+               if( a==thiskey ){
+                   prefix=thiskey+"="; found=true;
+                   inputData.insert(std::pair<std::string,std::string>(thiskey,""));
+               } else if( a.find(thiskey+"=")==0){
+                   a.erase(0,a.find("=")+1); prefix=""; found=true;
+                   if(inputData.count(thiskey)==0){
+                      inputData.insert(std::pair<std::string,std::string>(thiskey,a));
+                   } else {
+                      inputData[thiskey]=a;
+                   }
+               }
+           }
+         }
+         if(!found){
+            fprintf(out,"ERROR : unknown option %s\n\n", a.c_str() );
+            printhelp=true;
+         }
+      }
+      if(printhelp) break;
+  }
+
+  if(!printhelp) setRemainingToDefault(out);
+
+  if(printhelp){
+     fprintf(out,"Usage: %s [options] \n\n", name.c_str() );
+     keywords.print( out ); 
+  }
+
+  return !printhelp;
+}
+
+void CLTool::setRemainingToDefault(FILE* out){
+  std::string def, thiskey;
+  for(int k=0;k<keywords.size();++k){
+      thiskey=keywords.get(k);
+      if( keywords.style(thiskey,"compulsory") ){
+          if( inputData.count(thiskey)==0 ){
+             if( keywords.getDefaultValue(thiskey,def) ){
+                 plumed_assert( def.length()>0 );
+                 inputData.insert(std::pair<std::string,std::string>(thiskey,def));
+             } else {
+                 fprintf(out,"ERROR : argument %s is compulsory. Use --help option for help\n",thiskey.c_str() );
+             }
+          }
+      }
+  }
+}
+
+bool CLTool::readInputFile( int argc, char**argv, FILE* in, FILE*out ){
+  plumed_assert(inputdata==ifile);
+
+  // Check if use is just asking for help
+  std::string a;
+  for(int i=1;i<argc;i++){
+      a=argv[i];
+      if(a.length()==0) continue;
+      if(a=="-h" || a=="--help"){
+         fprintf(out,"Usage: %s < inputFile \n", name.c_str() );
+         fprintf(out,"inputFile should contain one directive per line.  The directives should come from amongst the following\n\n");
+         keywords.print( out );
+         return false;
+      }
+  }
+
+  FILE* mystdin=in;
+  if(argc==2) mystdin=fopen(argv[1],"r");
+
+  char buffer[256]; std::string line; line.resize(256);
+  while(fgets(buffer,256,mystdin)){
+     line=buffer; 
+     for(int i=0;i<line.length();++i) if(line[i]=='#' || line[i]=='\n') line.erase(i);
+     Tools::stripLeadingAndTrailingBlanks( line );
+     if(line.length()==0) continue;
+     sscanf(line.c_str(),"%s",buffer);
+     std::string keyword=buffer; bool found=false;
+     for(unsigned i=0;i<keywords.size();++i){
+         std::string thiskey=keywords.get(i);
+         if(thiskey==keyword){
+            found=true;
+            std::size_t keypos=line.find_first_of(keyword)+keyword.length();
+            inputData.insert(std::pair<std::string,std::string>(thiskey,line.substr(keypos))); 
+            Tools::stripLeadingAndTrailingBlanks( inputData[thiskey] );
+         }
+     }
+     if(!found){
+        fprintf(stderr,"Unknown keyword found in input file :%s\n",keyword.c_str());
+        return false;
+     }
+  }
+
+  if(argc==2) fclose(mystdin);
+  setRemainingToDefault(out);
+  return true;
+}
+
+void CLTool::readInputData( int argc, char**argv, FILE* in, FILE*out ){
+  plumed_assert( inputdata!=commandline && inputdata!=ifile );
+  if( inputdata==userspec ) plumed_massert(0, "You have to actually write the routine in the base class!");
+}
diff --git a/src/CLTool.h b/src/CLTool.h
index 1dc435baa..354e608d3 100644
--- a/src/CLTool.h
+++ b/src/CLTool.h
@@ -25,17 +25,25 @@
 #include <cstdio>
 #include <vector>
 #include <string>
+#include <cstdio>
+#include "Tools.h"
+#include "Keywords.h"
 
 namespace PLMD{
 
 class PlumedCommunicator;
 
 class CLToolOptions{
+  friend class CLTool;
   friend class CLToolRegister;
+private:
   std::vector<std::string> line;
+/// The documentation for this command line tool
+  const Keywords& keys;
+  static Keywords emptyKeys;
 public:
-  CLToolOptions(const std::string &name):
-    line(1,name) { }
+  CLToolOptions(const std::string &name);
+  CLToolOptions(const CLToolOptions& co, const Keywords& k);
 };
 
 /**
@@ -44,18 +52,62 @@ Interface to all the command-line tools.
 This class just define an interface, and does not implement anything.
 Inherits from this class to create a new command-line tool.
 */
-class CLTool
-{
+class CLTool {
+// This is a fried so we can create input data quickly
+// when you do debug-float. 
+template <typename real>
+friend class CLToolDriver;
+private:
+/// The name of this command line tool
+  const std::string name;
+/// The list of keywords for this CLTool
+  const Keywords& keywords;
+/// The data read in from the command line stored in a map with the keywords
+  std::map<std::string,std::string> inputData;
+/// Read the arguments from the command line
+  bool readCommandLineArgs( int argc, char**argv, FILE*out );
+/// Read the arguments from an input file specified on the command line
+  bool readInputFile( int argc, char**argv, FILE* in, FILE*out );
+/// Set arguments from the default options provided to Keywords
+  void setRemainingToDefault(FILE* out);
+protected:
+/// Get the value of one of the command line arguments 
+  template<class T>
+  bool parse(const std::string&key,T&t);
+/// Find out whether one of the command line flags is present or not
+  void parseFlag(const std::string&key,bool&t);  
 public:
+/// How is the input specified on the command line or in an input file
+  enum {unset,commandline,ifile,userspec} inputdata;
+/// Create the help keywords 
+  static void registerKeywords( Keywords& keys );
+  CLTool(const CLToolOptions& co ); 
+/// Read the arguments from the command line
+  bool readInput( int argc, char**argv, FILE* in, FILE*out );
+/// Read the input in the derived class (overwrite this if you are not using 
+/// command line arguments or an input file in the style of simplemd's)
+  virtual void readInputData( int argc, char**argv, FILE* in, FILE*out );
 /// virtual function mapping to the specific main for each tool
-  virtual int main(int argc, char **argv,FILE*in,FILE*out,PlumedCommunicator&pc)=0;
+  virtual int main( FILE*out, PlumedCommunicator&pc )=0;
 /// virtual function returning a one-line descriptor for the tool
   virtual std::string description()const{return "(no description available)";};
 /// virtual destructor to allow inheritance
   virtual ~CLTool(){};
 };
 
+template<class T>
+bool CLTool::parse(const std::string&key,T&t){
+  plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
+  if(keywords.style(key,"compulsory") ){
+     plumed_assert(inputData.count(key)>0);
+     plumed_assert( Tools::convert(inputData[key],t) );
+     return true;
+  }
+  if( inputData.count(key)==0 ) return false; 
+  Tools::convert(inputData[key],t);
+  return true;
 }
 
+}
 
 #endif
diff --git a/src/CLToolDriver.cpp b/src/CLToolDriver.cpp
index 73b155e44..b1c9e6721 100644
--- a/src/CLToolDriver.cpp
+++ b/src/CLToolDriver.cpp
@@ -34,21 +34,53 @@ using namespace std;
 namespace PLMD {
 
 //+PLUMEDOC TOOLS driver
-/**
-driver is a tool that allows one to to use plumed to post-process
-an existing trajectory.
+/*
+driver is a tool that allows one to to use plumed to post-process an existing trajectory.
+
+The input to driver is specified using the command line arguments described below.
+
+\par Examples
+
+The following command tells plumed to postprocess the trajectory contained in trajectory.xyz
+ by calcualting the actions described in the input file plumed.dat.
+\verbatim
+plumed driver --plumed plumed.dat --ixyz trajectory.xyz
+\endverbatim
+
 */
 //+ENDPLUMEDOC
 
 template<typename real>
-class CLToolDriver:
-public CLTool
-{
+class CLToolDriver : public CLTool {
 public:
-  int main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc);
+  static void registerKeywords( Keywords& keys );
+  CLToolDriver(const CLToolOptions& co );
+  int main(FILE*out,PlumedCommunicator& pc);
   string description()const;
 };
 
+template<typename real>
+void CLToolDriver<real>::registerKeywords( Keywords& keys ){
+  CLTool::registerKeywords( keys );
+  keys.addFlag("--help-debug",false,"print special options that can be used to create regtests");
+  keys.add("compulsory","--plumed","plumed.dat","specify the name of the plumed input file");
+  keys.add("compulsory","--timestep","0.001","the timestep for the trajectory in picoseconds");
+  keys.add("compulsory","--stride","1","stride between frames on which to do the calculation");
+  keys.add("atoms","--ixyz","the trajectory in xyz format");
+  keys.add("optional","--dump-forces","dump the forces on a file");
+  keys.add("optional","--dump-forces-fmt","( default=%%f ) the format to use to dump the forces");
+  keys.add("hidden","--debug-float","turns on the single precision version (to check float interface)");
+  keys.add("hidden","--debug-dd","use a fake domain decomposition");
+  keys.add("hidden","--debug-pd","use a fake particle decomposition");
+}
+
+template<typename real>
+CLToolDriver<real>::CLToolDriver(const CLToolOptions& co ):
+CLTool(co)
+{
+ inputdata=commandline;
+}
+
 template<typename real>
 string CLToolDriver<real>::description()const{ return "analyze trajectories with plumed"; }
 
@@ -57,110 +89,49 @@ string CLToolDriver<float>::description()const{ return "analyze trajectories wit
 
 
 template<typename real>
-int CLToolDriver<real>::main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc){
-
-// to avoid warnings:
- (void) in;
-
- string plumedFile("plumed.dat");
- string dumpforces("");
- string dumpforcesFmt("%f");
- string trajectoryFile("");
- real timestep(real(0.001));
- unsigned stride(1);
- bool printhelp=false;
- bool printhelpdebug=false;
- bool debug_dd=false;
- bool debug_pd=false;
-
-// Start parsing options
-  string prefix("");
-  string a("");
-  for(int i=1;i<argc;i++){
-    a=prefix+argv[i];
-    if(a.length()==0) continue;
-    if(a=="-h" || a=="--help"){
-      printhelp=true;
-      break;
-    } else if(a=="--help-debug"){
-      printhelp=true;
-      printhelpdebug=true;
-      break;
-    } else if(a=="--debug-float"){
-      if(sizeof(real)!=sizeof(float)){
-        CLTool* cl=new CLToolDriver<float>;
-        int ret=cl->main(argc,argv,in,out,pc);
-        delete cl;
-        return ret;
-      }
-    } else if(a=="--debug-pd"){
-      debug_pd=true;
-    } else if(a=="--debug-dd"){
-      debug_dd=true;
-    } else if(a.find("--plumed=")==0){
-      a.erase(0,a.find("=")+1);
-      plumedFile=a;
-      prefix="";
-    } else if(a=="--plumed"){
-      prefix="--plumed=";
-    } else if(a.find("--timestep=")==0){
-      a.erase(0,a.find("=")+1);
-      double t;
-      Tools::convert(a,t);
-      timestep=real(t);
-      prefix="";
-    } else if(a=="--timestep"){
-      prefix="--timestep=";
-    } else if(a.find("--stride=")==0){
-      a.erase(0,a.find("=")+1);
-      Tools::convert(a,stride);
-      prefix="";
-    } else if(a=="--stride"){
-      prefix="--stride=";
-    } else if(a.find("--dump-forces=")==0){
-      a.erase(0,a.find("=")+1);
-      dumpforces=a;
-      prefix="";
-    } else if(a=="--dump-forces"){
-      prefix="--dump-forces=";
-    } else if(a.find("--dump-forces-fmt=")==0){
-      a.erase(0,a.find("=")+1);
-      dumpforcesFmt=a;
-      prefix="";
-    } else if(a=="--dump-forces-fmt"){
-      prefix="--dump-forces-fmt=";
-    } else if(a[0]=='-') {
-      string msg="ERROR: Unknown option " +a;
-      fprintf(stderr,"%s\n",msg.c_str());
-      return 1;
-    } else if(trajectoryFile.length()==0){
-      trajectoryFile=a;
-    } else {
-      string msg="ERROR: maximum one file at a time";
-      fprintf(stderr,"%s\n",msg.c_str());
-      return 1;
-    }
+int CLToolDriver<real>::main(FILE*out,PlumedCommunicator& pc){
+
+// Parse everything
+  bool printhelpdebug; parseFlag("--help-debug",printhelpdebug);
+  if( printhelpdebug ){
+      fprintf(out,"%s",
+         "Additional options for debug (only to be used in regtest):\n"
+         "  [--debug-float]         : turns on the single precision version (to check float interface)\n"
+         "  [--debug-dd]            : use a fake domain decomposition\n"
+         "  [--debug-pd]            : use a fake particle decomposition\n"
+      );
+      return 0;
+  }
+  std::string fakein; 
+  bool debugfloat=parse("--debug-float",fakein);
+  if(debugfloat && sizeof(real)!=sizeof(float)){
+      CLTool* cl=cltoolRegister().create(CLToolOptions("driver-float"));    //new CLToolDriver<float>(*this);
+      cl->inputData=this->inputData; 
+      int ret=cl->main(out,pc);
+      delete cl;
+      return ret;
   }
 
-  if(printhelp){
-    fprintf(out,"%s",
- "Usage: driver [options] trajectory.xyz\n"
- "Options:\n"
- "  [--help|-h]             : prints this help\n"
- "  [--help-debug]          : prints this help plus special options for debug\n"
- "  [--plumed FILE]         : plumed script file (default: plumed.dat)\n"
- "  [--timestep TS]         : timestep (default: 0.001) in picoseconds\n"
- "  [--stride ST]           : stride between frames (default: 1)\n"
- "  [--dump-forces FILE]    : dump forces on file FILE (default: do not dump)\n"
- "  [--dump-forces-fmt FMT] : dump forces on file FILE (default: %f)\n"
-);
-  if(printhelpdebug)
-    fprintf(out,"%s",
- "Additional options for debug (only to be used in regtest):\n"
- "  [--debug-float]         : turns on the single precision version (to check float interface)\n"
- "  [--debug-dd]            : use a fake domain decomposition\n"
- "  [--debug-pd]            : use a fake particle decomposition\n"
-);
+  bool debug_pd=parse("--debug-pd",fakein);
+  bool debug_dd=parse("--debug-dd",fakein);
+// Read the plumed input file name  
+  string plumedFile; parse("--plumed",plumedFile);
+// the timestep
+  double t; parse("--timestep",t);
+  real timestep=real(t);
+// the stride
+  unsigned stride; parse("--stride",stride);
+// are we writing forces
+  string dumpforces(""), dumpforcesFmt("%f");; 
+  parse("--dump-forces",dumpforces);
+  if(dumpforces!="") parse("--dump-forces-fmt",dumpforcesFmt);
+
+// Read in an xyz file
+  string trajectoryFile("");
+  std::string traj_xyz; parse("--ixyz",traj_xyz);
+  if(traj_xyz.length()>0 && trajectoryFile.length()==0) trajectoryFile=traj_xyz;
+  if(trajectoryFile.length()==0){
+    fprintf(out,"ERROR: missing trajectory data\n"); 
     return 0;
   }
 
@@ -179,7 +150,6 @@ int CLToolDriver<real>::main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunic
   p.cmd("setRealPrecision",&rr);
   int checknatoms=0;
   int step=0;
-  
 
   FILE* fp=fopen(trajectoryFile.c_str(),"r");
 
@@ -316,8 +286,9 @@ int CLToolDriver<real>::main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunic
 }
 
 typedef CLToolDriver<double> CLToolDriverDouble;
-
+typedef CLToolDriver<float> CLToolDriverFloat;
 PLUMED_REGISTER_CLTOOL(CLToolDriverDouble,"driver")
+PLUMED_REGISTER_CLTOOL(CLToolDriverFloat,"driver-float")
 
 
 
diff --git a/src/CLToolInfo.cpp b/src/CLToolInfo.cpp
index 44c407979..393649e44 100644
--- a/src/CLToolInfo.cpp
+++ b/src/CLToolInfo.cpp
@@ -32,8 +32,19 @@ using namespace std;
 namespace PLMD {
 
 //+PLUMEDOC TOOLS info
-/**
-This is a tool that allows you to obtain information about your plumed version
+/*
+This tool allows you to obtain information about your plumed version
+
+You can specify the information you require using the following command line
+arguments
+
+\par Examples
+
+The following command returns the root directory for your plumed distribution.
+\verbatim
+plumed info --root
+\endverbatim
+
 */
 //+ENDPLUMEDOC
 
@@ -41,56 +52,35 @@ class CLToolInfo:
 public CLTool
 {
 public:
-  int main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc);
+  static void registerKeywords( Keywords& keys );
+  CLToolInfo(const CLToolOptions& co );
+  int main(FILE*out,PlumedCommunicator& pc);
   string description()const{
     return "provide informations about plumed";
   }
 };
 
-
 PLUMED_REGISTER_CLTOOL(CLToolInfo,"info")
 
-int CLToolInfo::main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc){
-
-// to avoid warnings:
- (void) in;
-
- bool printconfiguration(false);
- bool printhelp(false);
-
-// Start parsing options
-  string prefix("");
-  string a("");
-  for(int i=1;i<argc;i++){
-    a=prefix+argv[i];
-    if(a.length()==0) continue;
-    if(a=="-h" || a=="--help"){
-      printhelp=true;
-      break;
-    }
-    if(a=="--configuration"){
-      printconfiguration=true;
-      break;
-    } else if(a=="--root"){
-      fprintf(out,"%s\n",plumedRoot.c_str());
-    } else {
-      string msg="ERROR: maximum one file at a time";
-      fprintf(stderr,"%s\n",msg.c_str());
-      return 1;
-    }
-  }
+void CLToolInfo::registerKeywords( Keywords& keys ){
+  CLTool::registerKeywords( keys );
+  keys.addFlag("--configuration",false,"prints the configuration file");
+  keys.addFlag("--root",false,"print the location of the root directory for the plumed source");
+}
 
-  if(printhelp){
-    fprintf(out,"%s",
- "Usage: info [options]\n"
- "Options:\n"
- "  [--help|-h]             : prints this help\n"
- "  [--configuration]       : prints the configuration file\n"
-);
-    return 0;
-  }
+CLToolInfo::CLToolInfo(const CLToolOptions& co ):
+CLTool(co)
+{
+  inputdata=commandline;
+}
+
+int CLToolInfo::main(FILE*out,PlumedCommunicator& pc){
+
+ bool printconfiguration; parseFlag("--configuration",printconfiguration);
+ bool printroot; parseFlag("--root",printroot);
+ if(printroot) fprintf(out,"%s\n",plumedRoot.c_str());
 
-  if(printconfiguration){
+ if(printconfiguration){
     static const unsigned char conf [] ={
 #include "Makefile.conf.xxd"
     , 0x00 };
diff --git a/src/CLToolMain.cpp b/src/CLToolMain.cpp
index ce4dd6aed..1dd927a5f 100644
--- a/src/CLToolMain.cpp
+++ b/src/CLToolMain.cpp
@@ -203,8 +203,10 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,PlumedCommunicator& p
 
   if(find(availableCxx.begin(),availableCxx.end(),command)!=availableCxx.end()){
     CLTool *cl=cltoolRegister().create(command);
-    plumed_assert(cl);
-    int ret=cl->main(argc-i,&argv[i],in,out,pc);
+    plumed_assert(cl); 
+    // Read the command line options (returns false if we are just printing help)
+    if( !cl->readInput( argc-i,&argv[i],in,out ) ){ delete cl; return 0; } 
+    int ret=cl->main(out,pc);
     delete cl;
     return ret;
   }
@@ -218,7 +220,7 @@ int CLToolMain::run(int argc, char **argv,FILE*in,FILE*out,PlumedCommunicator& p
     return 0;
   }
 
-  string msg="ERROR: unknown command " + command;
+  string msg="ERROR: unknown command " + command + ". Use 'plumed help' for help";
   fprintf(stderr,"%s\n",msg.c_str());
   return 1;
 
diff --git a/src/CLToolManual.cpp b/src/CLToolManual.cpp
index 0754891bc..3f35621ee 100644
--- a/src/CLToolManual.cpp
+++ b/src/CLToolManual.cpp
@@ -34,9 +34,22 @@ using namespace std;
 namespace PLMD {
 
 //+PLUMEDOC TOOLS manual
-/**
+/*
 manual is a tool that you can use to construct the manual page for 
 a particular action
+
+The manual constructed by this action is in html. In all probability you will never need to use this
+tool. However, it is used within the scripts that generate plumed's html manual.  If you need to use this
+tool outside those scripts the input is specified using the following command line arguments.
+
+\par Examples
+
+The following generates the html manual for the action DISTANCE.
+\verbatim
+plumed manual --action DISTANCE
+\endverbatim
+ 
+
 */
 //+ENDPLUMEDOC
 
@@ -44,7 +57,9 @@ class CLToolManual:
 public CLTool
 {
 public:
-  int main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc);
+  static void registerKeywords( Keywords& keys );
+  CLToolManual(const CLToolOptions& co );
+  int main(FILE*out,PlumedCommunicator& pc);
   string description()const{
     return "print out a description of the keywords for an action in html";
   }
@@ -52,56 +67,28 @@ public:
 
 PLUMED_REGISTER_CLTOOL(CLToolManual,"manual")
 
-int CLToolManual::main(int argc,char**argv,FILE*in,FILE*out,PlumedCommunicator& pc){
-
-// to avoid warnings:
- (void) in;
-
- std::string action="none";
- bool printhelp(false);
-
-// Start parsing options
- string prefix("");
- std::string a("");
- for(int i=1;i<argc;i++){
-    a=prefix+argv[i];
-    if(a.length()==0) continue;
-    if(a=="-h" || a=="--help"){
-      printhelp=true;
-      break;
-    }
-    if(a.find("--action=")==0){
-      a.erase(0,a.find("=")+1);
-      action=a; 
-      prefix="";
-    } else if(a=="--action"){
-      prefix="--action=";
-    } else {
-      string msg="ERROR: unknown option"+a;
-      fprintf(stderr,"%s\n",msg.c_str());
-      return 1;
-    }
- } 
-
- if(printhelp){
-   fprintf(out,"%s",
-   "Usage: info [options]\n"
-   "Options:\n"
-   "  [--help|-h]           : prints this help\n"
-   "  [--action]            : print the manual for this action\n"
-);
-   return 0; 
- }
+void CLToolManual::registerKeywords( Keywords& keys ){
+  CLTool::registerKeywords( keys );
+  keys.add("compulsory","--action","print the manual for this particular action");
+}
 
- if(action=="none"){
-    fprintf(stderr,"missing --action flag\n");
-    return 1;
- }
+CLToolManual::CLToolManual(const CLToolOptions& co ):
+CLTool(co)
+{
+  inputdata=commandline;
+}
 
- std::cerr<<actionRegister(); 
- if( !actionRegister().printManual(action) ){
-    fprintf(stderr,"specified action is not registered\n");
-    return 1; 
+int CLToolManual::main(FILE*out,PlumedCommunicator& pc){
+
+ std::string action; 
+ if( !parse("--action",action) ) return 1;
+ std::cerr<<"LIST OF DOCUMENTED ACTIONS:\n";
+ std::cerr<<actionRegister()<<"\n"; 
+ std::cerr<<"LIST OF DOCUMENTED COMMAND LINE TOOLS:\n";
+ std::cerr<<cltoolRegister()<<"\n\n";
+ if( !actionRegister().printManual(action) && !cltoolRegister().printManual(action) ){
+       fprintf(stderr,"specified action is not registered\n");
+       return 1; 
  }
 
  return 0;
diff --git a/src/CLToolRegister.cpp b/src/CLToolRegister.cpp
index 4d9292b99..b382de20d 100644
--- a/src/CLToolRegister.cpp
+++ b/src/CLToolRegister.cpp
@@ -50,12 +50,14 @@ void CLToolRegister::remove(creator_pointer f){
   }
 }
 
-void CLToolRegister::add(string key,creator_pointer f){
+void CLToolRegister::add(string key,creator_pointer f,keywords_pointer kf){
   if(m.count(key)){
     m.erase(key);
     disabled.insert(key);
   }else{
     m.insert(pair<string,creator_pointer>(key,f));
+    Keywords keys; kf(keys);
+    mk.insert(pair<string,Keywords>(key,keys));
   };
 }
 
@@ -67,8 +69,10 @@ bool CLToolRegister::check(string key){
 CLTool* CLToolRegister::create(const CLToolOptions&ao){
   if(ao.line.size()<1)return NULL;
   CLTool* cltool;
-  if(check(ao.line[0])) cltool=m[ao.line[0]](ao);
-  else cltool=NULL;
+  if(check(ao.line[0])){
+     CLToolOptions nao( ao,mk[ao.line[0]] );
+     cltool=m[ao.line[0]](nao);
+  } else cltool=NULL;
   return cltool;
 }
 
@@ -88,6 +92,15 @@ std::ostream & PLMD::operator<<(std::ostream &log,const CLToolRegister&ar){
   return log;
 }
 
+bool CLToolRegister::printManual( const std::string& cltool ){
+  if ( check(cltool) ){
+     mk[cltool].print_html(false);
+     return true;
+  } else {
+     return false;
+  }
+}
+
 vector<string> CLToolRegister::list()const{
   vector<string> s;
   for(const_mIterator it=m.begin();it!=m.end();++it)
diff --git a/src/CLToolRegister.h b/src/CLToolRegister.h
index 251a1be8c..7c1331461 100644
--- a/src/CLToolRegister.h
+++ b/src/CLToolRegister.h
@@ -27,6 +27,7 @@
 #include <set>
 #include <vector>
 #include <iosfwd>
+#include "Keywords.h"
 
 namespace PLMD{
 
@@ -39,8 +40,12 @@ class CLToolRegister{
   friend std::ostream &operator<<(std::ostream &,const CLToolRegister&);
 /// Pointer to a function which, given the options, create an CLTool
   typedef CLTool*(*creator_pointer)(const CLToolOptions&);
+/// Pointer to a function which, returns the keywords allowed
+  typedef void(*keywords_pointer)(Keywords&);
 /// Map cltool to a function which creates the related object
   std::map<std::string,creator_pointer> m;
+/// Map cltool name to the keywords for this function
+  std::map<std::string,Keywords> mk;
 /// Iterator over the map
   typedef std::map<std::string,creator_pointer>::iterator mIterator;
 /// Iterator over the map
@@ -51,7 +56,7 @@ public:
 /// Register a new class.
 /// \param key The name of the directive to be used in the input file
 /// \param key A pointer to a function which creates an object of that class
-  void add(std::string key,creator_pointer);
+  void add(std::string key,creator_pointer,keywords_pointer);
 /// Verify if a directive is present in the register
   bool check(std::string cltool);
 /// Create an CLTool of the type indicated in the options
@@ -61,6 +66,8 @@ public:
   ~CLToolRegister();
 /// Returns a list of the allowed CLTools
   std::vector<std::string> list()const;
+/// Print out the instructions for using the tool in html ready for input into the manual
+  bool printManual(const std::string& cltool); 
 };
 
 /// Function returning a reference to the CLToolRegister.
@@ -83,9 +90,9 @@ std::ostream & operator<<(std::ostream &log,const CLToolRegister&ar);
 /// This macro should be used in the .cpp file of the corresponding class
 #define PLUMED_REGISTER_CLTOOL(classname,directive) \
   static class classname##RegisterMe{ \
-    static PLMD::CLTool* create(const PLMD::CLToolOptions&ao){(void)ao;return new classname;} \
+    static PLMD::CLTool* create(const PLMD::CLToolOptions&ao){return new classname(ao);} \
   public: \
-    classname##RegisterMe(){PLMD::cltoolRegister().add(directive,create);}; \
+    classname##RegisterMe(){PLMD::cltoolRegister().add(directive,create,classname::registerKeywords);}; \
     ~classname##RegisterMe(){PLMD::cltoolRegister().remove(create);}; \
   } classname##RegisterMeObject;
 
diff --git a/src/CLToolSimpleMD.cpp b/src/CLToolSimpleMD.cpp
index 0a7d9ca49..925b0d095 100644
--- a/src/CLToolSimpleMD.cpp
+++ b/src/CLToolSimpleMD.cpp
@@ -34,6 +34,45 @@ using namespace PLMD;
 
 namespace PLMD{
 
+//+PLUMEDOC TOOLS simplemd
+/*
+simplemd allows one to do molecular dynamics on systems of Lennard-Jones atoms.
+
+The input to simplemd is spcified in an input file. Configurations are input and
+output in xyz format. The input file should contain one directive per line. 
+The directives available are as follows:
+
+\par Examples
+
+You run an MD simulation using simplemd with the following command:
+\verbatim
+plumed simplemd < in
+\endverbatim
+
+The following is an example of an input file for a simplemd calculation. This file
+instructs simplemd to do 50 steps of MD at a temperature of 0.722
+\verbatim
+nputfile input.xyz
+outputfile output.xyz
+temperature 0.722
+tstep 0.005
+friction 1
+forcecutoff 2.5
+listcutoff  3.0
+nstep 50
+nconfig 10 trajectory.xyz
+nstat   10 energies.dat
+\endverbatim
+
+If you run the following a description of all the directives that can be used in the
+input file will be output.
+\verbatim
+plumed simplemd --help
+\endverbatim
+
+*/
+//+ENDPLUMEDOC
+
 class CLToolSimpleMD:
 public PLMD::CLTool
 {
@@ -52,7 +91,26 @@ FILE* write_statistics_fp;
 
 
 public:
-CLToolSimpleMD(){
+static void registerKeywords( Keywords& keys ){ 
+  keys.add("compulsory","nstep","The number of steps of dynamics you want to run");
+  keys.add("compulsory","temperature","NVE","the temperature at which you wish to run the simulation in LJ units");
+  keys.add("compulsory","friction","off","The friction (in LJ units) for the langevin thermostat that is used to keep the temperature constant");
+  keys.add("compulsory","tstep","0.005","the integration timestep in LJ units");
+  keys.add("compulsory","inputfile","An xyz file containing the initial configuration of the system");  
+  keys.add("compulsory","forcecutoff","2.5","");
+  keys.add("compulsory","listcutoff","3.0","");
+  keys.add("compulsory","outputfile","An output xyz file containing the final configuration of the system");
+  keys.add("compulsory","nconfig","10","The frequency with which to write configurations to the trajectory file followed by the name of the trajectory file");
+  keys.add("compulsory","nstat","1","The frequency with which to write the statistics to the statistics file followed by the name of the statistics file");
+  keys.add("compulsory","maxneighbours","10000","The maximum number of neighbours an atom can have");
+  keys.add("compulsory","idum","0","The random number seed");
+  keys.add("compulsory","ndim","3","The dimensionality of the system (some interesting LJ clusters are two dimensional)");
+}
+
+CLToolSimpleMD( const CLToolOptions& co ) :
+CLTool(co)
+{
+  inputdata=ifile;
   for(int i=0;i<32;i++) iv[i]=0.0;
   iy=0;
   iset=0;
@@ -66,8 +124,7 @@ CLToolSimpleMD(){
 private:
 
 void 
-read_input(FILE*   fp,
-           double& temperature,
+read_input(double& temperature,
            double& tstep,
            double& friction,
            double& forcecutoff,
@@ -84,99 +141,49 @@ read_input(FILE*   fp,
            int&    ndim,
            int&    idum)
 {
-  temperature=1.0;
-  tstep=0.005;
-  friction=0.0;
-  forcecutoff=2.5;
-  listcutoff=3.0;
-  nstep=1;
-  nconfig=10;
-  nstat=1;
-  maxneighbours=1000;
-  idum=0;
-  ndim=3;
-  wrapatoms=false;
-  statfile="";
-  trajfile="";
-  outputfile="";
-  inputfile="";
-
-  string line;
-
-  line.resize(256);
-  char buffer[256];
-  char buffer1[256];
-
-  while(fgets(buffer,256,fp)){
-    line=buffer;
-    for(int i=0;i<line.length();++i) if(line[i]=='#' || line[i]=='\n') line.erase(i);
-    for(int i=line.length()-1;i>=0;--i){
-      if(line[i]!=' ')break;
-      line.erase(i);
-    }
-    if(line.length()==0) continue;
-    sscanf(line.c_str(),"%s",buffer);
-    string keyword=buffer;
-    if(keyword=="temperature")
-      sscanf(line.c_str(),"%s %lf",buffer,&temperature);
-    else if(keyword=="tstep")
-      sscanf(line.c_str(),"%s %lf",buffer,&tstep);
-    else if(keyword=="friction")
-      sscanf(line.c_str(),"%s %lf",buffer,&friction);
-    else if(keyword=="forcecutoff")
-      sscanf(line.c_str(),"%s %lf",buffer,&forcecutoff);
-    else if(keyword=="listcutoff")
-      sscanf(line.c_str(),"%s %lf",buffer,&listcutoff);
-    else if(keyword=="nstep")
-      sscanf(line.c_str(),"%s %d",buffer,&nstep);
-    else if(keyword=="nconfig")
-    {
-      sscanf(line.c_str(),"%s %d %s",buffer,&nconfig,buffer1);
-      trajfile=buffer1;
-    }
-    else if(keyword=="nstat")
-    {
-      sscanf(line.c_str(),"%s %d %s",buffer,&nstat,buffer1);
-      statfile=buffer1;
-    }
-    else if(keyword=="maxneighbours")
-      sscanf(line.c_str(),"%s %d",buffer,&maxneighbours);
-    else if(keyword=="inputfile")
-    {
-      sscanf(line.c_str(),"%s %s",buffer,buffer1);
-      inputfile=buffer1;
-    }
-    else if(keyword=="outputfile")
-    {
-      sscanf(line.c_str(),"%s %s",buffer,buffer1);
-      outputfile=buffer1;
-    }
-    else if(keyword=="idum")
-      sscanf(line.c_str(),"%s %d",buffer,&idum);
-    else if(keyword=="ndim")
-      sscanf(line.c_str(),"%s %d",buffer,&ndim);
-    else{
-      fprintf(stderr,"Unknown keywords :%s\n",keyword.c_str());
-      exit(1);
-    }
-  }
 
+  // Read everything from input file
+  char buffer1[256];
+  std::string tempstr; parse("temperature",tempstr);
+  if( tempstr!="NVE" ) Tools::convert(tempstr,temperature);
+  parse("tstep",tstep);
+  std::string frictionstr; parse("friction",frictionstr);
+  if( tempstr!="NVE" ){
+      if(frictionstr=="off"){ fprintf(stderr,"Specify friction for thermostat\n"); exit(1); }
+      Tools::convert(frictionstr,friction); 
+  } 
+  parse("forcecutoff",forcecutoff);
+  parse("listcutoff",listcutoff);
+  parse("nstep",nstep);
+  parse("maxneighbours",maxneighbours);
+  parse("idum",idum);
+
+  // Read in stuff with sanity checks
+  parse("inputfile",inputfile);
   if(inputfile.length()==0){
       fprintf(stderr,"Specify input file\n");
       exit(1);
   }
+  parse("outputfile",outputfile);
   if(outputfile.length()==0){
       fprintf(stderr,"Specify output file\n");
       exit(1);
   }
+  std::string nconfstr; parse("nconfig",nconfstr);
+  sscanf(nconfstr.c_str(),"%d %s",&nconfig,buffer1);
+  trajfile=buffer1;
   if(trajfile.length()==0){
       fprintf(stderr,"Specify traj file\n");
       exit(1);
   }
+  std::string nstatstr; parse("nstat",nstatstr);
+  sscanf(nstatstr.c_str(),"%d %s",&nconfig,buffer1);
+  statfile=buffer1;
   if(statfile.length()==0){
       fprintf(stderr,"Specify stat file\n");
       exit(1);
   }
+  parse("ndim",ndim);
   if(ndim<1 || ndim>3){
       fprintf(stderr,"ndim should be 1,2 or 3\n");
       exit(1);
@@ -369,7 +376,7 @@ void write_statistics(const string & statfile,const int istep,const double tstep
 
 
 
-int main(int argc,char**argv,FILE*in,FILE*out,PLMD::PlumedCommunicator& pc){
+int main(FILE*out,PLMD::PlumedCommunicator& pc){
   int            natoms;       // number of atoms
   vector<Vector> positions;    // atomic positions
   vector<Vector> velocities;   // velocities
@@ -423,18 +430,11 @@ int main(int argc,char**argv,FILE*in,FILE*out,PLMD::PlumedCommunicator& pc){
     plumed->cmd("setRealPrecision",&s);
   }
 
-  FILE* mystdin=in;
-
-  if(argc==2) mystdin=fopen(argv[1],"r");
-
-  read_input(mystdin,temperature,tstep,friction,forcecutoff,
+  read_input(temperature,tstep,friction,forcecutoff,
              listcutoff,nstep,nconfig,nstat,
              wrapatoms,inputfile,outputfile,trajfile,statfile,
              maxneighbour,ndim,idum);
 
-  if(argc==2) fclose(mystdin);
-
-
 // number of atoms is read from file inputfile
   read_natoms(inputfile,natoms);
 
diff --git a/src/Keywords.cpp b/src/Keywords.cpp
index d1d302508..de9a5e083 100644
--- a/src/Keywords.cpp
+++ b/src/Keywords.cpp
@@ -218,13 +218,14 @@ bool Keywords::reserved( const std::string & k ) const {
   return false;
 }
 
-void Keywords::print_html() const {
+void Keywords::print_html( const bool isaction ) const {
   unsigned nkeys=0;
   for(unsigned i=0;i<keys.size();++i){
      if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
   }
   if( nkeys>0 ){
-    std::cout<<"\\par Specifying the atoms involved\n\n";
+    if(isaction) std::cout<<"\\par Specifying the atoms involved\n\n";
+    else std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     for(unsigned i=0;i<keys.size();++i){
         if ( (types.find(keys[i])->second).isAtomList() ) print_html_item( keys[i] );
@@ -236,7 +237,8 @@ void Keywords::print_html() const {
      if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
   }
   if( nkeys>0 ){
-     std::cout<< "\\par Compulsory keywords\n\n";
+     if(isaction) std::cout<< "\\par Compulsory keywords\n\n";
+     else std::cout<<"\\par The following must be present\n\n";
      std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
      for(unsigned i=0;i<keys.size();++i){
         if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] );
@@ -248,7 +250,8 @@ void Keywords::print_html() const {
      if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
   }
   if( nkeys>0 ){
-     std::cout<<"\\par Options\n\n";
+     if(isaction) std::cout<<"\\par Options\n\n";
+     else std::cout<<"\\par The following options are available\n\n";
      std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
      for(unsigned i=0;i<keys.size();++i){
         if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] );
@@ -270,6 +273,66 @@ void Keywords::print_html() const {
   std::cout<<"</table>\n\n";
 }
 
+void Keywords::print( FILE* out ) const {
+  unsigned nkeys=0;
+  for(unsigned i=0;i<keys.size();++i){
+     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
+  }
+  if( nkeys>0 ){
+      fprintf(out,"The input trajectory can be in any of the following formats: \n\n");
+      for(unsigned i=0;i<keys.size();++i){
+          if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], out );
+      }
+  }
+  nkeys=0;
+  for(unsigned i=0;i<keys.size();++i){
+     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
+  }
+  if( nkeys>0 ){
+     fprintf(out,"\nThe following arguments are compulsory: \n\n");
+     for(unsigned i=0;i<keys.size();++i){
+        if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
+     }
+  }
+  nkeys=0;
+  for(unsigned i=0;i<keys.size();++i){
+     if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
+  }
+  if( nkeys>0 ){
+     fprintf( out,"\nIn addition you may use the following options: \n\n");
+     for(unsigned i=0;i<keys.size();++i){
+        if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
+     }
+  }
+  nkeys=0;
+  for(unsigned i=0;i<keys.size();++i){
+     if ( (types.find(keys[i])->second).isOptional() ) nkeys++;
+  }
+  if( nkeys>0 ){
+     for(unsigned i=0;i<keys.size();++i){
+        if ( (types.find(keys[i])->second).isOptional() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
+     }
+     fprintf(out,"\n");
+  }
+}
+
+void Keywords::printKeyword( const std::string& key, FILE* out ) const {
+  bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
+  std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
+  fprintf(out,"%23s - ", key.c_str() );
+  unsigned nl=0; std::string blank=" ";
+  for(unsigned i=0;i<w.size();++i){
+      nl+=w[i].length() + 1;
+      if( nl>60 ){
+         fprintf(out,"\n%23s   %s ", blank.c_str(), w[i].c_str() ); nl=0;
+      } else {
+         fprintf(out,"%s ", w[i].c_str() );
+      }
+      if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
+  }
+  fprintf(out,"\n");
+}
+
 void Keywords::print( Log& log ) const {
   unsigned nkeys=0;
   for(unsigned i=0;i<keys.size();++i){
@@ -338,6 +401,11 @@ void Keywords::print_html_item( const std::string& key ) const {
   printf("</tr>\n");
 }
 
+std::string Keywords::get( const unsigned k ) const {
+  plumed_assert( k<size() );
+  return keys[k];
+}
+
 bool Keywords::getLogicalDefault( std::string key, bool& def ) const {
    if( booldefs.find(key)!=booldefs.end() ){ 
      def=booldefs.find(key)->second;
diff --git a/src/Keywords.h b/src/Keywords.h
index dfd87ea9f..e1923248e 100644
--- a/src/Keywords.h
+++ b/src/Keywords.h
@@ -76,11 +76,13 @@ private:
   void print_html_item( const std::string& ) const;
 /// Print a particular keyword
   void printKeyword( const std::string& j, Log& log ) const ;
+/// Print a particular keyword (copy of the above that works with files)
+  void printKeyword( const std::string& j, FILE* out ) const ;
 /// find out whether flag key is on or off by default.
   bool getLogicalDefault( std::string key, bool& def ) const ;
+public:
 /// Get the value of the default for the keyword named key
   bool getDefaultValue( std::string key, std::string& def ) const ;
-public:
 /// Return the number of defined keywords 
   unsigned size() const;
 /// Check if numbered keywords are allowed for this action
@@ -89,12 +91,16 @@ public:
   std::string getKeyword( const unsigned i ) const ;
 /// Print the documentation to the log file (used by PLMD::Action::error)
   void print( Log& log ) const ;
+/// Print the documentation to a file (use by PLUMED::CLTool::readCommandLineArgs)
+  void print( FILE* out ) const ;
 /// Reserve a keyword 
   void reserve( const std::string & t, const std::string & k, const std::string & d );
 /// Reserve a flag
   void reserveFlag( const std::string & k, const bool def, const std::string & d );
 /// Use one of the reserved keywords
   void use( const std::string  k );
+/// Get the ith keyword
+  std::string get( const unsigned k ) const ;
 /// Add a new keyword of type t with name k and description d
   void add( const std::string & t, const std::string & k, const std::string & d );
 /// Add a new compulsory keyword (t must equal compulsory) with name k, default value def and description d
@@ -110,7 +116,7 @@ public:
 /// Check if the keyword with name k has style t
   bool style( const std::string & k, const std::string & t ) const ;
 /// Print an html version of the documentation
-  void print_html() const ;
+  void print_html( const bool isaction ) const ;
 /// Change the style of a keyword
   void reset_style( const std::string & k, const std::string & style );
 /// Add keywords from one keyword object to another
diff --git a/src/Tools.cpp b/src/Tools.cpp
index 987462134..161ec8227 100644
--- a/src/Tools.cpp
+++ b/src/Tools.cpp
@@ -235,3 +235,9 @@ vector<string> Tools::ls(const string&d){
   }
   return result;
 }
+
+void Tools::stripLeadingAndTrailingBlanks( std::string& str ){
+  std::size_t first=str.find_first_not_of(' ');
+  std::size_t last=str.find_last_not_of(' ');
+  if( first<last ) str=str.substr(first,last+1);
+}
diff --git a/src/Tools.h b/src/Tools.h
index 65b7c5c41..1c4f62f8d 100644
--- a/src/Tools.h
+++ b/src/Tools.h
@@ -104,6 +104,8 @@ public:
   static void interpretLabel(std::vector<std::string>&s);
 /// list files in a directory
   static std::vector<std::string> ls(const std::string&);
+/// removes leading and trailing blanks from a string
+  static void stripLeadingAndTrailingBlanks( std::string& str );
 };
 
 template <class T>
-- 
GitLab