Add implementation
This commit is contained in:
		| @@ -1,2 +1,2 @@ | ||||
| LDLIBS := | ||||
| LDLIBS := -lscstring -lscerror -lscterm | ||||
| MANSECTION := 1 | ||||
|   | ||||
							
								
								
									
										106
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -1,17 +1,93 @@ | ||||
| // C++ | ||||
| #include <cerrno> | ||||
| #include <iostream> | ||||
| #include <cstdlib> | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| #include <sys/types.h> | ||||
| #include <vector> | ||||
| #include <map> | ||||
|  | ||||
| // POSIX | ||||
| #include <getopt.h> | ||||
| #include <sys/xattr.h> | ||||
|  | ||||
| //libraries | ||||
| #include <libscstring.hpp> | ||||
| #include <libscerror.hpp> | ||||
| #include <libscterm.hpp> | ||||
|  | ||||
| // project | ||||
| #include "commit.inc" | ||||
|  | ||||
| void print_help() { | ||||
| std::vector<std::string> additions; | ||||
| std::string change; | ||||
| std::map<std::string, std::string> changes; | ||||
| std::vector<std::string> deletions; | ||||
| bool should_list = false; | ||||
|  | ||||
| static void handle_additions(std::vector<std::string>& tags) { | ||||
|     for (const std::string& tag : additions) { | ||||
|         tags.push_back(tag); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void handle_changes(std::vector<std::string>& 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<std::string>& 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<std::string> tags; | ||||
|     std::vector<char> 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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user