change CLI interface: options: --relation --attribute --record --records --records-from-stdin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bash-completion.sh Tue Sep 22 21:00:30 2020 +0200
@@ -0,0 +1,46 @@
+# Relational pipes
+# Copyright © 2019 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/>.
+
+_relpipe_in_cli_completion() {
+ local w0 w1 w2 w3
+
+ COMPREPLY=()
+ w0=${COMP_WORDS[COMP_CWORD]}
+ w1=${COMP_WORDS[COMP_CWORD-1]}
+ w2=${COMP_WORDS[COMP_CWORD-2]}
+ w3=${COMP_WORDS[COMP_CWORD-3]}
+
+ DATA_TYPE=(
+ "string"
+ "integer"
+ "boolean"
+ )
+
+ if [[ "$w1" == "--relation" && "x$w0" == "x" ]]; then COMPREPLY=("''")
+ elif [[ "$w1" == "--attribute" && "x$w0" == "x" ]]; then COMPREPLY=("''")
+ elif [[ "$w2" == "--attribute" ]]; then COMPREPLY=($(compgen -W "${DATA_TYPE[*]}" -- "$w0"))
+ else
+ OPTIONS=(
+ "--relation"
+ "--attribute"
+ "--record"
+ "--records"
+ "--records-from-stdin"
+ )
+ COMPREPLY=($(compgen -W "${OPTIONS[*]}" -- "$w0"))
+ fi
+}
+
+complete -F _relpipe_in_cli_completion relpipe-in-cli
--- a/nbproject/configurations.xml Tue Sep 22 17:42:19 2020 +0200
+++ b/nbproject/configurations.xml Tue Sep 22 21:00:30 2020 +0200
@@ -42,6 +42,7 @@
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df root="." name="0">
<df name="src">
+ <in>CLICommand.h</in>
<in>relpipe-in-cli.cpp</in>
</df>
</df>
@@ -90,6 +91,8 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
+ <item path="src/CLICommand.h" ex="false" tool="3" flavor2="0">
+ </item>
<item path="src/relpipe-in-cli.cpp" ex="false" tool="1" flavor2="0">
<ccTool flags="0">
</ccTool>
@@ -124,6 +127,8 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
+ <item path="src/CLICommand.h" ex="false" tool="3" flavor2="0">
+ </item>
</conf>
</confs>
</configurationDescriptor>
--- a/src/ArgumentsCommand.h Tue Sep 22 17:42:19 2020 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/**
- * 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 <cstdlib>
-#include <iostream>
-#include <string>
-#include <vector>
-#include <algorithm>
-
-#include <relpipe/writer/typedefs.h>
-#include <relpipe/writer/AttributeMetadata.h>
-
-#include "Command.h"
-
-namespace relpipe {
-namespace in {
-namespace cli {
-
-class ArgumentsCommand : public Command {
-public:
-
- void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector<relpipe::writer::string_t>& arguments) override {
- using namespace relpipe::writer;
-
- size_t i = 0;
- string_t relationName = arguments[i++];
- integer_t attributeCount = std::stol(arguments[i++]); // TODO: use integer data type's method? + unsigned type
- boolean_t writeHeader = true; // TODO: add option for header omitting
-
- // TODO: check argument count
-
- std::shared_ptr<RelationalWriter> writer(Factory::create(output));
-
- std::vector<AttributeMetadata> attributes(attributeCount);
-
- for (size_t j = 0; j < attributeCount; j++) {
- string_t attributeName = arguments[i++];
- TypeId attributeType = writer->toTypeId(arguments[i++]);
- attributes[j] = {attributeName, attributeType};
- }
-
- writer->startRelation(relationName, attributes, writeHeader);
-
- for (; i < arguments.size(); i++) {
- writer->writeAttribute(arguments[i]);
- }
- }
-};
-
-}
-}
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CLICommand.h Tue Sep 22 21:00:30 2020 +0200
@@ -0,0 +1,74 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 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 <codecvt>
+#include <memory>
+#include <iostream>
+
+#include "Configuration.h"
+
+namespace relpipe {
+namespace in {
+namespace cli {
+
+class CLICommand {
+private:
+
+ std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings and use platform encoding as default
+
+ void processRelation(RelationConfiguration& configuration, std::shared_ptr<writer::RelationalWriter> writer) {
+ // Write header / metadata:
+ std::vector<relpipe::writer::AttributeMetadata> attributesMetadata;
+ for (AttributeRecipe ar : configuration.attributes) attributesMetadata.push_back({ar.name, ar.type});
+ writer->startRelation(configuration.relation, attributesMetadata, true);
+
+ // Write records from CLI:
+ for (auto value : configuration.values) writer->writeAttribute(value);
+
+ // Write records from STDIN:
+ if (configuration.valueStream) {
+ std::stringstream rawValue;
+ while (true) {
+ char ch = 0;
+ configuration.valueStream->get(ch);
+ if (ch == 0 && configuration.valueStream->good()) {
+ writer->writeAttribute(convertor.from_bytes(rawValue.str()));
+ rawValue.str("");
+ rawValue.clear();
+ } else if (configuration.valueStream->good()) {
+ rawValue << ch;
+ } else if (configuration.valueStream->eof()) {
+ return;
+ } else {
+ throw relpipe::cli::RelpipeCLIException(L"Error while reading values from the input stream.", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception
+ }
+ }
+ }
+
+ }
+
+public:
+
+ void process(Configuration& configuration, std::shared_ptr<writer::RelationalWriter> writer) {
+ for (RelationConfiguration& relationConfiguration : configuration.relationConfigurations) processRelation(relationConfiguration, writer);
+ }
+};
+
+}
+}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CLIParser.h Tue Sep 22 21:00:30 2020 +0200
@@ -0,0 +1,120 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 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 <vector>
+#include <iostream>
+
+#include <relpipe/writer/typedefs.h>
+#include <relpipe/cli/CLI.h>
+#include <relpipe/cli/RelpipeCLIException.h>
+
+#include "Configuration.h"
+
+namespace relpipe {
+namespace in {
+namespace cli {
+
+class CLIParser {
+private:
+
+ relpipe::writer::string_t readNext(const std::vector<relpipe::writer::string_t>& arguments, int& i) {
+ if (i < arguments.size()) return arguments[i++];
+ else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+ void readNextRecord(const std::vector<relpipe::writer::string_t>& arguments, int& i, RelationConfiguration& currentRelation) {
+ for (const auto& a : currentRelation.attributes) currentRelation.values.emplace_back(readNext(arguments, i));
+ }
+
+ void addRelation(Configuration& c, RelationConfiguration& currentRelation) {
+ if (currentRelation.relation.size()) {
+ c.relationConfigurations.push_back(currentRelation);
+ currentRelation = RelationConfiguration();
+ }
+ }
+
+ /**
+ * TODO: use a common method
+ */
+ bool parseBoolean(const relpipe::writer::string_t& value) {
+ if (value == L"true") return true;
+ else if (value == L"false") return false;
+ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse boolean value: " + value + L" (expecting true or false)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+ /**
+ * TODO: use a common method
+ */
+ relpipe::writer::TypeId parseTypeId(const relpipe::writer::string_t& value) {
+ using t = relpipe::writer::TypeId;
+ if (value == L"string") return t::STRING;
+ else if (value == L"integer") return t::INTEGER;
+ else if (value == L"boolean") return t::BOOLEAN;
+ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TypeId: " + value, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+public:
+
+ static const relpipe::writer::string_t OPTION_RELATION;
+ static const relpipe::writer::string_t OPTION_ATTRIBUTE;
+ static const relpipe::writer::string_t OPTION_RECORD;
+ static const relpipe::writer::string_t OPTION_RECORDS;
+ static const relpipe::writer::string_t OPTION_RECORDS_STDIN;
+
+ Configuration parse(const std::vector<relpipe::writer::string_t>& arguments) {
+ Configuration c;
+ RelationConfiguration currentRelation;
+
+ for (int i = 0; i < arguments.size();) {
+ relpipe::writer::string_t option = readNext(arguments, i);
+
+ if (option == OPTION_RELATION) {
+ addRelation(c, currentRelation); // previous relation
+ currentRelation.relation = readNext(arguments, i);
+ } else if (option == OPTION_ATTRIBUTE) {
+ AttributeRecipe attribute;
+ attribute.name = readNext(arguments, i);
+ attribute.type = parseTypeId(readNext(arguments, i));
+ currentRelation.attributes.push_back(attribute);
+ } else if (option == OPTION_RECORD) {
+ readNextRecord(arguments, i, currentRelation);
+ } else if (option == OPTION_RECORDS) {
+ while (i < arguments.size()) readNextRecord(arguments, i, currentRelation);
+ } else if (option == OPTION_RECORDS_STDIN) {
+ for (RelationConfiguration r : c.relationConfigurations) if (r.valueStream) throw relpipe::cli::RelpipeCLIException(L"Only one relation can read data from STDIN.", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ currentRelation.valueStream = &std::cin;
+ } else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+ addRelation(c, currentRelation); // last relation
+
+ return c;
+ }
+
+ virtual ~CLIParser() {
+ }
+};
+
+const relpipe::writer::string_t CLIParser::OPTION_RELATION = L"--relation";
+const relpipe::writer::string_t CLIParser::OPTION_ATTRIBUTE = L"--attribute";
+const relpipe::writer::string_t CLIParser::OPTION_RECORD = L"--record";
+const relpipe::writer::string_t CLIParser::OPTION_RECORDS = L"--records";
+const relpipe::writer::string_t CLIParser::OPTION_RECORDS_STDIN = L"--records-from-stdin";
+
+}
+}
+}
--- a/src/Command.h Tue Sep 22 17:42:19 2020 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/**
- * 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 <cstdlib>
-#include <iostream>
-#include <string>
-#include <vector>
-#include <algorithm>
-
-
-namespace relpipe {
-namespace in {
-namespace cli {
-
-class Command {
-public:
- virtual ~Command() = default;
-
- /**
- * Processes the inputs (stream + arguments) and generates output in the relational pipes format.
- *
- * @param input usually STDIN, may not be used if all data are passed as CLI arguments
- * @param output usually STDOUT, relational data is passed here
- * @param command command name, usualy not needed, may be significant if the same Command instance is used for several commands
- * @param arguments CLI arguments containing data or parameters (format is specific to each command)
- */
- virtual void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector<relpipe::writer::string_t> &arguments) = 0;
-
-};
-
-}
-}
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Configuration.h Tue Sep 22 21:00:30 2020 +0200
@@ -0,0 +1,62 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 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 <vector>
+#include <iostream>
+
+#include <relpipe/writer/typedefs.h>
+
+
+namespace relpipe {
+namespace in {
+namespace cli {
+
+class AttributeRecipe {
+public:
+
+ virtual ~AttributeRecipe() {
+ }
+
+ relpipe::writer::string_t name;
+ relpipe::writer::TypeId type;
+
+};
+
+class RelationConfiguration {
+public:
+
+ virtual ~RelationConfiguration() {
+ }
+
+ relpipe::writer::string_t relation;
+ std::vector<AttributeRecipe> attributes;
+ std::vector<relpipe::writer::string_t> values;
+ std::istream* valueStream = nullptr;
+};
+
+class Configuration {
+public:
+ std::vector<RelationConfiguration> relationConfigurations;
+
+ virtual ~Configuration() {
+ }
+};
+
+}
+}
+}
\ No newline at end of file
--- a/src/StdInCommand.h Tue Sep 22 17:42:19 2020 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/**
- * 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 <cstdlib>
-#include <iostream>
-#include <string>
-#include <vector>
-#include <algorithm>
-#include <string>
-#include <locale>
-
-#include <relpipe/writer/typedefs.h>
-#include <relpipe/writer/AttributeMetadata.h>
-#include <relpipe/cli/CLI.h>
-#include <relpipe/cli/RelpipeCLIException.h>
-
-#include "Command.h"
-
-namespace relpipe {
-namespace in {
-namespace cli {
-
-/**
- * TODO: consider code merge with ArgumentsCommand
- */
-class StdInCommand : public Command {
-private:
- relpipe::writer::boolean_t readStdIn;
- std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings.
-
- /**
- * Reads next value from arguments and (if no arguments left) from input
- * @param input
- * @param arguments
- * @param i current index in the arguments vector
- * @param required if true, exception is thrown when no data found
- * @return
- */
- relpipe::writer::string_t readNext(std::istream& input, const std::vector<relpipe::writer::string_t>& arguments, size_t& i, relpipe::writer::boolean_t required) {
- using namespace relpipe::writer;
- using namespace relpipe::cli;
-
- if (i < arguments.size()) {
- return arguments[i++];
- } else if (readStdIn) {
- std::stringstream value;
-
- while (true) {
- char ch;
- input.get(ch);
- if (ch == 0 || input.eof() || input.fail()) break;
- else value << ch;
- }
-
- if (required && value.str().empty()) throw RelpipeCLIException(L"Missing value on STDIN.", CLI::EXIT_CODE_BAD_SYNTAX);
-
- return convertor.from_bytes(value.str());
- } else {
- if (required) throw RelpipeCLIException(L"Missing value on CLI.", CLI::EXIT_CODE_BAD_SYNTAX);
- return L"";
- }
- }
-
-
-public:
-
- StdInCommand(relpipe::writer::boolean_t readStdIn) :
- readStdIn(readStdIn) {
- }
-
- void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector<relpipe::writer::string_t>& arguments) override {
- using namespace relpipe::writer;
-
- size_t i = 0;
- string_t relationName = readNext(input, arguments, i, true);
- integer_t attributeCount = std::stol(readNext(input, arguments, i, true)); // TODO: use integer data type's method? + unsigned type
- boolean_t writeHeader = true; // TODO: add option for header omitting
-
- std::shared_ptr<RelationalWriter> writer(Factory::create(output));
-
- std::vector<AttributeMetadata> attributes(attributeCount);
-
- for (size_t j = 0; j < attributeCount; j++) {
- string_t attributeName = readNext(input, arguments, i, true);
- TypeId attributeType = writer->toTypeId(readNext(input, arguments, i, true));
- attributes[j] = {attributeName, attributeType};
- }
-
- writer->startRelation(relationName, attributes, writeHeader);
-
- while (true) {
- string_t value = readNext(input, arguments, i, false);
- if (value.empty() && (input.eof() || input.fail() || (!readStdIn && i >= arguments.size()))) break;
- else writer->writeAttribute(value);
- // TODO: check attribute count (avoid unfinished records)
- }
- }
-};
-
-}
-}
-}
--- a/src/relpipe-in-cli.cpp Tue Sep 22 17:42:19 2020 +0200
+++ b/src/relpipe-in-cli.cpp Tue Sep 22 21:00:30 2020 +0200
@@ -25,23 +25,15 @@
#include <relpipe/cli/CLI.h>
#include <relpipe/cli/RelpipeCLIException.h>
-#include "Command.h"
-#include "ArgumentsCommand.h"
-#include "StdInCommand.h"
+#include "CLIParser.h"
+#include "Configuration.h"
+
+#include "CLICommand.h"
using namespace relpipe::cli;
using namespace relpipe::in::cli;
using namespace relpipe::writer;
-Command* findCommand(string_t commandName) {
- // TODO: better command names
- // TODO: help command
- if (commandName == L"generate") return new ArgumentsCommand();
- else if (commandName == L"generate-without-stdin") return new StdInCommand(false); // TODO: just for testing, StdInCommand(false) should work same as ArgumentsCommand()
- else if (commandName == L"generate-from-stdin") return new StdInCommand(true);
- else throw RelpipeCLIException(L"Unknown command: " + commandName, CLI::EXIT_CODE_UNKNOWN_COMMAND);
-}
-
int main(int argc, char** argv) {
setlocale(LC_ALL, "");
CLI::untieStdIO();
@@ -50,29 +42,20 @@
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
try {
- if (cli.arguments().size() > 0) {
-
- const wstring commandName = cli.arguments()[0];
- vector<wstring> arguments(cli.arguments().size() - 1);
- for (int i = 1; i < cli.arguments().size(); i++) {
- arguments[i - 1] = cli.arguments()[i];
- }
-
- std::shared_ptr<Command> command(findCommand(commandName));
- command->process(cin, cout, commandName, arguments);
- resultCode = CLI::EXIT_CODE_SUCCESS;
-
- } else {
- throw RelpipeCLIException(L"Missing command…", CLI::EXIT_CODE_BAD_SYNTAX);
- }
- } catch (RelpipeCLIException e) {
+ CLIParser cliParser;
+ Configuration configuration = cliParser.parse(cli.arguments());
+ CLICommand command;
+ std::shared_ptr<RelationalWriter> writer(Factory::create(std::cout));
+ command.process(configuration, writer);
+ resultCode = CLI::EXIT_CODE_SUCCESS;
+ } catch (RelpipeWriterException& e) {
+ fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str());
+ fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
+ resultCode = CLI::EXIT_CODE_DATA_ERROR;
+ } catch (RelpipeCLIException& e) {
fwprintf(stderr, L"Caught CLI exception: %ls\n", e.getMessge().c_str());
fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
resultCode = e.getExitCode();
- } catch (RelpipeWriterException e) {
- fwprintf(stderr, L"Caught Writer exception: %ls\n", e.getMessge().c_str());
- fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount());
- resultCode = CLI::EXIT_CODE_DATA_ERROR;
}
return resultCode;