mf/utils.cpp

104 lines
3.5 KiB
C++

#include <cstring>
#include <unistd.h>
#include "database.h"
#include "utils.h"
static std::filesystem::path normalize(std::filesystem::path path);
static std::optional<std::filesystem::path> relative_path_from(const std::filesystem::path& from, const std::filesystem::path& path);
void output_meme(const char* path, const char* source, const char* description, const char* miscinfo, int fd, bool edit) {
auto output = [=](const char* header, const char* contents, bool end = false) {
write(fd, "# ", 2);
write(fd, header, strlen(header));
write(fd, ":\n", 2);
write(fd, contents, strlen(contents));
write(fd, "\n", 1);
if (!end) {
write(fd, edit ? "\n\0\n" : "\n", edit ? 3 : 1);
}
};
output(edit ? "Path (immutable)" : "Path", path);
output("Source", source);
output("Description", description);
output("Miscellaneous information", miscinfo, true);
}
std::vector<std::filesystem::path> get_paths_relative_to_database(const blankie::cliparse::Parser& parser, const Database& db, int* rc, bool needs_exist) {
std::vector<std::filesystem::path> paths;
paths.reserve(parser.arguments.size() - 1);
for (size_t i = 1; i < parser.arguments.size(); i++) {
std::filesystem::path normalized_path = normalize(parser.arguments[i]);
std::optional<std::filesystem::path> relative_path = relative_path_from(db.path.parent_path(), normalized_path);
if (!relative_path) {
fprintf(stderr, "%s is not in %s\n", normalized_path.c_str(), db.path.parent_path().c_str());
*rc = 1;
} else if (needs_exist && !std::filesystem::is_regular_file(normalized_path)) {
fprintf(stderr, "%s is not a file\n", normalized_path.c_str());
*rc = 1;
} else {
paths.push_back(*relative_path);
}
}
return paths;
}
std::filesystem::path get_path_relative_to_database(const char* path, const Database& db) {
std::filesystem::path normalized_path = normalize(path);
std::optional<std::filesystem::path> relative_path = relative_path_from(db.path.parent_path(), normalized_path);
if (!relative_path) {
fprintf(stderr, "%s is not in %s\n", normalized_path.c_str(), db.path.parent_path().c_str());
exit(1);
}
if (!std::filesystem::is_regular_file(normalized_path)) {
fprintf(stderr, "%s is not a file\n", normalized_path.c_str());
exit(1);
}
return *relative_path;
}
std::filesystem::path normalize(std::filesystem::path path) {
if (path.is_relative()) {
path = std::filesystem::current_path() / path;
}
std::filesystem::path normalized = path.root_path();
for (auto it = path.begin(); it != path.end(); it++) {
if (*it == ".") {
// do nothing
} else if (*it == "..") {
normalized = normalized.parent_path();
} else {
normalized /= *it;
}
}
return normalized;
}
std::optional<std::filesystem::path> relative_path_from(const std::filesystem::path& from, const std::filesystem::path& path) {
auto from_it = from.begin();
auto path_it = path.begin();
for (; from_it != from.end() && path_it != path.end(); from_it++, path_it++) {
if (*from_it != *path_it) {
return std::nullopt;
}
}
if (from_it != from.end()) {
return std::nullopt;
}
std::filesystem::path name;
for (; path_it != path.end(); path_it++) {
name /= *path_it;
}
return name;
}