[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)