#include #include #include "database.h" #include "utils.h" static std::filesystem::path normalize(std::filesystem::path path); static std::optional 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 get_paths_relative_to_database(const blankie::cliparse::Parser& parser, const Database& db, int* rc, bool needs_exist) { std::vector 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 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 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 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; }