123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- #include <deque>
- #include <iostream>
- #include <iomanip>
- #include "simple/file.hpp"
- #include "simple/support/enum.hpp"
- #include "simple/support/misc.hpp"
- #include "simple/support/algorithm.hpp"
- #include "simple/support/iterator/match.hpp"
- using namespace simple;
- using namespace std::literals;
- enum class Options
- {
- Padding,
- Color,
- Source,
- Format,
- Separator,
- Wordwise,
- Invalid
- };
- using Option = support::mapped_enum<Options, Options::Invalid, 2>;
- template <> Option::guts::map_type Option::guts::map
- {{
- { "-p"s, "--padding"s },
- { "-c"s, "--color"s },
- { "-i"s, "--source"s },
- { "-f"s, "--format"s },
- { "-s"s, "--separator"s },
- { "-w"s, "--words"s },
- }};
- enum class Formats
- {
- PlainText, OneLine, Hex,
- Invalid
- };
- using Format = support::mapped_enum<Formats, Formats::Invalid>;
- template <> Format::guts::map_type Format::guts::map
- {{
- { "plain"s }, { "one-line"s }, { "hex"s },
- }};
- enum class Colors
- {
- Black, Red,
- Green, Yellow,
- Blue, Magenta,
- Cyan, White,
- Invalid
- };
- using Color = support::mapped_enum<Colors, Colors::Invalid>;
- template <> Color::guts::map_type Color::guts::map
- {{
- { "black"s }, { "red"s },
- { "green"s }, { "yellow"s },
- { "blue"s }, { "magenta"s },
- { "cyan"s }, { "white"s }
- }};
- using buffer = std::vector<unsigned char>;
- using const_range = support::range<buffer::const_iterator>;
- template <typename Range>
- void print(Range range, Format format, Color color = Colors::Invalid)
- {
- assert(range.valid());
- auto cout_flags = std::cout.flags();
- std::cout << std::hex;
- if(Colors::Invalid != color)
- std::cout << "\33[4" << char('0' + (int)Colors(color)) << 'm';
- switch(format)
- {
- case Formats::Hex:
- if constexpr (std::is_same_v<Range, const_range>)
- for(auto&& c : range)
- {
- if(c <= 0xf)
- std::cout << '0';
- std::cout << +c;
- }
- else std::cerr << "ERROR: Hex format not supported for wordwise crop." << '\n';
- break;
- case Formats::OneLine:
- if constexpr (std::is_same_v<Range, const_range>)
- for(auto&& c : range)
- {
- auto cc = '\n' == c ? 'n' : '\r' == c ? 'r' : c;
- if(cc != c)
- std::cout << "\33[7m" << cc << "\33[27m";
- else
- std::cout << c;
- }
- else std::cerr << "ERROR: One line format not supported for wordwise crop." << '\n';
- break;
- default:
- for(auto&& c : range)
- {
- std::cout << c;
- if constexpr (not std::is_same_v<Range, const_range>)
- std::cout << ' ';
- }
- }
- if(Colors::Invalid != color)
- std::cout << "\33[0m";
- std::cout.flags(cout_flags);
- }
- auto split_words(const buffer& b)
- {
- std::vector<std::string> words;
- simple::support::split(b, simple::support::match_iterator(simple::support::is_space), std::back_inserter(words));
- return words;
- }
- void crop(const std::string& filename, const std::string& range, Color color, int padding, Format format, bool wordwise)
- {
- auto r = support::storn<int64_t>(range);
- const auto source = file::dump<buffer>(file::bropex(filename));
- auto do_print = [r, padding, format, color](const auto& source)
- {
- print(support::get_iterator_range<int64_t>(source, {r.lower()-padding , r.lower()}), format);
- print(support::get_iterator_range<int64_t>(source, r), format, color);
- print(support::get_iterator_range<int64_t>(source, {r.upper(), r.upper()+padding}), format);
- };
- if(wordwise)
- do_print(split_words(source));
- else
- do_print(source);
- }
- void process_arguments(std::deque<std::string> args)
- {
- std::string filename;
- std::string separator;
- Color color;
- Format format;
- int padding = 0;
- bool wordwise = false;
- args.pop_front();
- while(!args.empty())
- {
- switch(Option(args.front()))
- {
- case Options::Padding:
- args.pop_front();
- padding = support::ston<int>(args.at(0));
- if(padding < 0)
- throw std::out_of_range("negative padding");
- break;
- case Options::Color:
- args.pop_front();
- color = Color(args.at(0));
- break;
- case Options::Source:
- args.pop_front();
- filename = args.at(0);
- break;
- case Options::Separator:
- args.pop_front();
- separator = args.at(0) + '\n';
- break;
- case Options::Format:
- args.pop_front();
- format = Format(args.at(0));
- break;
- case Options::Wordwise:
- args.pop_front();
- wordwise = support::ston<bool>(args.at(0));
- break;
- default:
- crop(filename, args.front(), color, padding, format, wordwise);
- std::cout << '\n' << separator;
- break;
- }
- args.pop_front();
- }
- }
- int main(int argc, char const* argv[]) try
- {
- process_arguments({argv, argv + argc});
- return 0;
- }
- catch(...)
- {
- if(errno) std::perror("Oh nooo!");
- throw;
- }
|