[C++] Implement abspath
diff --git a/func.cc b/func.cc
index 3dbd970..af6c81a 100644
--- a/func.cc
+++ b/func.cc
@@ -294,12 +294,27 @@
   }
 }
 
-void RealpathFunc(const vector<Value*>&, Evaluator*, string*) {
-  printf("TODO(realpath)");
+void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+  shared_ptr<string> text = args[0]->Eval(ev);
+  WordWriter ww(s);
+  for (StringPiece tok : WordScanner(*text)) {
+    char orig = tok[tok.size()];
+    const_cast<char*>(tok.data())[tok.size()] = '\0';
+    char buf[PATH_MAX];
+    if (realpath(tok.data(), buf))
+      *s += buf;
+    const_cast<char*>(tok.data())[tok.size()] = orig;
+  }
 }
 
-void AbspathFunc(const vector<Value*>&, Evaluator*, string*) {
-  printf("TODO(abspath)");
+void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
+  shared_ptr<string> text = args[0]->Eval(ev);
+  WordWriter ww(s);
+  string buf;
+  for (StringPiece tok : WordScanner(*text)) {
+    AbsPath(tok, &buf);
+    ww.Write(buf);
+  }
 }
 
 void IfFunc(const vector<Value*>&, Evaluator*, string*) {
diff --git a/strutil.cc b/strutil.cc
index 0548f62..d09abda 100644
--- a/strutil.cc
+++ b/strutil.cc
@@ -1,11 +1,15 @@
 #include "strutil.h"
 
 #include <ctype.h>
+#include <limits.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <unordered_map>
 #include <utility>
 
+#include "log.h"
+
 WordScanner::Iterator& WordScanner::Iterator::operator++() {
   int len = static_cast<int>(in->size());
   for (s = i; s < len; s++) {
@@ -228,3 +232,50 @@
     return s;
   return s.substr(0, found);
 }
+
+void AbsPath(StringPiece s, string* o) {
+  if (s.get(0) == '/') {
+    o->clear();
+  } else {
+    char buf[PATH_MAX];
+    if (!getcwd(buf, PATH_MAX)) {
+      fprintf(stderr, "getcwd failed\n");
+      CHECK(false);
+    }
+
+    CHECK(buf[0] == '/');
+    *o = buf;
+    *o += '/';
+  }
+  AppendString(s, o);
+
+  size_t j = 1;
+  size_t prev_start = 1;
+  for (size_t i = 1; i < o->size(); i++) {
+    char c= (*o)[i];
+    if (c != '/') {
+      (*o)[j] = c;
+      j++;
+      continue;
+    }
+
+    StringPiece prev_dir = StringPiece(o->data() + prev_start, j - prev_start);
+    if (prev_dir == ".") {
+      j--;
+    } else if (prev_dir == "..") {
+      j -= 4;
+      j = o->rfind('/', j);
+      if (j == string::npos) {
+        j = 1;
+      } else {
+        j++;
+      }
+    } else if (!prev_dir.empty()) {
+      (*o)[j] = c;
+      j++;
+    }
+    LOG("%zu => %zu", prev_start, j);
+    prev_start = j;
+  }
+  o->resize(j);
+}
diff --git a/strutil.h b/strutil.h
index 592333c..a24abfa 100644
--- a/strutil.h
+++ b/strutil.h
@@ -86,5 +86,6 @@
 StringPiece Basename(StringPiece s);
 StringPiece GetExt(StringPiece s);
 StringPiece StripExt(StringPiece s);
+void AbsPath(StringPiece s, string* o);
 
 #endif  // STRUTIL_H_
diff --git a/testcase/abspath.mk b/testcase/abspath.mk
index 91c7722..3b2f9af 100644
--- a/testcase/abspath.mk
+++ b/testcase/abspath.mk
@@ -1,4 +1,4 @@
-foo = $(abspath ./foo)
+foo = $(abspath ./foo bar/../foo bar//..//foo / /usr)
 
 test:
 	echo $(foo)