14 * |
14 * |
15 * You should have received a copy of the GNU General Public License |
15 * You should have received a copy of the GNU General Public License |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 */ |
17 */ |
18 #include <cstdlib> |
18 #include <cstdlib> |
19 #include <fstream> |
19 #include <vector> |
20 #include <memory> |
20 #include <memory> |
21 #include <regex> |
21 #include <regex> |
22 #include <algorithm> |
22 #include <algorithm> |
23 #include <unistd.h> |
23 #include <unistd.h> |
24 |
24 |
25 #include <relpipe/writer/RelationalWriter.h> |
25 #include <relpipe/writer/RelationalWriter.h> |
26 #include <relpipe/writer/RelpipeWriterException.h> |
26 #include <relpipe/writer/RelpipeWriterException.h> |
|
27 #include <relpipe/writer/AttributeMetadata.h> |
27 #include <relpipe/writer/Factory.h> |
28 #include <relpipe/writer/Factory.h> |
28 #include <relpipe/writer/TypeId.h> |
29 #include <relpipe/writer/TypeId.h> |
29 |
30 |
30 #include <relpipe/cli/CLI.h> |
31 #include <relpipe/cli/CLI.h> |
31 |
32 |
32 using namespace std; |
33 using namespace std; |
33 using namespace relpipe::cli; |
34 using namespace relpipe::cli; |
34 using namespace relpipe::writer; |
35 using namespace relpipe::writer; |
35 |
36 |
36 /** |
37 bool readValue(istream& input, stringstream& currentValue, bool& lastInRecord) { |
37 * see https://hg.frantovo.cz/sql-api/file/tip/prototyp/prototyp.sql#l49 |
38 lastInRecord = false; |
38 */ |
39 char ch; |
39 void processDataStream(ostream &output, istream* input) { |
40 input.get(ch); |
|
41 if (ch == '"') { |
|
42 while (input.get(ch)) { |
|
43 if (ch == '"') { |
|
44 input.get(ch); |
|
45 if (ch == '"') { |
|
46 currentValue << ch; |
|
47 } else { |
|
48 if (ch == '\r') input.get(ch); |
|
49 if (ch == '\n') lastInRecord = true; |
|
50 else if (ch != ',') throw RelpipeWriterException(L"Unexpected character (should be ā\\nā or ā,ā)"); |
|
51 return true; |
|
52 } |
|
53 } else { |
|
54 currentValue << ch; |
|
55 } |
|
56 } |
|
57 } else if (ch == ',') { |
|
58 return true; |
|
59 } else if (ch == '\n') { |
|
60 lastInRecord = true; |
|
61 return true; |
|
62 } else if (ch == '\r') { |
|
63 currentValue << ch; |
|
64 if (ch == '\n') { |
|
65 lastInRecord = true; |
|
66 return true; |
|
67 } else { |
|
68 throw RelpipeWriterException(L"Crazy carriage stuck during journey"); |
|
69 } |
|
70 } else { |
|
71 for (currentValue << ch; input.get(ch);) { |
|
72 switch (ch) { |
|
73 case ',': return true; |
|
74 case '\r': break; |
|
75 case '\n': |
|
76 lastInRecord = true; |
|
77 return true; |
|
78 default: currentValue << ch; |
|
79 } |
|
80 } |
|
81 } |
|
82 return false; |
|
83 } |
40 |
84 |
41 for (char ch; input->get(ch);) { |
85 void processDataStream(ostream &output, istream& input) { |
42 output << "ch: " << ch << endl; |
86 wstring_convert < codecvt_utf8<wchar_t>> convertor; // UTF-8 is required for CSV |
|
87 std::shared_ptr<RelationalWriter> writer(Factory::create(output)); |
|
88 vector<AttributeMetadata> metadata; |
|
89 bool headerDone = false; |
|
90 bool lastInRecord = false; |
|
91 stringstream currentValue; |
|
92 |
|
93 |
|
94 while (readValue(input, currentValue, lastInRecord) && input.good()) { |
|
95 if (headerDone) { |
|
96 writer->writeAttribute(convertor.from_bytes(currentValue.str())); |
|
97 } else { |
|
98 AttributeMetadata am; |
|
99 am.attributeName = convertor.from_bytes(currentValue.str()); |
|
100 am.typeId = TypeId::STRING; // TODO: support also other types passed as CLI parameters |
|
101 metadata.push_back(am); |
|
102 if (lastInRecord) { |
|
103 headerDone = true; |
|
104 writer->startRelation(L"csv", metadata, true); // TODO: support also custom relation name passed as CLI parameter |
|
105 } |
|
106 } |
|
107 |
|
108 currentValue.str(""); |
|
109 currentValue.clear(); |
43 } |
110 } |
44 } |
111 } |
45 |
112 |
46 int main(int argc, char** argv) { |
113 int main(int argc, char** argv) { |
47 setlocale(LC_ALL, ""); |
114 setlocale(LC_ALL, ""); |
49 CLI cli(argc, argv); |
116 CLI cli(argc, argv); |
50 |
117 |
51 int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; |
118 int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; |
52 |
119 |
53 try { |
120 try { |
54 processDataStream(cout, &cin); |
121 processDataStream(cout, cin); |
55 resultCode = CLI::EXIT_CODE_SUCCESS; |
122 resultCode = CLI::EXIT_CODE_SUCCESS; |
56 } catch (RelpipeWriterException e) { |
123 } catch (RelpipeWriterException e) { |
57 fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str()); |
124 fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str()); |
58 fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); |
125 fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); |
59 resultCode = CLI::EXIT_CODE_DATA_ERROR; |
126 resultCode = CLI::EXIT_CODE_DATA_ERROR; |