2019-12-14 22:33:57 +01:00
|
|
|
#include <fxos/util.h>
|
2020-01-19 18:17:01 +01:00
|
|
|
#include <filesystem>
|
2019-12-15 18:40:05 +01:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
2020-01-19 18:17:01 +01:00
|
|
|
#include <ctime>
|
2021-03-16 12:27:19 +01:00
|
|
|
#include <map>
|
2019-12-14 22:33:57 +01:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2019-12-15 18:40:05 +01:00
|
|
|
#include <sys/stat.h>
|
2019-12-14 22:33:57 +01:00
|
|
|
|
2019-12-28 17:18:13 +01:00
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
2021-03-16 12:27:19 +01:00
|
|
|
std::string colors(std::string str)
|
|
|
|
{
|
|
|
|
std::map<int, std::string> colors = {
|
|
|
|
// Gray, Red, Green, Yello, Blue, Magenta, Cyan, White
|
|
|
|
{'A',"30;1"}, {'R',"31;1"}, {'G',"32;1"}, {'Y',"33;1"},
|
|
|
|
{'B',"34;1"}, {'M',"35;1"}, {'C',"36;1"}, {'W',"37;1"},
|
|
|
|
// Same but without bold
|
|
|
|
{'a',"30"}, {'r',"31"}, {'g',"32"}, {'y',"33"},
|
|
|
|
{'b',"34"}, {'m',"35"}, {'c',"36"}, {'w',"37"},
|
|
|
|
// Italic, parameter shortcut
|
|
|
|
{'i',"3"}, {'P',"32m\x1b[3"},
|
|
|
|
};
|
|
|
|
bool show = isatty(STDOUT_FILENO);
|
|
|
|
|
|
|
|
for(size_t i = 0; i < str.size() - 2; i++) {
|
|
|
|
if(str[i] == '<' && str[i+1] == '>')
|
|
|
|
str.replace(i, 2, show ? "\x1b[0m" : "");
|
|
|
|
else if(str[i] == '<' && str[i+2] == '>' && colors.count(str[i+1]))
|
|
|
|
str.replace(i, 3, show ? "\x1b[" + colors[str[i+1]] + "m" : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2019-12-28 17:18:13 +01:00
|
|
|
Buffer::Buffer():
|
|
|
|
size {0}, data {nullptr}, path {"(none)"}
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-15 18:40:05 +01:00
|
|
|
/* Empty buffer initialized with given byte */
|
2019-12-28 17:18:13 +01:00
|
|
|
Buffer::Buffer(size_t bufsize, int fill)
|
2019-12-14 22:33:57 +01:00
|
|
|
{
|
2019-12-28 17:18:13 +01:00
|
|
|
size = bufsize;
|
2020-02-28 16:19:50 +01:00
|
|
|
char *buffer = new char[size];
|
2020-02-16 21:43:58 +01:00
|
|
|
memset(buffer, fill, size);
|
2019-12-15 18:40:05 +01:00
|
|
|
|
2020-02-16 21:43:58 +01:00
|
|
|
data = std::shared_ptr<char>(buffer);
|
2019-12-28 17:18:13 +01:00
|
|
|
path = "(anonymous)";
|
|
|
|
}
|
2019-12-15 18:40:05 +01:00
|
|
|
|
|
|
|
/* Buffer initialized from file */
|
2019-12-28 17:18:13 +01:00
|
|
|
Buffer::Buffer(std::string filepath, ssize_t bufsize, int fill)
|
2019-12-15 18:40:05 +01:00
|
|
|
{
|
|
|
|
char const *path = filepath.c_str();
|
2019-12-14 22:33:57 +01:00
|
|
|
|
|
|
|
int fd = open(path, O_RDONLY);
|
|
|
|
if(!fd) throw std::runtime_error(format("cannot open '%s'", path));
|
|
|
|
|
|
|
|
struct stat statbuf;
|
|
|
|
ssize_t x = fstat(fd, &statbuf);
|
|
|
|
|
|
|
|
if(x < 0)
|
|
|
|
{
|
|
|
|
close(fd);
|
|
|
|
throw std::runtime_error(format("cannot stat '%s'", path));
|
|
|
|
}
|
|
|
|
|
2019-12-28 17:18:13 +01:00
|
|
|
size = (bufsize < 0) ? statbuf.st_size : bufsize;
|
|
|
|
size_t size_to_read = std::min(size, (size_t)statbuf.st_size);
|
2019-12-14 22:33:57 +01:00
|
|
|
|
2019-12-15 18:40:05 +01:00
|
|
|
/* Read buffer and fill whatever is left */
|
2020-02-28 16:19:50 +01:00
|
|
|
data = std::shared_ptr<char>(new char[size]);
|
|
|
|
memset(data.get(), fill, size);
|
|
|
|
x = read(fd, data.get(), size_to_read);
|
2019-12-15 18:40:05 +01:00
|
|
|
|
|
|
|
close(fd);
|
|
|
|
if(x != (ssize_t)size_to_read)
|
2019-12-14 22:33:57 +01:00
|
|
|
{
|
2019-12-15 18:40:05 +01:00
|
|
|
throw std::runtime_error(format(
|
|
|
|
"error while reading '%s'", path));
|
|
|
|
}
|
2019-12-14 22:33:57 +01:00
|
|
|
|
2019-12-28 17:18:13 +01:00
|
|
|
this->path = filepath;
|
2019-12-15 18:40:05 +01:00
|
|
|
}
|
2019-12-14 22:33:57 +01:00
|
|
|
|
2021-03-16 13:19:41 +01:00
|
|
|
Buffer::Buffer(std::string filepath, std::vector<std::string> const &folders,
|
2019-12-28 17:18:13 +01:00
|
|
|
ssize_t size, int fill):
|
|
|
|
Buffer()
|
2019-12-15 18:40:05 +01:00
|
|
|
{
|
2019-12-28 17:18:13 +01:00
|
|
|
for(auto &f: folders)
|
|
|
|
{
|
|
|
|
fs::path p = fs::path(f) / fs::path(filepath);
|
|
|
|
if(fs::exists(p))
|
|
|
|
{
|
|
|
|
/* Hopefully this will use the move assignment */
|
|
|
|
*this = Buffer(p, size, fill);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char const *path = filepath.c_str();
|
|
|
|
throw std::runtime_error(format("cannot find '%s' in library", path));
|
2019-12-14 22:33:57 +01:00
|
|
|
}
|
|
|
|
|
2019-12-15 18:40:05 +01:00
|
|
|
/* Create a buffer by copying and resizing another buffer */
|
|
|
|
Buffer::Buffer(Buffer const &other, size_t new_size, int fill):
|
|
|
|
Buffer(new_size, fill)
|
2019-12-14 22:33:57 +01:00
|
|
|
{
|
2020-02-16 21:43:58 +01:00
|
|
|
memcpy(data.get(), other.data.get(), std::min(new_size, other.size));
|
2019-12-14 22:33:57 +01:00
|
|
|
}
|
2020-01-19 18:17:01 +01:00
|
|
|
|
|
|
|
/* Generic timer which returns times in ns using CLOCK_REALTIME */
|
|
|
|
struct timespec timer_start(void)
|
|
|
|
{
|
|
|
|
struct timespec start;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &start);
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
long long timer_end(struct timespec start)
|
|
|
|
{
|
|
|
|
struct timespec end;
|
|
|
|
clock_gettime(CLOCK_REALTIME, &end);
|
|
|
|
|
|
|
|
long long ns = 1000000000 * (end.tv_sec - start.tv_sec);
|
|
|
|
ns += end.tv_nsec - start.tv_nsec;
|
|
|
|
return ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Format ns durations to us, ms or s depending on the value */
|
|
|
|
std::string timer_format(long long duration)
|
|
|
|
{
|
|
|
|
if(duration < 2000) return format("%lld ns", duration);
|
|
|
|
duration /= 1000;
|
|
|
|
if(duration < 2000) return format("%lld us", duration);
|
|
|
|
duration /= 1000;
|
|
|
|
if(duration < 2000) return format("%lld ms", duration);
|
|
|
|
duration /= 1000;
|
|
|
|
return format("%lld s", duration);
|
|
|
|
}
|