From 01738449c56cb60f3bf8947f8aa012b7196a0dc3 Mon Sep 17 00:00:00 2001 From: Bob Polis Date: Fri, 19 Jul 2024 16:36:25 +0200 Subject: [PATCH] Add implementation --- premake.make | 2 +- src/main.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/premake.make b/premake.make index 456557b..59ab771 100644 --- a/premake.make +++ b/premake.make @@ -1,2 +1,2 @@ -LDLIBS := +LDLIBS := -lscstring -lscerror -lscterm MANSECTION := 1 diff --git a/src/main.cpp b/src/main.cpp index b89c219..e70be76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,93 @@ +// C++ +#include #include #include #include #include +#include +#include +#include + +// POSIX #include +#include + +//libraries +#include +#include +#include + +// project #include "commit.inc" -void print_help() { +std::vector additions; +std::string change; +std::map changes; +std::vector deletions; +bool should_list = false; + +static void handle_additions(std::vector& tags) { + for (const std::string& tag : additions) { + tags.push_back(tag); + } +} + +static void handle_changes(std::vector& tags) { + for (const auto& elem : changes) { + auto it = std::find(tags.begin(), tags.end(), elem.first); + if (it != tags.end()) { + *it = elem.second; + } + } +} + +static void handle_deletions(std::vector& tags) { + for (const std::string& tag : deletions) { + tags.erase(std::remove(tags.begin(), tags.end(), tag), tags.end()); + } +} + +static void process(const char* path) { + const char* tagname {"user.xdg.tags"}; + std::vector tags; + std::vector buf(1024); + ssize_t sz = getxattr(path, tagname, buf.data(), buf.size()); + if (sz == -1) { + if (errno != ENODATA) { + throw_if_min1(sz); + } + } else { + std::string val(buf.data(), sz); + tags = sc::split(val, ","); + } + bool edits = additions.size() > 0 || changes.size() > 0 || deletions.size() > 0; + if (edits) { + if (should_list) { + std::cout << path << '\n'; + std::cout << " before: " << sc::join(tags, ", ") << '\n'; + } + handle_deletions(tags); + handle_changes(tags); + handle_additions(tags); + if (should_list) { + std::cout << " after: " << sc::join(tags, ", ") << '\n'; + } + std::string joined {sc::join(tags, ",")}; + throw_if_min1(setxattr(path, tagname, joined.c_str(), joined.size(), 0)); + } else { + if (should_list) { + std::cout << path << ": " << sc::io::yellowf << sc::join(tags, ", ") << sc::io::reset << '\n'; + } + } +} + +static void print_help() { std::cout << "usage: tagger [-h|--version]\n"; std::cout << " -h, --help show this help text and exit\n"; std::cout << " --version show version number and exit\n"; } -void print_version() { +static void print_version() { std::cout << "tagger version 1.0"; if (commit[0] != '\0') { std::cout << ", build " << commit; @@ -25,9 +101,14 @@ int main(int argc, char* argv[]) { struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, {"version", no_argument, &opt_val, 1}, + {"add", required_argument, nullptr, 'a'}, + {"delete", required_argument, nullptr, 'd'}, + {"change", required_argument, nullptr, 'c'}, + {"into", required_argument, nullptr, 'i'}, + {"list", no_argument, nullptr, 'l'}, {nullptr, 0, nullptr, 0} }; - while ((opt_char = getopt_long(argc, argv, "h", long_options, nullptr)) != -1) { + while ((opt_char = getopt_long(argc, argv, "a:c:d:hi:l", long_options, nullptr)) != -1) { std::string arg {optarg ? optarg : ""}; switch (opt_char) { case 0: { @@ -39,24 +120,39 @@ int main(int argc, char* argv[]) { } break; } + case 'a': + additions.push_back(arg); + break; + case 'c': + change = arg; + break; + case 'd': + deletions.push_back(arg); + break; case 'h': print_help(); return EXIT_SUCCESS; + case 'i': + changes.emplace(change, arg); + break; + case 'l': + should_list = true; + break; case '?': throw std::runtime_error("unrecognized option"); } } if (optind == argc) { // here when no file args + throw std::runtime_error {"please specify input files"}; } for (int i = optind; i < argc; ++i) { try { - // process file argv[i] + process(argv[i]); } catch (const std::runtime_error& ex) { std::cerr << "tagger: " << ex.what() << '\n'; } } - std::cout << "hello, tagger\n"; } catch (const std::exception& ex) { std::cerr << "tagger: " << ex.what() << '\n'; return EXIT_FAILURE;