84 void closeOrThrow(int fd) { |
84 void closeOrThrow(int fd) { |
85 int error = close(fd); |
85 int error = close(fd); |
86 if (error) throw cli::RelpipeCLIException(L"Unable to close FD: " + to_wstring(fd) + L" from PID: " + to_wstring(getpid()), cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exceptions? |
86 if (error) throw cli::RelpipeCLIException(L"Unable to close FD: " + to_wstring(fd) + L" from PID: " + to_wstring(getpid()), cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exceptions? |
87 } |
87 } |
88 |
88 |
|
89 void execp(const std::vector<std::string>& args) { |
|
90 const char** a = new const char*[args.size() + 1]; |
|
91 for (size_t i = 0; i < args.size(); i++) a[i] = args[i].c_str(); |
|
92 a[args.size()] = nullptr; |
|
93 |
|
94 execvp(a[0], (char*const*) a); |
|
95 |
|
96 delete[] a; |
|
97 throw cli::RelpipeCLIException(L"Unable to do execvp().", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exceptions? |
|
98 } |
|
99 |
89 void cleanUp() { |
100 void cleanUp() { |
90 if (awkInputWriterFD >= 0) { |
101 if (awkInputWriterFD >= 0) { |
91 closeOrThrow(awkInputWriterFD); |
102 closeOrThrow(awkInputWriterFD); |
92 // TODO: check exit codes |
103 // TODO: check exit codes |
93 __pid_t waitResult1 = wait(NULL); |
104 __pid_t waitResult1 = wait(NULL); |
138 closeOrThrow(awkOutputReaderFD); |
149 closeOrThrow(awkOutputReaderFD); |
139 |
150 |
140 redirectFD(awkInputReaderFD, STDIN_FILENO); |
151 redirectFD(awkInputReaderFD, STDIN_FILENO); |
141 redirectFD(awkOutputWriterFD, STDOUT_FILENO); |
152 redirectFD(awkOutputWriterFD, STDOUT_FILENO); |
142 |
153 |
|
154 std::wstringstream awkScript; |
|
155 awkScript << L"BEGIN {" << std::endl; |
|
156 awkScript << L"FS=\"\\t\";" << std::endl; |
|
157 awkScript << L"};" << std::endl; |
|
158 |
|
159 awkScript << L"END {" << std::endl; |
|
160 // awkScript << … << std::endl; |
|
161 awkScript << L"};" << std::endl; |
|
162 |
|
163 awkScript << L"{print \"AWK says: line \" NR \" '\" $0 \"' has \" NF \" fields; first field is '\" $1 \"'\";}" << std::endl; |
|
164 |
|
165 std::vector<std::string> args; |
|
166 args.push_back("awk"); |
|
167 args.push_back(convertor.to_bytes(awkScript.str())); |
|
168 |
143 // Runs AWK program found on $PATH → user can plug-in a custom implementation or a wrapper, but this can be also bit dangerous (however AWK itself is dangerous). |
169 // Runs AWK program found on $PATH → user can plug-in a custom implementation or a wrapper, but this can be also bit dangerous (however AWK itself is dangerous). |
144 execlp("awk", "awk", "BEGIN { FS=\"\\t\" }; {print \"AWK says: line \" NR \" '\" $0 \"' has \" NF \" fields; first field is '\" $1 \"'\";}", nullptr); |
170 execp(args); |
145 } else { |
171 } else { |
146 // Parent process |
172 // Parent process |
147 closeOrThrow(awkInputReaderFD); |
173 closeOrThrow(awkInputReaderFD); |
148 closeOrThrow(awkOutputWriterFD); |
174 closeOrThrow(awkOutputWriterFD); |
149 |
175 |
154 } else if (writerPid == 0) { |
180 } else if (writerPid == 0) { |
155 // Writer child process |
181 // Writer child process |
156 closeOrThrow(awkInputWriterFD); |
182 closeOrThrow(awkInputWriterFD); |
157 |
183 |
158 locale::global(locale("")); // needed for processing unicode texts, otherwise getline() stopped working on first line with non-ascii characters; TODO: move somewhere else? |
184 locale::global(locale("")); // needed for processing unicode texts, otherwise getline() stopped working on first line with non-ascii characters; TODO: move somewhere else? |
159 |
185 |
160 __gnu_cxx::stdio_filebuf<wchar_t> awkOutputReaderBuffer(awkOutputReaderFD, std::ios::in); |
186 __gnu_cxx::stdio_filebuf<wchar_t> awkOutputReaderBuffer(awkOutputReaderFD, std::ios::in); |
161 std::wistream awkOutputReader(&awkOutputReaderBuffer); |
187 std::wistream awkOutputReader(&awkOutputReaderBuffer); |
162 |
188 |
163 relationalWriter->startRelation(L"writer_debug",{ |
189 relationalWriter->startRelation(L"writer_debug",{ |
164 {L"message", writer::TypeId::STRING}, |
190 {L"message", writer::TypeId::STRING}, |