# HG changeset patch # User František Kučera # Date 1557151220 -7200 # Node ID 513ea30d2fa3bea1dd71bd2741116d6dc161b2fa # Parent 46db0e6e548b475b6d149ff89c3f6195f7541cf6 more configuration/options diff -r 46db0e6e548b -r 513ea30d2fa3 src/CLIParser.h --- a/src/CLIParser.h Sun May 05 23:09:20 2019 +0200 +++ b/src/CLIParser.h Mon May 06 16:00:20 2019 +0200 @@ -29,6 +29,10 @@ namespace tr { namespace awk { +/** + * This tr-awk CLI options are inspired by tr-guile options. + * These configurations are independent and might diverge, but when possible, the should share same option names and same logic for common parts. + */ class CLIParser { private: @@ -39,17 +43,65 @@ 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 addRelation(Configuration& c, RelationConfiguration& currentRelation) { + if (currentRelation.relation.size()) { + c.relationConfigurations.push_back(currentRelation); + currentRelation = RelationConfiguration(); + } + } + + relpipe::writer::TypeId parseTypeId(const 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 string_t OPTION_EXPRESSION; + static const string_t OPTION_RELATION; + static const string_t OPTION_OUTPUT_ATTRIBUTE; + static const string_t OPTION_INPUT_ATTRIBUTES_APPEND; + static const string_t OPTION_INPUT_ATTRIBUTES_PREPEND; + static const string_t OPTION_BEFORE_RECORDS; + static const string_t OPTION_AFTER_RECORDS; + static const string_t OPTION_FOR_EACH; + static const string_t OPTION_DEFINE; Configuration parse(const std::vector& arguments) { Configuration c; + RelationConfiguration currentRelation; - for (int i = 0; i < arguments.size();) { - string_t option = readNext(arguments, i); - if (option == OPTION_EXPRESSION) c.awkExpression = readNext(arguments, i); - else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); + { + for (int i = 0; i < arguments.size();) { + string_t option = readNext(arguments, i); + + if (option == OPTION_BEFORE_RECORDS) currentRelation.awkBeforeRecords = readNext(arguments, i); + else if (option == OPTION_AFTER_RECORDS) currentRelation.awkAfterRecords = readNext(arguments, i); + else if (option == OPTION_FOR_EACH) currentRelation.awkForEach = readNext(arguments, i); + else if (option == OPTION_INPUT_ATTRIBUTES_APPEND) currentRelation.inputAttributesAppend = true; + else if (option == OPTION_INPUT_ATTRIBUTES_PREPEND) currentRelation.inputAttributesPrepend = true; + else if (option == OPTION_RELATION) { + addRelation(c, currentRelation); // previous relation + currentRelation.relation = readNext(arguments, i); + } else if (option == OPTION_OUTPUT_ATTRIBUTE) { + relpipe::writer::AttributeMetadata attribute; + attribute.attributeName = readNext(arguments, i); + attribute.typeId = parseTypeId(readNext(arguments, i)); + currentRelation.writerMetadata.push_back(attribute); + } else if (option == OPTION_DEFINE) { + DefinitionRecipe definition; + definition.name = readNext(arguments, i); + definition.type = readNext(arguments, i); + definition.value = readNext(arguments, i); + if (currentRelation.relation.size()) currentRelation.definitions.push_back(definition); + else c.definitions.push_back(definition); + } 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; @@ -59,7 +111,14 @@ } }; -const string_t CLIParser::OPTION_EXPRESSION = L"--expression"; +const string_t CLIParser::OPTION_RELATION = L"--relation"; +const string_t CLIParser::OPTION_OUTPUT_ATTRIBUTE = L"--output-attribute"; +const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_APPEND = L"--input-attributes-append"; +const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_PREPEND = L"--input-attributes-prepend"; +const string_t CLIParser::OPTION_BEFORE_RECORDS = L"--before-records"; +const string_t CLIParser::OPTION_AFTER_RECORDS = L"--after-records"; +const string_t CLIParser::OPTION_FOR_EACH = L"--for-each"; +const string_t CLIParser::OPTION_DEFINE = L"--define"; } } diff -r 46db0e6e548b -r 513ea30d2fa3 src/Configuration.h --- a/src/Configuration.h Sun May 05 23:09:20 2019 +0200 +++ b/src/Configuration.h Mon May 06 16:00:20 2019 +0200 @@ -24,10 +24,62 @@ namespace tr { namespace awk { +class DefinitionRecipe { +public: + + virtual ~DefinitionRecipe() { + } + + relpipe::writer::string_t name; + relpipe::writer::string_t type; + relpipe::writer::string_t value; +}; + +class RelationConfiguration { +public: + + virtual ~RelationConfiguration() { + } + + relpipe::writer::string_t relation; + relpipe::writer::string_t awkBeforeRecords; + relpipe::writer::string_t awkAfterRecords; + relpipe::writer::string_t awkForEach; + + /** + * Variable definitions for this relation. + * Can be used as a safe way for passing parameters from the outside environment. + * See also Configuration::definitions (can be overridden by relation's definitions) + */ + std::vector definitions; + + /** + * If empty, output relation will have same metadata as the input relation. + */ + std::vector writerMetadata; + + /** + * Whether original attributes should be appended to those specified using --output-attribute + */ + bool inputAttributesAppend = false; + + /** + * Whether original attributes should be prepended to those specified using --output-attribute + */ + bool inputAttributesPrepend = false; +}; + class Configuration { public: - relpipe::writer::string_t awkExpression; + vector relationConfigurations; + + /** + * Global definitions for all relations. + * Can be used as a safe way for passing parameters from the outside environment. + * See also RelationConfiguration::definitions + */ + std::vector definitions; virtual ~Configuration() { }