crop.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #include <deque>
  2. #include <iostream>
  3. #include <iomanip>
  4. #include "simple/file.hpp"
  5. #include "simple/support/enum.hpp"
  6. #include "simple/support/misc.hpp"
  7. #include "simple/support/algorithm.hpp"
  8. #include "simple/support/iterator/match.hpp"
  9. using namespace simple;
  10. using namespace std::literals;
  11. enum class Options
  12. {
  13. Padding,
  14. Color,
  15. Source,
  16. Format,
  17. Separator,
  18. Wordwise,
  19. Linewise,
  20. Invalid
  21. };
  22. using Option = support::mapped_enum<Options, Options::Invalid, 2>;
  23. template <> Option::guts::map_type Option::guts::map
  24. {{
  25. { "-p"s, "--padding"s },
  26. { "-c"s, "--color"s },
  27. { "-i"s, "--source"s },
  28. { "-f"s, "--format"s },
  29. { "-s"s, "--separator"s },
  30. { "-w"s, "--words"s },
  31. { "-l"s, "--lines"s },
  32. }};
  33. enum class Formats
  34. {
  35. PlainText, OneLine, Hex,
  36. Invalid
  37. };
  38. using Format = support::mapped_enum<Formats, Formats::Invalid>;
  39. template <> Format::guts::map_type Format::guts::map
  40. {{
  41. { "plain"s }, { "one-line"s }, { "hex"s },
  42. }};
  43. enum class Colors
  44. {
  45. Black, Red, Green, Yellow,
  46. Blue, Magenta, Cyan, White,
  47. Invalid
  48. };
  49. using Color = support::mapped_enum<Colors, Colors::Invalid>;
  50. template <> Color::guts::map_type Color::guts::map
  51. {{
  52. { "black"s }, { "red"s }, { "green"s }, { "yellow"s },
  53. { "blue"s }, { "magenta"s }, { "cyan"s }, { "white"s }
  54. }};
  55. using buffer = std::vector<unsigned char>;
  56. using const_range = support::range<buffer::const_iterator>;
  57. template <typename Range>
  58. void print(Range range, Format format, std::string joiner, Color color = Colors::Invalid)
  59. {
  60. assert(range.valid());
  61. auto cout_flags = std::cout.flags();
  62. std::cout << std::hex;
  63. if(Colors::Invalid != color)
  64. std::cout << "\33[4" << char('0' + (int)Colors(color)) << 'm';
  65. switch(format)
  66. {
  67. case Formats::Hex:
  68. if constexpr (std::is_same_v<Range, const_range>)
  69. for(auto&& c : range)
  70. {
  71. if(c <= 0xf)
  72. std::cout << '0';
  73. std::cout << +c;
  74. }
  75. else std::cerr << "ERROR: Hex format not supported for wordwise/linewise crop." << '\n';
  76. break;
  77. case Formats::OneLine:
  78. if constexpr (std::is_same_v<Range, const_range>)
  79. for(auto&& c : range)
  80. {
  81. auto cc = '\n' == c ? 'n' : '\r' == c ? 'r' : c;
  82. if(cc != c)
  83. std::cout << "\33[7m" << cc << "\33[27m";
  84. else
  85. std::cout << c;
  86. }
  87. else std::cerr << "ERROR: One line format not supported for wordwise/linewise crop." << '\n';
  88. break;
  89. default:
  90. for(auto&& c : range)
  91. {
  92. std::cout << c;
  93. if constexpr (not std::is_same_v<Range, const_range>)
  94. std::cout << joiner;
  95. }
  96. }
  97. if(Colors::Invalid != color)
  98. std::cout << "\33[0m";
  99. std::cout.flags(cout_flags);
  100. }
  101. auto split(const buffer& b, const std::string& separator)
  102. {
  103. std::vector<std::string> words;
  104. if(separator == "")
  105. support::split(b, support::match_iterator(support::is_space), std::back_inserter(words));
  106. else
  107. support::split(b, separator, std::back_inserter(words));
  108. return words;
  109. }
  110. void crop(const std::string& filename, const std::string& range, Color color, int padding, Format format, const char* separator)
  111. {
  112. auto r = support::storn<int64_t>(range);
  113. const auto source = file::dump<buffer>(file::bropex(filename));
  114. auto do_print = [r, padding, format, color, joiner = !separator || separator == ""s ? " "s : separator](const auto& source)
  115. {
  116. print(support::get_iterator_range<int64_t>(source, {r.lower()-padding , r.lower()}), format, joiner);
  117. print(support::get_iterator_range<int64_t>(source, r), format, joiner, color);
  118. print(support::get_iterator_range<int64_t>(source, {r.upper(), r.upper()+padding}), format, joiner);
  119. };
  120. if(separator)
  121. do_print(split(source, separator));
  122. else
  123. do_print(source);
  124. }
  125. void process_arguments(std::deque<std::string> args)
  126. {
  127. std::string filename;
  128. std::string separator;
  129. Color color;
  130. Format format;
  131. int padding = 0;
  132. const char* in_separator = nullptr;
  133. args.pop_front();
  134. while(!args.empty())
  135. {
  136. switch(Option(args.front()))
  137. {
  138. case Options::Padding:
  139. args.pop_front();
  140. padding = support::ston<int>(args.at(0));
  141. if(padding < 0)
  142. throw std::out_of_range("negative padding");
  143. break;
  144. case Options::Color:
  145. args.pop_front();
  146. color = Color(args.at(0));
  147. break;
  148. case Options::Source:
  149. args.pop_front();
  150. filename = args.at(0);
  151. break;
  152. case Options::Separator:
  153. args.pop_front();
  154. separator = args.at(0) + '\n';
  155. break;
  156. case Options::Format:
  157. args.pop_front();
  158. format = Format(args.at(0));
  159. break;
  160. case Options::Wordwise: in_separator = ""; break;
  161. case Options::Linewise: in_separator = "\n"; break;
  162. default:
  163. crop(filename, args.front(), color, padding, format, in_separator);
  164. std::cout << '\n' << separator;
  165. break;
  166. }
  167. args.pop_front();
  168. }
  169. }
  170. int main(int argc, char const* argv[]) try
  171. {
  172. process_arguments({argv, argv + argc});
  173. return 0;
  174. }
  175. catch(...)
  176. {
  177. if(errno) std::perror("Oh nooo!");
  178. throw;
  179. }