Resurrect the 'rules' tool.

This tool is useful for writing shell completion script for tools
expecting a rule name as argument.

The tool was dropped by 34b46f28c.

Fix #1024.
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index c9309ad..7f3ab8a 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -283,6 +283,9 @@
 
 `recompact`:: recompact the `.ninja_deps` file. _Available since Ninja 1.4._
 
+`rules`:: output the list of all rules (eventually with their description
+if they have one).  It can be used to know which rule name to pass to
++ninja -t targets rule _name_+ or +ninja -t compdb+.
 
 Writing your own Ninja files
 ----------------------------
diff --git a/src/eval_env.cc b/src/eval_env.cc
index aa3d2b6..e9b6c43 100644
--- a/src/eval_env.cc
+++ b/src/eval_env.cc
@@ -131,3 +131,17 @@
   }
   return result;
 }
+
+string EvalString::Unparse() const {
+  string result;
+  for (TokenList::const_iterator i = parsed_.begin();
+       i != parsed_.end(); ++i) {
+    bool special = (i->second == SPECIAL);
+    if (special)
+      result.append("${");
+    result.append(i->first);
+    if (special)
+      result.append("}");
+  }
+  return result;
+}
diff --git a/src/eval_env.h b/src/eval_env.h
index 999ce42..8fb9bf4 100644
--- a/src/eval_env.h
+++ b/src/eval_env.h
@@ -33,8 +33,13 @@
 /// A tokenized string that contains variable references.
 /// Can be evaluated relative to an Env.
 struct EvalString {
+  /// @return The evaluated string with variable expanded using value found in
+  ///         environment @a env.
   string Evaluate(Env* env) const;
 
+  /// @return The string with variables not expanded.
+  string Unparse() const;
+
   void Clear() { parsed_.clear(); }
   bool empty() const { return parsed_.empty(); }
 
diff --git a/src/ninja.cc b/src/ninja.cc
index 5f19a65..a093cd1 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -126,6 +126,7 @@
   int ToolCompilationDatabase(const Options* options, int argc, char* argv[]);
   int ToolRecompact(const Options* options, int argc, char* argv[]);
   int ToolUrtle(const Options* options, int argc, char** argv);
+  int ToolRules(const Options* options, int argc, char* argv[]);
 
   /// Open the build log.
   /// @return false on error.
@@ -561,6 +562,55 @@
   }
 }
 
+int NinjaMain::ToolRules(const Options* options, int argc, char* argv[]) {
+  // Parse options.
+
+  // The rules tool uses getopt, and expects argv[0] to contain the name of
+  // the tool, i.e. "rules".
+  argc++;
+  argv--;
+
+  bool print_description = false;
+
+  optind = 1;
+  int opt;
+  while ((opt = getopt(argc, argv, const_cast<char*>("hd"))) != -1) {
+    switch (opt) {
+    case 'd':
+      print_description = true;
+      break;
+    case 'h':
+    default:
+      printf("usage: ninja -t rules [options]\n"
+             "\n"
+             "options:\n"
+             "  -d     also print the description of the rule\n"
+             "  -h     print this message\n"
+             );
+    return 1;
+    }
+  }
+  argv += optind;
+  argc -= optind;
+
+  // Print rules
+
+  typedef map<string, const Rule*> Rules;
+  const Rules& rules = state_.bindings_.GetRules();
+  for (Rules::const_iterator i = rules.begin(); i != rules.end(); ++i) {
+    printf("%s", i->first.c_str());
+    if (print_description) {
+      const Rule* rule = i->second;
+      const EvalString* description = rule->GetBinding("description");
+      if (description != NULL) {
+        printf(": %s", description->Unparse().c_str());
+      }
+    }
+    printf("\n");
+  }
+  return 0;
+}
+
 enum PrintCommandMode { PCM_Single, PCM_All };
 void PrintCommands(Edge* edge, set<Edge*>* seen, PrintCommandMode mode) {
   if (!edge)
@@ -841,6 +891,8 @@
       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
     { "recompact",  "recompacts ninja-internal data structures",
       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
+    { "rules",  "list all rules",
+      Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRules },
     { "urtle", NULL,
       Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
     { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }