27 |
27 |
28 namespace relpipe { |
28 namespace relpipe { |
29 namespace tr { |
29 namespace tr { |
30 namespace awk { |
30 namespace awk { |
31 |
31 |
|
32 /** |
|
33 * This tr-awk CLI options are inspired by tr-guile options. |
|
34 * These configurations are independent and might diverge, but when possible, the should share same option names and same logic for common parts. |
|
35 */ |
32 class CLIParser { |
36 class CLIParser { |
33 private: |
37 private: |
34 |
38 |
35 // FIXME: move common methods/classes to relpipe-lib-cli or relpipe-lib-helper |
39 // FIXME: move common methods/classes to relpipe-lib-cli or relpipe-lib-helper |
36 |
40 |
37 string_t readNext(std::vector<string_t> arguments, int& i) { |
41 string_t readNext(std::vector<string_t> arguments, int& i) { |
38 if (i < arguments.size()) return arguments[i++]; |
42 if (i < arguments.size()) return arguments[i++]; |
39 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); |
43 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); |
40 } |
44 } |
41 |
45 |
|
46 void addRelation(Configuration& c, RelationConfiguration& currentRelation) { |
|
47 if (currentRelation.relation.size()) { |
|
48 c.relationConfigurations.push_back(currentRelation); |
|
49 currentRelation = RelationConfiguration(); |
|
50 } |
|
51 } |
|
52 |
|
53 relpipe::writer::TypeId parseTypeId(const string_t& value) { |
|
54 using t = relpipe::writer::TypeId; |
|
55 if (value == L"string") return t::STRING; |
|
56 else if (value == L"integer") return t::INTEGER; |
|
57 else if (value == L"boolean") return t::BOOLEAN; |
|
58 else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TypeId: " + value, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); |
|
59 } |
|
60 |
42 public: |
61 public: |
43 |
62 |
44 static const string_t OPTION_EXPRESSION; |
63 static const string_t OPTION_RELATION; |
|
64 static const string_t OPTION_OUTPUT_ATTRIBUTE; |
|
65 static const string_t OPTION_INPUT_ATTRIBUTES_APPEND; |
|
66 static const string_t OPTION_INPUT_ATTRIBUTES_PREPEND; |
|
67 static const string_t OPTION_BEFORE_RECORDS; |
|
68 static const string_t OPTION_AFTER_RECORDS; |
|
69 static const string_t OPTION_FOR_EACH; |
|
70 static const string_t OPTION_DEFINE; |
45 |
71 |
46 Configuration parse(const std::vector<string_t>& arguments) { |
72 Configuration parse(const std::vector<string_t>& arguments) { |
47 Configuration c; |
73 Configuration c; |
|
74 RelationConfiguration currentRelation; |
48 |
75 |
49 for (int i = 0; i < arguments.size();) { |
76 { |
50 string_t option = readNext(arguments, i); |
77 for (int i = 0; i < arguments.size();) { |
51 if (option == OPTION_EXPRESSION) c.awkExpression = readNext(arguments, i); |
78 string_t option = readNext(arguments, i); |
52 else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); |
79 |
|
80 if (option == OPTION_BEFORE_RECORDS) currentRelation.awkBeforeRecords = readNext(arguments, i); |
|
81 else if (option == OPTION_AFTER_RECORDS) currentRelation.awkAfterRecords = readNext(arguments, i); |
|
82 else if (option == OPTION_FOR_EACH) currentRelation.awkForEach = readNext(arguments, i); |
|
83 else if (option == OPTION_INPUT_ATTRIBUTES_APPEND) currentRelation.inputAttributesAppend = true; |
|
84 else if (option == OPTION_INPUT_ATTRIBUTES_PREPEND) currentRelation.inputAttributesPrepend = true; |
|
85 else if (option == OPTION_RELATION) { |
|
86 addRelation(c, currentRelation); // previous relation |
|
87 currentRelation.relation = readNext(arguments, i); |
|
88 } else if (option == OPTION_OUTPUT_ATTRIBUTE) { |
|
89 relpipe::writer::AttributeMetadata attribute; |
|
90 attribute.attributeName = readNext(arguments, i); |
|
91 attribute.typeId = parseTypeId(readNext(arguments, i)); |
|
92 currentRelation.writerMetadata.push_back(attribute); |
|
93 } else if (option == OPTION_DEFINE) { |
|
94 DefinitionRecipe definition; |
|
95 definition.name = readNext(arguments, i); |
|
96 definition.type = readNext(arguments, i); |
|
97 definition.value = readNext(arguments, i); |
|
98 if (currentRelation.relation.size()) currentRelation.definitions.push_back(definition); |
|
99 else c.definitions.push_back(definition); |
|
100 } else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS); |
|
101 |
|
102 } |
|
103 |
|
104 addRelation(c, currentRelation); // last relation |
53 } |
105 } |
54 |
106 |
55 return c; |
107 return c; |
56 } |
108 } |
57 |
109 |
58 virtual ~CLIParser() { |
110 virtual ~CLIParser() { |
59 } |
111 } |
60 }; |
112 }; |
61 |
113 |
62 const string_t CLIParser::OPTION_EXPRESSION = L"--expression"; |
114 const string_t CLIParser::OPTION_RELATION = L"--relation"; |
|
115 const string_t CLIParser::OPTION_OUTPUT_ATTRIBUTE = L"--output-attribute"; |
|
116 const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_APPEND = L"--input-attributes-append"; |
|
117 const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_PREPEND = L"--input-attributes-prepend"; |
|
118 const string_t CLIParser::OPTION_BEFORE_RECORDS = L"--before-records"; |
|
119 const string_t CLIParser::OPTION_AFTER_RECORDS = L"--after-records"; |
|
120 const string_t CLIParser::OPTION_FOR_EACH = L"--for-each"; |
|
121 const string_t CLIParser::OPTION_DEFINE = L"--define"; |
63 |
122 |
64 } |
123 } |
65 } |
124 } |
66 } |
125 } |