--- a/nbproject/configurations.xml Sat Jun 06 01:50:42 2020 +0200
+++ b/nbproject/configurations.xml Wed Sep 23 11:23:12 2020 +0200
@@ -42,6 +42,7 @@
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df root="." name="0">
<df name="src">
+ <in>CSVCommand.cpp</in>
<in>relpipe-in-csv.cpp</in>
</df>
</df>
@@ -91,7 +92,11 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
- <item path="src/relpipe-in-csv.cpp" ex="false" tool="1" flavor2="0">
+ <item path="src/CSVCommand.cpp" ex="false" tool="1" flavor2="0">
+ <ccTool flags="0">
+ </ccTool>
+ </item>
+ <item path="src/relpipe-in-csv.cpp" ex="false" tool="1" flavor2="11">
<ccTool flags="0">
</ccTool>
</item>
--- a/nbproject/project.xml Sat Jun 06 01:50:42 2020 +0200
+++ b/nbproject/project.xml Wed Sep 23 11:23:12 2020 +0200
@@ -6,7 +6,7 @@
<name>relpipe-in-csv.cpp</name>
<c-extensions/>
<cpp-extensions>cpp</cpp-extensions>
- <header-extensions/>
+ <header-extensions>h</header-extensions>
<sourceEncoding>UTF-8</sourceEncoding>
<make-dep-projects/>
<sourceRootList>
--- a/src/CMakeLists.txt Sat Jun 06 01:50:42 2020 +0200
+++ b/src/CMakeLists.txt Wed Sep 23 11:23:12 2020 +0200
@@ -29,6 +29,7 @@
# Executable output:
add_executable(
${EXECUTABLE_FILE}
+ CSVCommand.cpp
relpipe-in-csv.cpp
)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CSVCommand.cpp Wed Sep 23 11:23:12 2020 +0200
@@ -0,0 +1,146 @@
+/**
+ * Relational pipes
+ * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <cstdlib>
+#include <vector>
+#include <memory>
+#include <regex>
+#include <algorithm>
+#include <unistd.h>
+
+#include <relpipe/writer/RelationalWriter.h>
+#include <relpipe/writer/RelpipeWriterException.h>
+#include <relpipe/writer/AttributeMetadata.h>
+#include <relpipe/writer/Factory.h>
+#include <relpipe/writer/TypeId.h>
+
+#include <relpipe/cli/CLI.h>
+
+#include "CSVCommand.h"
+
+using namespace std;
+using namespace relpipe::cli;
+using namespace relpipe::writer;
+
+namespace relpipe {
+namespace in {
+namespace csv {
+
+bool CSVCommand::readValue(std::istream& input, std::stringstream& currentValue, bool& lastInRecord) {
+ lastInRecord = false;
+ char ch;
+ input.get(ch);
+ if (ch == '"') {
+ while (input.get(ch)) {
+ if (ch == '"') {
+ input.get(ch);
+ if (ch == '"') {
+ currentValue << ch;
+ } else {
+ if (ch == '\r') input.get(ch);
+ if (ch == '\n') lastInRecord = true;
+ else if (ch != ',') throw RelpipeWriterException(L"Unexpected character (should be „\\n“ or „,“)");
+ return true;
+ }
+ } else {
+ currentValue << ch;
+ }
+ }
+ } else if (ch == ',') {
+ return true;
+ } else if (ch == '\n') {
+ lastInRecord = true;
+ return true;
+ } else if (ch == '\r') {
+ input.get(ch);
+ if (ch == '\n') {
+ lastInRecord = true;
+ return true;
+ } else {
+ throw RelpipeWriterException(L"Crazy carriage stuck during journey");
+ }
+ } else {
+ for (currentValue << ch; input.get(ch);) {
+ switch (ch) {
+ case ',': return true;
+ case '\r': break;
+ case '\n':
+ lastInRecord = true;
+ return true;
+ default: currentValue << ch;
+ }
+ }
+ }
+ return false;
+}
+
+void CSVCommand::processDataStream(std::ostream& output, std::istream& input, const vector<relpipe::writer::string_t>& args) {
+ wstring_convert < codecvt_utf8<wchar_t>> convertor; // UTF-8 is required for CSV
+ std::shared_ptr<RelationalWriter> writer(Factory::create(output));
+ vector<AttributeMetadata> metadata;
+ bool headerDone = false;
+ bool lastInRecord = false;
+ stringstream currentValue;
+
+
+ while (readValue(input, currentValue, lastInRecord) && input.good()) {
+ if (headerDone) {
+ writer->writeAttribute(convertor.from_bytes(currentValue.str()));
+ } else {
+ AttributeMetadata am;
+ am.attributeName = convertor.from_bytes(currentValue.str());
+ am.typeId = TypeId::STRING;
+ metadata.push_back(am);
+ if (lastInRecord) {
+
+ /*
+ * Usage (simple syntax):
+ * relpipe-in-csv → default relation name, attribute names on the first line, all types are string
+ * relpipe-in-csv my_relation → custom relation name
+ * relpipe-in-csv my_relation a b c → custom relation name, custom attribute names (a,b,c), first line contains data
+ * relpipe-in-csv my_relation a integer b string c boolean → custom relation name, custom attribute names (a,b,c), custom types (integer,string,boolean), first line contains data
+ */
+
+ vector<string_t> firstLine;
+ if (args.size() == (1 + metadata.size())) {
+ for (int i = 0; i < metadata.size(); i++) {
+ firstLine.push_back(metadata[i].attributeName);
+ metadata[i].attributeName = args[1 + i];
+ }
+ } else if (args.size() == (1 + 2 * metadata.size())) {
+ for (int i = 0; i < metadata.size(); i++) {
+ firstLine.push_back(metadata[i].attributeName);
+ metadata[i].attributeName = args[1 + i * 2];
+ metadata[i].typeId = writer->toTypeId(args[1 + i * 2 + 1]);
+ }
+ }
+
+ headerDone = true;
+ writer->startRelation(args.size() > 0 ? args[0] : L"csv", metadata, true);
+ if (firstLine.size()) {
+ for (string_t value : firstLine) writer->writeAttribute(value);
+ }
+ }
+ }
+
+ currentValue.str("");
+ currentValue.clear();
+ }
+}
+
+}
+}
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CSVCommand.h Wed Sep 23 11:23:12 2020 +0200
@@ -0,0 +1,39 @@
+/**
+ * Relational pipes
+ * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <relpipe/writer/TypeId.h>
+
+namespace relpipe {
+namespace in {
+namespace csv {
+
+class CSVCommand {
+private:
+ bool readValue(std::istream& input, std::stringstream& currentValue, bool& lastInRecord);
+public:
+ void processDataStream(std::ostream &output, std::istream& input, const vector<relpipe::writer::string_t>& args);
+
+};
+
+}
+}
+}
--- a/src/relpipe-in-csv.cpp Sat Jun 06 01:50:42 2020 +0200
+++ b/src/relpipe-in-csv.cpp Wed Sep 23 11:23:12 2020 +0200
@@ -29,111 +29,12 @@
#include <relpipe/cli/CLI.h>
+#include "CSVCommand.h"
+
using namespace std;
using namespace relpipe::cli;
using namespace relpipe::writer;
-
-bool readValue(istream& input, stringstream& currentValue, bool& lastInRecord) {
- lastInRecord = false;
- char ch;
- input.get(ch);
- if (ch == '"') {
- while (input.get(ch)) {
- if (ch == '"') {
- input.get(ch);
- if (ch == '"') {
- currentValue << ch;
- } else {
- if (ch == '\r') input.get(ch);
- if (ch == '\n') lastInRecord = true;
- else if (ch != ',') throw RelpipeWriterException(L"Unexpected character (should be „\\n“ or „,“)");
- return true;
- }
- } else {
- currentValue << ch;
- }
- }
- } else if (ch == ',') {
- return true;
- } else if (ch == '\n') {
- lastInRecord = true;
- return true;
- } else if (ch == '\r') {
- input.get(ch);
- if (ch == '\n') {
- lastInRecord = true;
- return true;
- } else {
- throw RelpipeWriterException(L"Crazy carriage stuck during journey");
- }
- } else {
- for (currentValue << ch; input.get(ch);) {
- switch (ch) {
- case ',': return true;
- case '\r': break;
- case '\n':
- lastInRecord = true;
- return true;
- default: currentValue << ch;
- }
- }
- }
- return false;
-}
-
-void processDataStream(ostream &output, istream& input, const vector<string_t>& args) {
- wstring_convert < codecvt_utf8<wchar_t>> convertor; // UTF-8 is required for CSV
- std::shared_ptr<RelationalWriter> writer(Factory::create(output));
- vector<AttributeMetadata> metadata;
- bool headerDone = false;
- bool lastInRecord = false;
- stringstream currentValue;
-
-
- while (readValue(input, currentValue, lastInRecord) && input.good()) {
- if (headerDone) {
- writer->writeAttribute(convertor.from_bytes(currentValue.str()));
- } else {
- AttributeMetadata am;
- am.attributeName = convertor.from_bytes(currentValue.str());
- am.typeId = TypeId::STRING;
- metadata.push_back(am);
- if (lastInRecord) {
-
- /*
- * Usage (simple syntax):
- * relpipe-in-csv → default relation name, attribute names on the first line, all types are string
- * relpipe-in-csv my_relation → custom relation name
- * relpipe-in-csv my_relation a b c → custom relation name, custom attribute names (a,b,c), first line contains data
- * relpipe-in-csv my_relation a integer b string c boolean → custom relation name, custom attribute names (a,b,c), custom types (integer,string,boolean), first line contains data
- */
-
- vector<string_t> firstLine;
- if (args.size() == (1 + metadata.size())) {
- for (int i = 0; i < metadata.size(); i++) {
- firstLine.push_back(metadata[i].attributeName);
- metadata[i].attributeName = args[1 + i];
- }
- } else if (args.size() == (1 + 2 * metadata.size())) {
- for (int i = 0; i < metadata.size(); i++) {
- firstLine.push_back(metadata[i].attributeName);
- metadata[i].attributeName = args[1 + i * 2];
- metadata[i].typeId = writer->toTypeId(args[1 + i * 2 + 1]);
- }
- }
-
- headerDone = true;
- writer->startRelation(args.size() > 0 ? args[0] : L"csv", metadata, true);
- if (firstLine.size()) {
- for (string_t value : firstLine) writer->writeAttribute(value);
- }
- }
- }
-
- currentValue.str("");
- currentValue.clear();
- }
-}
+using namespace relpipe::in::csv;
int main(int argc, char** argv) {
setlocale(LC_ALL, "");
@@ -143,7 +44,8 @@
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
try {
- processDataStream(cout, cin, cli.arguments());
+ CSVCommand command;
+ command.processDataStream(cout, cin, cli.arguments());
resultCode = CLI::EXIT_CODE_SUCCESS;
} catch (RelpipeWriterException e) {
fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str());