}
if (sp.removePrefix("./")) {
+ // Also remove any subsequent slashes to avoid making this path absolute.
+ while (sp.startsWith('/')) {
+ sp.advance(1);
+ }
continue;
}
return;
}
- // Strip trailing slashes
- while (sp.removeSuffix('/')) { }
+ // Strip trailing slashes, except when this is the root path.
+ while (sp.size() > 1 && sp.removeSuffix('/')) { }
if (sp.removeSuffix("/.")) {
continue;
baseDir_.clear(); // subDir_ is absolute
}
- // Make sure that baseDir_ isn't empty; subDir_ may be
- if (baseDir_.empty()) {
- swap(baseDir_, subDir_);
- }
-
simplifyPath(baseDir_);
simplifyPath(subDir_);
simplifyPath(file_);
+
+ // Make sure it's never the case that baseDir_ is empty, but subDir_ isn't.
+ if (baseDir_.empty()) {
+ swap(baseDir_, subDir_);
+ }
}
size_t Dwarf::Path::size() const {
- if (baseDir_.empty()) {
- assert(subDir_.empty());
- return file_.size();
+ size_t size = 0;
+ bool needsSlash = false;
+
+ if (!baseDir_.empty()) {
+ size += baseDir_.size();
+ needsSlash = !baseDir_.endsWith('/');
+ }
+
+ if (!subDir_.empty()) {
+ size += needsSlash;
+ size += subDir_.size();
+ needsSlash = !subDir_.endsWith('/');
}
- return
- baseDir_.size() + !subDir_.empty() + subDir_.size() + !file_.empty() +
- file_.size();
+ if (!file_.empty()) {
+ size += needsSlash;
+ size += file_.size();
+ }
+
+ return size;
}
size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const {
size_t totalSize = 0;
+ bool needsSlash = false;
auto append = [&] (folly::StringPiece sp) {
if (bufSize >= 2) {
if (!baseDir_.empty()) {
append(baseDir_);
+ needsSlash = !baseDir_.endsWith('/');
}
if (!subDir_.empty()) {
- assert(!baseDir_.empty());
- append("/");
+ if (needsSlash) {
+ append("/");
+ }
append(subDir_);
+ needsSlash = !subDir_.endsWith('/');
}
if (!file_.empty()) {
- if (!baseDir_.empty()) {
+ if (needsSlash) {
append("/");
}
append(file_);
void Dwarf::Path::toString(std::string& dest) const {
size_t initialSize = dest.size();
+ bool needsSlash = false;
dest.reserve(initialSize + size());
if (!baseDir_.empty()) {
dest.append(baseDir_.begin(), baseDir_.end());
+ needsSlash = baseDir_.endsWith('/');
}
if (!subDir_.empty()) {
- assert(!baseDir_.empty());
- dest.push_back('/');
+ if (needsSlash) {
+ dest.push_back('/');
+ }
dest.append(subDir_.begin(), subDir_.end());
+ needsSlash = subDir_.endsWith('/');
}
if (!file_.empty()) {
- dest.push_back('/');
+ if (needsSlash) {
+ dest.push_back('/');
+ }
dest.append(file_.begin(), file_.end());
}
assert(dest.size() == initialSize + size());
--- /dev/null
+/*
+ * Copyright 2014 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/experimental/symbolizer/Dwarf.h>
+
+#include <gtest/gtest.h>
+
+using folly::symbolizer::Dwarf;
+
+void checkPath(
+ std::string expectedPath,
+ std::string expectedBaseDir,
+ std::string expectedSubDir,
+ std::string expectedFile,
+ std::string rawBaseDir,
+ std::string rawSubDir,
+ std::string rawFile) {
+ Dwarf::Path path(rawBaseDir, rawSubDir, rawFile);
+
+ CHECK_EQ(expectedBaseDir, path.baseDir())
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+ CHECK_EQ(expectedSubDir, path.subDir())
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+ CHECK_EQ(expectedFile, path.file())
+ << "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
+
+ CHECK_EQ(expectedPath, path.toString());
+
+ // Check the the `toBuffer` function.
+ char buf[1024];
+ size_t len;
+ len = path.toBuffer(buf, 1024);
+ CHECK_EQ(expectedPath, std::string(buf, len));
+}
+
+TEST(Dwarf, Path) {
+ checkPath(
+ "hello.cpp",
+ "",
+ "",
+ "hello.cpp",
+ "",
+ "",
+ "hello.cpp");
+ checkPath(
+ "foo/hello.cpp",
+ "foo",
+ "",
+ "hello.cpp",
+ "foo",
+ "",
+ "hello.cpp");
+ checkPath(
+ "foo/hello.cpp",
+ "foo",
+ "",
+ "hello.cpp",
+ "",
+ "foo",
+ "hello.cpp");
+ checkPath(
+ "hello.cpp",
+ "",
+ "",
+ "hello.cpp",
+ "./////",
+ "./////",
+ "hello.cpp");
+ checkPath(
+ "/hello.cpp",
+ "/",
+ "",
+ "hello.cpp",
+ "/////",
+ "./////",
+ "hello.cpp");
+ checkPath(
+ "/hello.cpp",
+ "/",
+ "",
+ "hello.cpp",
+ "/./././././././",
+ "",
+ "hello.cpp");
+}