[C++] Fix info, warning, and error for ninja
diff --git a/command.cc b/command.cc
index f696cd5..6b48f68 100644
--- a/command.cc
+++ b/command.cc
@@ -175,6 +175,7 @@
 }
 
 void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) {
+  ev_->set_loc(n->loc);
   ev_->set_current_scope(n->rule_vars);
   current_dep_node_ = n;
   for (Value* v : n->cmds) {
@@ -209,5 +210,22 @@
     }
     continue;
   }
+
+  if (!ev_->delayed_output_commands().empty()) {
+    vector<Command*> output_commands;
+    for (const string& cmd : ev_->delayed_output_commands()) {
+      Command* c = new Command(n->output);
+      c->cmd = make_shared<string>(cmd);
+      c->echo = false;
+      c->ignore_error = false;
+      output_commands.push_back(c);
+    }
+    // Prepend |output_commands|.
+    commands->swap(output_commands);
+    copy(output_commands.begin(), output_commands.end(),
+         back_inserter(*commands));
+    ev_->clear_delayed_output_commands();
+  }
+
   ev_->set_current_scope(NULL);
 }
diff --git a/command.h b/command.h
index e93de34..ab63240 100644
--- a/command.h
+++ b/command.h
@@ -33,7 +33,6 @@
   shared_ptr<string> cmd;
   bool echo;
   bool ignore_error;
-  //StringPiece shell;
 };
 
 class CommandEvaluator {
diff --git a/eval.h b/eval.h
index 558df3c..dad8127 100644
--- a/eval.h
+++ b/eval.h
@@ -59,6 +59,7 @@
   shared_ptr<string> EvalVar(Symbol name);
 
   const Loc& loc() const { return loc_; }
+  void set_loc(const Loc& loc) { loc_ = loc; }
 
   const vector<shared_ptr<Rule>>& rules() const { return rules_; }
   const unordered_map<Symbol, Vars*>& rule_vars() const {
@@ -76,6 +77,16 @@
   bool avoid_io() const { return avoid_io_; }
   void set_avoid_io(bool a) { avoid_io_ = a; }
 
+  const vector<string>& delayed_output_commands() const {
+    return delayed_output_commands_;
+  }
+  void add_delayed_output_command(const string& c) {
+    delayed_output_commands_.push_back(c);
+  }
+  void clear_delayed_output_commands() {
+    delayed_output_commands_.clear();
+  }
+
  private:
   Var* EvalRHS(Symbol lhs, Value* rhs, StringPiece orig_rhs, AssignOp op,
                bool is_override = false);
@@ -92,7 +103,11 @@
 
   Loc loc_;
   bool is_bootstrap_;
+
   bool avoid_io_;
+  // Commands which should run at ninja-time (i.e., info, warning, and
+  // error).
+  vector<string> delayed_output_commands_;
 };
 
 #endif  // EVAL_H_
diff --git a/func.cc b/func.cc
index e0f9e52..5f01ebe 100644
--- a/func.cc
+++ b/func.cc
@@ -534,30 +534,33 @@
   *s += var->Flavor();
 }
 
-void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   shared_ptr<string> a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
-    *s += "KATI_TODO(info)";
+    ev->add_delayed_output_command(StringPrintf("echo '%s'", a->c_str()));
     return;
   }
   printf("%s\n", a->c_str());
   fflush(stdout);
 }
 
-void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   shared_ptr<string> a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
-    *s += "KATI_TODO(warning)";
+    ev->add_delayed_output_command(
+        StringPrintf("echo '%s:%d: %s' 2>&1", LOCF(ev->loc()), a->c_str()));
     return;
   }
   printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
   fflush(stdout);
 }
 
-void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
   shared_ptr<string> a = args[0]->Eval(ev);
   if (ev->avoid_io()) {
-    *s += "KATI_TODO(error)";
+    ev->add_delayed_output_command(
+        StringPrintf("echo '%s:%d: *** %s.' 2>&1 && false",
+                     LOCF(ev->loc()), a->c_str()));
     return;
   }
   ev->Error(StringPrintf("*** %s.", a->c_str()));
diff --git a/runtest.rb b/runtest.rb
index e2458ce..b0cfae8 100755
--- a/runtest.rb
+++ b/runtest.rb
@@ -88,8 +88,13 @@
   end
 end
 
-def normalize_ninja_log(log)
+def normalize_ninja_log(log, mk)
   log.gsub!(/^\[\d+\/\d+\] .*\n/, '')
+  if mk =~ /err_error_in_recipe.mk/
+    # This test expects ninja fails. Strip ninja specific error logs.
+    log.gsub!(/^FAILED: .*\n/, '')
+    log.gsub!(/^ninja: .*\n/, '')
+  end
   log
 end
 
@@ -195,7 +200,7 @@
       res = IO.popen(cmd, 'r:binary', &:read)
       if via_ninja && File.exist?('build.ninja') && File.exists?('ninja.sh')
         log = IO.popen('./ninja.sh -j1 -v 2>&1', 'r:binary', &:read)
-        res += normalize_ninja_log(log)
+        res += normalize_ninja_log(log, mk)
       end
       res = normalize_kati_log(res)
       output += "=== #{tc} ===\n" + res
diff --git a/testcase/err_error_in_recipe.mk b/testcase/err_error_in_recipe.mk
new file mode 100644
index 0000000..af1b46b
--- /dev/null
+++ b/testcase/err_error_in_recipe.mk
@@ -0,0 +1,2 @@
+test:
+	$(error foo)
diff --git a/testcase/info.mk b/testcase/info.mk
index b6b501d..829729a 100644
--- a/testcase/info.mk
+++ b/testcase/info.mk
@@ -1,4 +1,3 @@
-# TODO(ninja): Fix
-
 test:
-	echo $(info "%s:%s" foo bar)
+	echo $(info "%s:%s" foo bar)xxx
+	$(info baz)
diff --git a/testcase/strip.mk b/testcase/strip.mk
index fc283ef..44df672 100644
--- a/testcase/strip.mk
+++ b/testcase/strip.mk
@@ -1,5 +1,3 @@
-# TODO(ninja): Fix
-
 XY:=x 	y
 X:=$(subst y, ,$(XY))
 Y:=$(subst x, ,$(XY))
diff --git a/testcase/warning.mk b/testcase/warning.mk
index 340c3c2..7e83503 100644
--- a/testcase/warning.mk
+++ b/testcase/warning.mk
@@ -1,4 +1,5 @@
 $(warning foo)
 
 test:
+	$(warning bar)
 	echo PASS