Skip to content

Instantly share code, notes, and snippets.

@bigdavedev
Last active November 3, 2016 05:20
Show Gist options
  • Save bigdavedev/868ee1ffffe66b8a8155b870449a5f19 to your computer and use it in GitHub Desktop.
Save bigdavedev/868ee1ffffe66b8a8155b870449a5f19 to your computer and use it in GitHub Desktop.
GNU Core Utils cat in less than 100 lines of code
#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