ccls/src/utils.cc

179 lines
5.1 KiB
C++
Raw Normal View History

2018-08-21 05:27:52 +00:00
/* Copyright 2017-2018 ccls Authors
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.
==============================================================================*/
2017-02-17 09:57:44 +00:00
#include "utils.h"
2018-05-27 19:24:56 +00:00
#include "log.hh"
#include "platform.h"
2018-01-30 00:27:43 +00:00
#include <siphash.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
using namespace llvm;
2018-08-09 17:08:14 +00:00
#include <algorithm>
2018-03-31 18:32:28 +00:00
#include <assert.h>
#include <ctype.h>
2018-04-07 17:43:56 +00:00
#include <errno.h>
#include <functional>
2018-08-09 17:08:14 +00:00
#include <string.h>
2017-04-08 22:54:36 +00:00
#include <unordered_map>
2017-02-17 09:57:44 +00:00
namespace ccls {
2018-03-31 18:32:28 +00:00
uint64_t HashUsr(std::string_view s) {
union {
uint64_t ret;
uint8_t out[8];
};
2018-01-14 21:18:12 +00:00
// k is an arbitrary key. Don't change it.
const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52,
0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d};
2018-08-09 17:08:14 +00:00
(void)siphash(reinterpret_cast<const uint8_t *>(s.data()), s.size(), k, out,
8);
return ret;
}
2018-07-07 23:56:47 +00:00
uint64_t HashUsr(llvm::StringRef s) {
return HashUsr(std::string_view(s.data(), s.size()));
}
2018-03-31 18:32:28 +00:00
bool EndsWith(std::string_view s, std::string_view suffix) {
return s.size() >= suffix.size() &&
std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
2017-03-31 04:15:42 +00:00
}
2018-03-31 18:32:28 +00:00
bool StartsWith(std::string_view s, std::string_view prefix) {
return s.size() >= prefix.size() &&
std::equal(prefix.begin(), prefix.end(), s.begin());
2017-03-31 04:15:42 +00:00
}
2018-08-09 17:08:14 +00:00
bool EndsWithAny(std::string_view s, const std::vector<std::string> &ss) {
return std::any_of(ss.begin(), ss.end(),
std::bind(EndsWith, s, std::placeholders::_1));
}
2018-08-09 17:08:14 +00:00
bool FindAnyPartial(const std::string &value,
const std::vector<std::string> &values) {
2018-01-30 00:27:43 +00:00
return std::any_of(std::begin(values), std::end(values),
2018-08-09 17:08:14 +00:00
[&value](const std::string &v) {
2018-01-30 00:27:43 +00:00
return value.find(v) != std::string::npos;
});
}
2018-08-09 17:08:14 +00:00
std::vector<std::string> SplitString(const std::string &str,
const std::string &delimiter) {
// http://stackoverflow.com/a/13172514
std::vector<std::string> strings;
std::string::size_type pos = 0;
std::string::size_type prev = 0;
while ((pos = str.find(delimiter, prev)) != std::string::npos) {
strings.push_back(str.substr(prev, pos - prev));
prev = pos + 1;
}
// To get the last substring (or only, if delimiter is not found)
strings.push_back(str.substr(prev));
return strings;
}
2018-08-09 17:08:14 +00:00
std::string LowerPathIfInsensitive(const std::string &path) {
#if defined(_WIN32)
2018-03-31 18:32:28 +00:00
std::string ret = path;
2018-08-09 17:08:14 +00:00
for (char &c : ret)
2018-03-31 18:32:28 +00:00
c = tolower(c);
return ret;
#else
return path;
#endif
}
2018-08-09 17:08:14 +00:00
void EnsureEndsInSlash(std::string &path) {
if (path.empty() || path[path.size() - 1] != '/')
path += '/';
}
2017-12-02 05:07:30 +00:00
std::string EscapeFileName(std::string path) {
2018-03-31 18:32:28 +00:00
bool slash = path.size() && path.back() == '/';
2018-08-09 17:08:14 +00:00
for (char &c : path)
2018-03-31 18:32:28 +00:00
if (c == '\\' || c == '/' || c == ':')
c = '@';
if (slash)
path += '/';
2017-12-02 05:07:30 +00:00
return path;
}
std::string ResolveIfRelative(const std::string &directory,
const std::string &path) {
if (sys::path::is_absolute(path))
return path;
SmallString<256> Ret;
sys::path::append(Ret, directory, path);
return NormalizePath(Ret.str());
}
std::optional<int64_t> LastWriteTime(const std::string &path) {
sys::fs::file_status Status;
if (sys::fs::status(path, Status))
return {};
return sys::toTimeT(Status.getLastModificationTime());
}
2018-08-09 17:08:14 +00:00
std::optional<std::string> ReadContent(const std::string &filename) {
2018-03-31 18:32:28 +00:00
char buf[4096];
std::string ret;
2018-08-09 17:08:14 +00:00
FILE *f = fopen(filename.c_str(), "rb");
if (!f)
return {};
2018-03-31 18:32:28 +00:00
size_t n;
while ((n = fread(buf, 1, sizeof buf, f)) > 0)
ret.append(buf, n);
fclose(f);
2018-03-31 18:32:28 +00:00
return ret;
}
2018-08-09 17:08:14 +00:00
void WriteToFile(const std::string &filename, const std::string &content) {
FILE *f = fopen(filename.c_str(), "wb");
if (!f ||
(content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) {
LOG_S(ERROR) << "failed to write to " << filename << ' ' << strerror(errno);
return;
}
2018-03-31 18:32:28 +00:00
fclose(f);
2017-03-09 18:02:55 +00:00
}
// Find discontinous |search| in |content|.
// Return |found| and the count of skipped chars before found.
2018-08-09 17:08:14 +00:00
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
int case_sensitivity) {
if (case_sensitivity == 1)
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
int j = pat.size();
if (!j)
return text.size();
for (int i = text.size(); i--;)
if ((case_sensitivity ? text[i] == pat[j - 1]
: tolower(text[i]) == tolower(pat[j - 1])) &&
!--j)
return i;
return -1;
}
2018-08-09 17:08:14 +00:00
std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; }
}