189 lines
4.1 KiB
C++
189 lines
4.1 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* 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/SymbolizedFrame.h>
|
|
|
|
namespace folly {
|
|
namespace symbolizer {
|
|
|
|
namespace {
|
|
|
|
// Simplify a path -- as much as we can while not moving data around...
|
|
void simplifyPath(StringPiece& sp) {
|
|
// Strip leading slashes and useless patterns (./), leaving one initial
|
|
// slash.
|
|
for (;;) {
|
|
if (sp.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Strip leading slashes, leaving one.
|
|
while (sp.startsWith("//")) {
|
|
sp.advance(1);
|
|
}
|
|
|
|
if (sp.startsWith("/./")) {
|
|
// Note 2, not 3, to keep it absolute
|
|
sp.advance(2);
|
|
continue;
|
|
}
|
|
|
|
if (sp.removePrefix("./")) {
|
|
// Also remove any subsequent slashes to avoid making this path absolute.
|
|
while (sp.startsWith('/')) {
|
|
sp.advance(1);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Strip trailing slashes and useless patterns (/.).
|
|
for (;;) {
|
|
if (sp.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Strip trailing slashes, except when this is the root path.
|
|
while (sp.size() > 1 && sp.removeSuffix('/')) {
|
|
}
|
|
|
|
if (sp.removeSuffix("/.")) {
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
Path::Path(StringPiece baseDir, StringPiece subDir, StringPiece file)
|
|
: baseDir_(baseDir), subDir_(subDir), file_(file) {
|
|
using std::swap;
|
|
|
|
// Normalize
|
|
if (file_.empty()) {
|
|
baseDir_.clear();
|
|
subDir_.clear();
|
|
return;
|
|
}
|
|
|
|
if (file_[0] == '/') {
|
|
// file_ is absolute
|
|
baseDir_.clear();
|
|
subDir_.clear();
|
|
}
|
|
|
|
if (!subDir_.empty() && subDir_[0] == '/') {
|
|
baseDir_.clear(); // subDir_ is absolute
|
|
}
|
|
|
|
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 Path::size() const {
|
|
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('/');
|
|
}
|
|
|
|
if (!file_.empty()) {
|
|
size += needsSlash;
|
|
size += file_.size();
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
size_t Path::toBuffer(char* buf, size_t bufSize) const {
|
|
size_t totalSize = 0;
|
|
bool needsSlash = false;
|
|
|
|
auto append = [&](StringPiece sp) {
|
|
if (bufSize >= 2) {
|
|
size_t toCopy = std::min(sp.size(), bufSize - 1);
|
|
memcpy(buf, sp.data(), toCopy);
|
|
buf += toCopy;
|
|
bufSize -= toCopy;
|
|
}
|
|
totalSize += sp.size();
|
|
};
|
|
|
|
if (!baseDir_.empty()) {
|
|
append(baseDir_);
|
|
needsSlash = !baseDir_.endsWith('/');
|
|
}
|
|
if (!subDir_.empty()) {
|
|
if (needsSlash) {
|
|
append("/");
|
|
}
|
|
append(subDir_);
|
|
needsSlash = !subDir_.endsWith('/');
|
|
}
|
|
if (!file_.empty()) {
|
|
if (needsSlash) {
|
|
append("/");
|
|
}
|
|
append(file_);
|
|
}
|
|
if (bufSize) {
|
|
*buf = '\0';
|
|
}
|
|
assert(totalSize == size());
|
|
return totalSize;
|
|
}
|
|
|
|
void Path::toString(std::string& dest) const {
|
|
size_t initialSize = dest.size();
|
|
dest.reserve(initialSize + size());
|
|
if (!baseDir_.empty()) {
|
|
dest.append(baseDir_.begin(), baseDir_.end());
|
|
}
|
|
if (!subDir_.empty()) {
|
|
if (!dest.empty() && dest.back() != '/') {
|
|
dest.push_back('/');
|
|
}
|
|
dest.append(subDir_.begin(), subDir_.end());
|
|
}
|
|
if (!file_.empty()) {
|
|
if (!dest.empty() && dest.back() != '/') {
|
|
dest.push_back('/');
|
|
}
|
|
dest.append(file_.begin(), file_.end());
|
|
}
|
|
assert(dest.size() == initialSize + size());
|
|
}
|
|
|
|
} // namespace symbolizer
|
|
} // namespace folly
|