Last active
November 3, 2016 05:20
-
-
Save bigdavedev/868ee1ffffe66b8a8155b870449a5f19 to your computer and use it in GitHub Desktop.
GNU Core Utils cat in less than 100 lines of code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include <fstream> | |
#include <iomanip> | |
#include <iterator> | |
#include <regex> | |
#include <vector> | |
#include <unistd.h> | |
namespace { | |
bool show_numbers = false; | |
bool show_line_end = false; | |
bool show_tabs = false; | |
bool show_non_print = false; | |
bool squash_blank = false; | |
bool number_nonblank = false; | |
void cat(std::istream& stream) { | |
int blank_lines = 0; | |
for (std::string line{}; std::getline(stream, line);) { | |
if (squash_blank) { blank_lines = (line.empty() ? ++blank_lines : 0); } | |
if (number_nonblank && line.empty()) { | |
if (squash_blank && blank_lines == 1) { std::cout << (show_line_end ? "$" : "") << std::endl; continue; } | |
} | |
if (show_numbers) { | |
static int count = 0; | |
if (blank_lines <= 1 && !(number_nonblank && line.empty())) { | |
std::cout << std::right << std::setw(6) << ++count << std::resetiosflags(std::ios_base::basefield) << "\t"; | |
} | |
} | |
if (show_tabs) { line = std::regex_replace(line, std::regex{"\t"}, "^I"); } | |
if (show_line_end) { line.append("$"); } | |
if (show_non_print) { | |
auto const regex = std::regex{ "[^\t-~]" }; | |
auto start = std::sregex_iterator{ std::begin(line), std::end(line), regex }; auto end = std::sregex_iterator{}; | |
for (auto i = start; i != end; ++i) { std::cout << ((*i).str(0)) << std::endl; } | |
} | |
if (blank_lines <= 1) { std::cout << line << std::endl; } | |
} | |
} | |
} | |
int main(int argc, char* argv[]) { | |
for(int opt = 0; opt != -1; opt = getopt(argc, argv, "ubsEhnvT")) { | |
switch (opt) { | |
case 'u': break; | |
case 's': squash_blank = true; break; | |
case 'b': number_nonblank = true; show_numbers = true; break; | |
case 'n': show_numbers = true; break; | |
case 'E': show_line_end = true; break; | |
case 'v': show_non_print = true; break; | |
case 'T': show_tabs = true; break; | |
case 'h': std::cout << "Usage: cat [OPTION]... [FILE]...\nConcatenate FILE(s) to standard output.\n\n\ | |
With no FILE, or when FILE is -, read standard input.\n\n -A, --show-all equivalent to -vET\n\ | |
-b, --number-nonblank number nonempty output lines, overrides -n\n -e equivalent to -vE\n\ | |
-E, --show-ends display $ at end of each line\n -n, --number number all output lines\n\ | |
-s, --squeeze-blank suppress repeated empty output lines\n -t equivalent to -vT\n\ | |
-T, --show-tabs display TAB characters as ^I\n -u (ignored)\n\ | |
-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB\n --help display this help and exit\n\ | |
--version output version information and exit\n\nExamples:\n\ | |
cat f - g Output f\'s contents, then standard input, then g\'s contents.\n cat Copy standard input to standard output.\n\n\ | |
GNU coreutils online help: <http://www.gnu.org/software/coreutils/>\nFull documentation at: <http://www.gnu.org/software/coreutils/cat>\n\ | |
or available locally via: info \'(coreutils) cat invocation\'\n"; return 0; | |
break; | |
} | |
} | |
if (optind == argc) { cat(std::cin); } | |
for (int index = optind; index < argc; ++index) { | |
if (auto filename = std::string{ argv[index] }; filename == "-") { cat(std::cin); } | |
else { auto file = std::ifstream{ argv[index] }; cat(file); } | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment