LDMX Software
GeneralCSVLoader.cxx
1#include "Conditions/GeneralCSVLoader.h"
2
3#include <string.h>
4#include <wordexp.h>
5
6#include <fstream>
7#include <iostream>
8
9#include "Framework/Exception/Exception.h"
10#include "boost/tokenizer.hpp"
11
12namespace conditions {
13
14const std::string& GeneralCSVLoader::get(const std::string& colname,
15 bool ignore_case) const {
16 size_t i;
17 for (i = 0; i < colNames_.size(); i++) {
18 if (ignore_case && !strcasecmp(colNames_[i].c_str(), colname.c_str()))
19 break;
20 if (colNames_[i] == colname) break;
21 }
22 if (i == colNames_.size()) {
23 EXCEPTION_RAISE("CSVNoSuchColumn",
24 "No such column '" + colname + "' reading CSV");
25 }
26 return rowData_[i];
27}
28
29int GeneralCSVLoader::getInteger(const std::string& colname,
30 bool ignore_case) const {
31 return atoi(get(colname, ignore_case).c_str());
32}
33
35 do {
36 std::string line = getNextLine();
37 if (line.empty()) return false;
38 // it's a comment!
39 if (line[0] == '#') continue;
40 // split into pieces
41 std::vector<std::string> line_split;
42 // explicitly erase trailing white space
43 line.erase(std::find_if(line.rbegin(), line.rend(),
44 [](unsigned char c) { return !std::isspace(c); })
45 .base(),
46 line.end());
47 boost::tokenizer<boost::escaped_list_separator<char>> tok(line);
48 for (auto chunk : tok) {
49 line_split.push_back(chunk);
50 }
51 if (colNames_.empty()) {
52 colNames_.swap(line_split);
53 continue;
54 }
55 if (line_split.size() == colNames_.size()) {
56 rowData_.swap(line_split);
57 } else {
58 EXCEPTION_RAISE("CSVLineMismatch",
59 "Reading CSV found line with " +
60 std::to_string(line_split.size()) + " in CSV with " +
61 std::to_string(colNames_.size()) + " columns");
62 }
63
64 return true;
65 } while (true);
66}
67
68StringCSVLoader::StringCSVLoader(const std::string& source,
69 const std::string lineseparators)
70 : source_{source}, linesep_{lineseparators}, rowBegin_{0}, rowEnd_{0} {
72}
73
75 std::string retval;
76 if (rowBegin_ != rowEnd_) {
77 if (rowEnd_ == std::string::npos) {
78 retval = source_.substr(rowBegin_, rowEnd_);
79 } else {
80 retval = source_.substr(rowBegin_, rowEnd_ - rowBegin_);
81 }
82 }
83 // now we look for the follow on.
84 // find the first non-end-of-line character
85 rowBegin_ = source_.find_first_not_of(linesep_, rowEnd_);
86 if (rowBegin_ != std::string::npos) {
87 rowEnd_ = source_.find_first_of(linesep_, rowBegin_);
88 } else {
89 rowEnd_ = std::string::npos;
90 }
91 return retval;
92}
93
94StreamCSVLoader::StreamCSVLoader(const std::string& filename)
95 : source_{0}, ownStream_{true} {
96 std::string expanded_fname = filename;
97 wordexp_t p;
98
99 if (wordexp(filename.c_str(), &p, 0)) {
100 EXCEPTION_RAISE("StreamCSVFileNotFound",
101 "Error expanding '" + filename + "'");
102 }
103
104 if (!p.we_wordc) {
105 EXCEPTION_RAISE("StreamCSVFileNotFound",
106 "No file matching '" + filename + "' found");
107 }
108
109 if (p.we_wordc != 1) {
110 int nfound = p.we_wordc;
111 wordfree(&p);
112 EXCEPTION_RAISE("StreamCSVFileNotFound",
113 "Multiple files (" + std::to_string(nfound) +
114 ") matching '" + filename + "' found");
115 }
116
117 expanded_fname = p.we_wordv[0];
118 wordfree(&p);
119
120 source_ = new std::ifstream(expanded_fname);
121 if (source_->fail()) {
122 EXCEPTION_RAISE("StreamCSVFileNotFound",
123 "Unable to open '" + expanded_fname + "'");
124 }
125}
126
128 : source_{&stream}, ownStream_{false} {}
129
134
136 // if no stream, no line...
137 if (!source_) return "";
138
139 do {
140 line_.clear();
141 std::getline(*source_, line_);
142 if (line_.empty() && source_->eof()) return "";
143 } while (line_.empty()); // skip blank lines
144
145 return line_;
146}
147
148} // namespace conditions
bool nextRow()
Advance to next row if possible.
const std::string & get(const std::string &colname, bool ignore_case=true) const
Get the value for the given column in the current row.
int getInteger(const std::string &colname, bool ignore_case=true) const
Get the value for the given column in the current row as an integer.
virtual std::string getNextLine()=0
Get the next line, returning an empty string when there is no further data.
std::vector< std::string > rowData_
The row data.
std::vector< std::string > colNames_
The column names.
virtual ~StreamCSVLoader()
Clean-up the stream if we own it.
virtual std::string getNextLine()
Get the next line, returning an empty string when there is no further data.
StreamCSVLoader(const std::string &filename)
Constructor a loader from the provided file name.
std::string line_
Line buffer.
std::istream * source_
The stream.
const std::string & source_
The original string.
std::string::size_type rowBegin_
The current start and end pointers.
StringCSVLoader(const std::string &source, const std::string lineseparators="\n")
Constructor.
const std::string linesep_
The separators.
virtual std::string getNextLine()
Get the next line, returning an empty string when there is no further data.