70int Run(std::size_t row_limit, std::istream& input, std::ostream& output,
72 LoggerT& logger,
Result& result) {
74 std::unique_ptr<std::istringstream> buffered_stdin;
75 std::istream* parse_input = &input;
77 std::ostringstream
raw;
79 buffered_stdin = std::make_unique<std::istringstream>(
raw.str());
80 parse_input = buffered_stdin.get();
81 logger.Verbose(
"Buffered stdin for CSV parsing.");
84 csv::CSVFormat format;
88 format.delimiter({
',',
'|',
'\t',
';',
'^' });
90 format.quote(
'"').header_row(0);
91 std::unique_ptr<csv::CSVReader> owned_reader;
93 owned_reader = std::make_unique<csv::CSVReader>(
97 owned_reader = std::make_unique<csv::CSVReader>(*parse_input, format);
99 csv::CSVReader& reader = *owned_reader;
101 const auto headers = reader.get_col_names();
102 if (headers.empty()) {
103 logger.Error(
"Input appears to have no header row.");
107 std::vector<std::vector<std::string>> rows;
108 rows.reserve(row_limit);
110 for (
auto& row : reader) {
111 if (rows.size() >= row_limit) {
115 std::vector<std::string> values;
116 values.reserve(headers.size());
118 for (std::size_t i = 0; i < headers.size(); ++i) {
119 if (i < row.size()) {
120 auto cell = row[i].get<std::string>();
124 values.emplace_back(
"");
128 rows.push_back(std::move(values));
132 std::vector<std::size_t> widths(headers.size(), 0);
133 constexpr std::size_t kMaxColumnWidth = 40;
135 for (std::size_t i = 0; i < headers.size(); ++i) {
136 widths[i] = std::min(headers[i].size(), kMaxColumnWidth);
139 for (
const auto& values : rows) {
140 for (std::size_t i = 0; i < values.size(); ++i) {
141 widths[i] = std::max(widths[i], std::min(values[i].size(), kMaxColumnWidth));
148 for (
const auto& values : rows) {
153 logger.Verbose(
"Displayed " + std::to_string(rows.size()) +
" row(s) plus header.");
155 }
catch (
const std::exception& ex) {
156 logger.Error(std::string(
"Failed to parse CSV for head: ") + ex.what());