[C++] Fix comment_in_command.mk
diff --git a/func.cc b/func.cc
index 41d3471..9cb86c1 100644
--- a/func.cc
+++ b/func.cc
@@ -40,6 +40,60 @@
 
 namespace {
 
+// TODO: This code is very similar to
+// NinjaGenerator::TranslateCommand. Factor them out.
+shared_ptr<string> StripShellComment(shared_ptr<string> cmd) {
+  if (cmd->find('#') == string::npos)
+    return cmd;
+
+  shared_ptr<string> res = make_shared<string>();
+  bool prev_backslash = false;
+  // Set space as an initial value so the leading comment will be
+  // stripped out.
+  char prev_char = ' ';
+  char quote = 0;
+  bool done = false;
+  const char* in = cmd->c_str();
+  for (; *in && !done; in++) {
+    switch (*in) {
+      case '#':
+        if (quote == 0 && isspace(prev_char)) {
+          while (*in && *in != '\n')
+            in++;
+          break;
+        }
+
+      case '\'':
+      case '"':
+      case '`':
+        if (quote) {
+          if (quote == *in)
+            quote = 0;
+        } else if (!prev_backslash) {
+          quote = *in;
+        }
+        *res += *in;
+        break;
+
+      case '\\':
+        *res += '\\';
+        break;
+
+      default:
+        *res += *in;
+    }
+
+    if (*in == '\\') {
+      prev_backslash = !prev_backslash;
+    } else {
+      prev_backslash = false;
+    }
+
+    prev_char = *in;
+  }
+  return res;
+}
+
 void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
   shared_ptr<string> pat_str = args[0]->Eval(ev);
   shared_ptr<string> repl = args[1]->Eval(ev);
@@ -437,7 +491,7 @@
   shared_ptr<string> cmd = args[0]->Eval(ev);
   if (ev->avoid_io() && !HasNoIoInShellScript(*cmd)) {
     *s += "$(";
-    *s += *cmd;
+    *s += *StripShellComment(cmd);
     *s += ")";
     return;
   }
diff --git a/ninja.cc b/ninja.cc
index 3598beb..a562b12 100644
--- a/ninja.cc
+++ b/ninja.cc
@@ -207,12 +207,12 @@
     // stripped out.
     char prev_char = ' ';
     char quote = 0;
-    bool done = false;
-    for (; *in && !done; in++) {
+    for (; *in; in++) {
       switch (*in) {
         case '#':
           if (quote == 0 && isspace(prev_char)) {
-            done = true;
+            while (in[1] && *in != '\n')
+              in++;
           } else {
             *cmd_buf += *in;
           }
diff --git a/testcase/comment_in_command.mk b/testcase/comment_in_command.mk
index 41fad51..881a241 100644
--- a/testcase/comment_in_command.mk
+++ b/testcase/comment_in_command.mk
@@ -1,5 +1,3 @@
-# TODO(c-ninja): Fix
-
 MAKEVER:=$(shell make --version | ruby -n0e 'puts $$_[/Make (\d)/,1]')
 
 test1:
@@ -19,7 +17,11 @@
 test3: $(shell echo foo #)
 
 test4:
-	echo $(shell echo OK #)
+	echo $(shell echo OK # FAIL \
+	FAIL2)
+
+test5:
+	echo $(shell echo $$(echo PASS))
 
 foo:
 	echo OK
diff --git a/testcase/escape_for_shell_in_recipe.mk b/testcase/escape_for_shell_in_recipe.mk
new file mode 100644
index 0000000..29b5fcf
--- /dev/null
+++ b/testcase/escape_for_shell_in_recipe.mk
@@ -0,0 +1,7 @@
+# TODO(ninja): The first testcase fails due to an extra escape. We
+# should be careful not to break the second case when we fix the first
+# case.
+
+test:
+	echo $(shell echo \"" # "\")
+	echo $$(echo \"" # "\")