src/AwkHandler.h
author František Kučera <franta-hg@frantovo.cz>
Tue, 30 Jul 2019 23:55:40 +0200
branchv_0
changeset 33 5288af2e4921
parent 31 64d9244ee252
child 35 eafffeea6a3e
permissions -rw-r--r--
namespace, formatting
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     1
/**
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     2
 * Relational pipes
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     3
 * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info)
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     4
 *
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     5
 * This program is free software: you can redistribute it and/or modify
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     6
 * it under the terms of the GNU General Public License as published by
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     7
 * the Free Software Foundation, either version 3 of the License, or
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     8
 * (at your option) any later version.
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
     9
 *
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    10
 * This program is distributed in the hope that it will be useful,
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    13
 * GNU General Public License for more details.
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    14
 *
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    15
 * You should have received a copy of the GNU General Public License
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    17
 */
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    18
#pragma once
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    19
33
5288af2e4921 namespace, formatting
František Kučera <franta-hg@frantovo.cz>
parents: 31
diff changeset
    20
#include <functional>
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    21
#include <memory>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    22
#include <string>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    23
#include <vector>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    24
#include <iostream>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    25
#include <sstream>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    26
#include <locale>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    27
#include <codecvt>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    28
#include <regex>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    29
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    30
#include <unistd.h>
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    31
#include <wait.h>
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    32
#include <ext/stdio_filebuf.h>
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    33
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    34
#include <relpipe/reader/typedefs.h>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    35
#include <relpipe/reader/TypeId.h>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    36
#include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    37
#include <relpipe/reader/handlers/AttributeMetadata.h>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    38
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    39
#include <relpipe/writer/Factory.h>
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    40
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    41
#include "Configuration.h"
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
    42
#include "AwkException.h"
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    43
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    44
namespace relpipe {
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    45
namespace tr {
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    46
namespace awk {
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    47
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    48
using namespace std;
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    49
using namespace relpipe;
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    50
using namespace relpipe::reader;
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    51
using namespace relpipe::reader::handlers;
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    52
5
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    53
/**
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    54
 * This transformation consists of three processes connected together using pipes.
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    55
 * 
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    56
 * Processes:
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    57
 *	- Parent: process RelationalReaderStringHandler events (read relational data, usually from STDIN) and pass them in the special text format to the pipe1
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    58
 *  - AWK: external program (/usr/bin/awk), read from the pipe1, writes to the pipe2
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    59
 *  - Writer: reads from the pipe2 and writes to relationalWriter (relational data, usually to STDOUT)
86de8e6ab231 documentation
František Kučera <franta-hg@frantovo.cz>
parents: 4
diff changeset
    60
 */
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    61
class AwkHandler : public RelationalReaderStringHandler {
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    62
private:
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    63
	Configuration configuration;
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    64
	writer::RelationalWriter* relationalWriter;
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
    65
	std::function<void() > relationalWriterFlush;
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
    66
	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
    67
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
    68
	int awkInputWriterFD = -1;
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
    69
	RelationConfiguration* currentRelationConfiguration = nullptr;
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
    70
	std::vector<AttributeMetadata> currentReaderMetadata;
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
    71
	std::vector<writer::AttributeMetadata> currentWriterMetadata;
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
    72
	std::map<string_t, string_t> currenVariablesMapping;
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
    73
	integer_t currentAttributeIndex = 0;
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
    74
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    75
	void createPipe(int& readerFD, int& writerFD) {
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    76
		int fds[2];
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    77
		int result = pipe(fds);
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    78
		readerFD = fds[0];
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    79
		writerFD = fds[1];
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
    80
		if (result < 0) throw AwkException(L"Unable to create a pipe.");
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    81
	}
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    82
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    83
	void redirectFD(int oldfd, int newfd) {
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    84
		int result = dup2(oldfd, newfd);
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
    85
		if (result < 0) throw AwkException(L"Unable redirect FD.");
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    86
	}
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    87
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    88
	void closeOrThrow(int fd) {
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
    89
		int error = close(fd);
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
    90
		if (error) throw AwkException(L"Unable to close FD: " + to_wstring(fd) + L" from PID: " + to_wstring(getpid()));
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
    91
	}
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
    92
11
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    93
	void execp(const std::vector<std::string>& args) {
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    94
		const char** a = new const char*[args.size() + 1];
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    95
		for (size_t i = 0; i < args.size(); i++) a[i] = args[i].c_str();
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    96
		a[args.size()] = nullptr;
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    97
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    98
		execvp(a[0], (char*const*) a);
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
    99
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
   100
		delete[] a;
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
   101
		throw AwkException(L"Unable to do execvp().");
11
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
   102
	}
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
   103
18
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   104
	/* TODO: move to lib-cli when stable and used in other modules */
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   105
	void setEnv(const char * name, const string_t& value) {
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   106
		setenv(name, convertor.to_bytes(value).c_str(), true);
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   107
	}
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   108
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   109
	/* TODO: move to lib-cli when stable and used in other modules */
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   110
	void setEnv(const char * name, std::string& value) {
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   111
		setenv(name, value.c_str(), true);
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   112
	}
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   113
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   114
	/* TODO: move to lib-cli when stable and used in other modules */
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   115
	void setEnv(const char * name, const integer_t& value) {
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   116
		setenv(name, to_string(value).c_str(), true);
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   117
	}
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   118
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   119
	void addDefinition(std::vector<std::string>& awkCliArgs, DefinitionRecipe& d) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   120
		awkCliArgs.push_back("-v");
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   121
		awkCliArgs.push_back(convertor.to_bytes(a2v(d.name) + L"=" + d.value));
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   122
	}
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   123
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   124
	void add(vector<AttributeMetadata>& readerAttributes, vector<writer::AttributeMetadata>& writerAttributes) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   125
		for (AttributeMetadata readerAttributes : readerAttributes)
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   126
			writerAttributes.push_back({
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   127
				readerAttributes.getAttributeName(),
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   128
				relationalWriter->toTypeId(readerAttributes.getTypeName())
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   129
			});
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   130
	}
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   131
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   132
	void cleanUp() {
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   133
		if (awkInputWriterFD >= 0) {
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   134
			closeOrThrow(awkInputWriterFD);
27
86d8bbc99e7b check exit codes of child processes
František Kučera <franta-hg@frantovo.cz>
parents: 26
diff changeset
   135
			int error1;
86d8bbc99e7b check exit codes of child processes
František Kučera <franta-hg@frantovo.cz>
parents: 26
diff changeset
   136
			int error2;
86d8bbc99e7b check exit codes of child processes
František Kučera <franta-hg@frantovo.cz>
parents: 26
diff changeset
   137
			__pid_t waitPID1 = wait(&error1);
86d8bbc99e7b check exit codes of child processes
František Kučera <franta-hg@frantovo.cz>
parents: 26
diff changeset
   138
			__pid_t waitPID2 = wait(&error2);
30
5261dfd3b952 more reserved names, exception
František Kučera <franta-hg@frantovo.cz>
parents: 29
diff changeset
   139
			if (error1 || error2) throw AwkException(L"The child process returned an error exit code.");
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   140
			awkInputWriterFD = -1;
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   141
		}
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   142
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   143
		currentAttributeIndex = 0;
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   144
		currentReaderMetadata.clear();
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   145
		currentWriterMetadata.clear();
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   146
		currenVariablesMapping.clear();
19
e4558df9ba2d drop – run AWK code but generate no output for given relation
František Kučera <franta-hg@frantovo.cz>
parents: 18
diff changeset
   147
		currentRelationConfiguration = nullptr;
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   148
	}
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   149
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   150
	void generateVariableMappings() {
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   151
		for (AttributeMetadata m : currentReaderMetadata) currenVariablesMapping[m.getAttributeName()] = L"";
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   152
		for (writer::AttributeMetadata m : currentWriterMetadata) currenVariablesMapping[m.attributeName] = L"";
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   153
		for (DefinitionRecipe d : configuration.definitions) currenVariablesMapping[d.name] = L"";
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   154
		for (DefinitionRecipe d : currentRelationConfiguration->definitions) currenVariablesMapping[d.name] = L"";
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   155
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   156
		for (std::pair<string_t, string_t> m : currenVariablesMapping) {
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   157
			currenVariablesMapping[m.first] = escapeAwkVariableName(m.first);
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   158
		}
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   159
	}
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   160
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   161
	string_t a2v(const string_t& attributeName) {
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   162
		if (currenVariablesMapping.find(attributeName) != currenVariablesMapping.end()) return currenVariablesMapping[attributeName];
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
   163
		else throw AwkException(L"Unable to find value in currenVariablesMapping");
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   164
	}
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   165
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   166
	template <typename K, typename V> bool containsValue(std::map<K, V> map, V value) {
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   167
		for (std::pair<K, V> p : map) if (p.second == value) return true;
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   168
		return false;
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   169
	}
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   170
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   171
	string_t escapeAwkVariableName(const string_t& attributeName) {
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   172
		// cat awkgram.y | awk -v FS='\\{"|",' -v ORS='|' '/static const struct token tokentab/, /\};/ { if (/^\{/) { print $2} }'
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   173
		// cat AwkHandler.h | awk -v FS=' |\\(' -v ORS='|' '/awkScript.*"function/ { print $4; }'
30
5261dfd3b952 more reserved names, exception
František Kučera <franta-hg@frantovo.cz>
parents: 29
diff changeset
   174
		std::wregex awkReservedNames(L"FS|OFS|NR|NF|" L"BEGIN|BEGINFILE|END|ENDFILE|adump|and|asort|asorti|atan2|bindtextdomain|break|case|close|compl|continue|cos|dcgettext|dcngettext|default|delete|do|else|eval|exit|exp|fflush|for|func|function|gensub|getline|gsub|if|in|include|index|int|intdiv0|isarray|length|load|log|lshift|match|mktime|namespace|next|nextfile|or|patsplit|print|printf|rand|return|rshift|sin|split|sprintf|sqrt|srand|stopme|strftime|strtonum|sub|substr|switch|system|systime|tolower|toupper|typeof|while|xor");
24
c805c968b7ed escape reserved AWK and our names: prefix conflicting variables with _
František Kučera <franta-hg@frantovo.cz>
parents: 23
diff changeset
   175
		std::wregex trReservedNames(L"_escape|_unescape|_readVariables|_writeVariables|record");
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   176
		std::wregex badCharacters(L"[^a-zA-Z0-9_]|^([0-9])");
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   177
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   178
		const string_t& name = std::regex_replace(attributeName, badCharacters, L"_$1");
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   179
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   180
		bool badName = false;
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   181
		badName |= regex_match(name, awkReservedNames);
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   182
		badName |= regex_match(name, trReservedNames);
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   183
		badName |= containsValue(currenVariablesMapping, name);
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   184
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   185
		if (badName) return escapeAwkVariableName(L"_" + name);
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   186
		else return name;
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   187
	}
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   188
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   189
	string_t escapeAwkValue(const string_t& value) {
23
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   190
		std::wstringstream escaped;
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   191
		for (wchar_t ch : value) {
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   192
			if (ch == '\t') escaped << L"\\t";
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   193
			else if (ch == '\n') escaped << L"\\n";
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   194
			else if (ch == '\\') escaped << L"\\\\";
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   195
			else escaped << ch;
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   196
		}
bc20d499a458 value escaping in c++
František Kučera <franta-hg@frantovo.cz>
parents: 22
diff changeset
   197
		return escaped.str();
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   198
	}
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   199
20
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   200
	void processAwkOutput(int awkOutputReaderFD) {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   201
		locale::global(locale("")); // needed for processing unicode texts, otherwise getline() stopped working on first line with non-ascii characters; TODO: move somewhere else?
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   202
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   203
		__gnu_cxx::stdio_filebuf<wchar_t> awkOutputReaderBuffer(awkOutputReaderFD, std::ios::in);
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   204
		std::wistream awkOutputReader(&awkOutputReaderBuffer);
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   205
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   206
		if (currentRelationConfiguration->drop) {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   207
			for (wchar_t ch; awkOutputReader.read(&ch, 1).good();); // just eat the lines from the AWK
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   208
		} else {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   209
			std::wstringstream currentValue;
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   210
			for (wchar_t ch; awkOutputReader.read(&ch, 1).good();) {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   211
				if (ch == '\t' || ch == '\n') {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   212
					relationalWriter->writeAttribute(currentValue.str());
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   213
					currentValue.str(L"");
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   214
					currentValue.clear();
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   215
				} else if (ch == '\\') {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   216
					ch = awkOutputReader.get();
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   217
					if (ch == 't') currentValue << L'\t';
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   218
					else if (ch == 'n') currentValue << L'\n';
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   219
					else if (ch == '\\') currentValue << L'\\';
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
   220
					else throw AwkException(L"Unknown escape sequence. Only \\t, \\n and \\\\ are supported.");
20
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   221
				} else {
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   222
					currentValue << ch;
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   223
				}
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   224
			}
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   225
		}
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   226
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   227
		closeOrThrow(awkOutputReaderFD);
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   228
	}
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   229
26
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   230
	void debugVariableMapping(const string_t& relationName) {
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   231
		relationalWriter->startRelation(relationName + L".variableMapping",{
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   232
			{L"attribute", writer::TypeId::STRING},
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   233
			{L"variable", writer::TypeId::STRING},
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   234
		}, true);
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   235
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   236
		for (std::pair<string_t, string_t> m : currenVariablesMapping) {
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   237
			relationalWriter->writeAttribute(m.first);
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   238
			relationalWriter->writeAttribute(m.second);
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   239
		}
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   240
	}
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   241
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   242
public:
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   243
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   244
	/**
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   245
	 * @param relationalWriter
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   246
	 * @param relationalWriterFlush the writer must be flushed before fork() in order to 
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   247
	 * avoid duplicate output (otherwise single relation might be written from two processes); 
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   248
	 * This is a little hack – if it stops working, we should reconnect the pipes 
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   249
	 * and use the writer only from a single process and avoid its effective duplication,
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   250
	 * or use different writers for each relation (or process).
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   251
	 * @param configuration
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   252
	 */
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   253
	AwkHandler(writer::RelationalWriter* relationalWriter, std::function<void() > relationalWriterFlush, Configuration& configuration) : relationalWriter(relationalWriter), relationalWriterFlush(relationalWriterFlush), configuration(configuration) {
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   254
	}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   255
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   256
	void startRelation(string_t name, vector<AttributeMetadata> attributes) override {
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   257
		cleanUp();
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   258
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   259
		for (int i = 0; i < configuration.relationConfigurations.size(); i++) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   260
			if (regex_match(name, wregex(configuration.relationConfigurations[i].relation))) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   261
				currentRelationConfiguration = &configuration.relationConfigurations[i];
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   262
				break; // it there are multiple matches, only the first configuration is used
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   263
			}
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   264
		}
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   265
21
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   266
		currentReaderMetadata = attributes;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   267
		// TODO: move to a reusable method (or use same metadata on both reader and writer side?)		
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   268
		if (currentRelationConfiguration && currentRelationConfiguration->writerMetadata.size()) {
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   269
			if (currentRelationConfiguration->inputAttributesPrepend) add(currentReaderMetadata, currentWriterMetadata);
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   270
			currentWriterMetadata.insert(currentWriterMetadata.end(), currentRelationConfiguration->writerMetadata.begin(), currentRelationConfiguration->writerMetadata.end());
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   271
			if (currentRelationConfiguration->inputAttributesAppend) add(currentReaderMetadata, currentWriterMetadata);
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   272
		} else {
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   273
			add(currentReaderMetadata, currentWriterMetadata);
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   274
		}
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   275
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   276
		if (currentRelationConfiguration) {
25
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   277
			generateVariableMappings();
13a1e1134797 avoid collisions in AWK variable names
František Kučera <franta-hg@frantovo.cz>
parents: 24
diff changeset
   278
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   279
			int awkInputReaderFD;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   280
			int awkOutputReaderFD;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   281
			int awkOutputWriterFD;
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   282
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   283
			createPipe(awkInputReaderFD, awkInputWriterFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   284
			createPipe(awkOutputReaderFD, awkOutputWriterFD);
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   285
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   286
			relationalWriterFlush();
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   287
			__pid_t awkPid = fork();
11
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
   288
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   289
			if (awkPid < 0) {
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
   290
				throw AwkException(L"Unable to fork AWK process.");
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   291
			} else if (awkPid == 0) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   292
				// AWK child process
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   293
				closeOrThrow(awkInputWriterFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   294
				closeOrThrow(awkOutputReaderFD);
12
8844ebce8fb4 pass defined global variables to AWK as CLI arguments
František Kučera <franta-hg@frantovo.cz>
parents: 11
diff changeset
   295
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   296
				redirectFD(awkInputReaderFD, STDIN_FILENO);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   297
				redirectFD(awkOutputWriterFD, STDOUT_FILENO);
11
f515d14794e0 variable execvp() arguments
František Kučera <franta-hg@frantovo.cz>
parents: 10
diff changeset
   298
18
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   299
				// Environment variables:
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   300
				setEnv("relationName", name);
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   301
				setEnv("inputAttributeCount", currentReaderMetadata.size());
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   302
				setEnv("outputAttributeCount", currentWriterMetadata.size());
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   303
				// TODO: better names? ENV vs. AWK variables?
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   304
				for (int i = 0; i < currentReaderMetadata.size(); i++) {
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   305
					setEnv((std::string("inputAttributeName") + std::to_string(i)).c_str(), currentReaderMetadata[i].getAttributeName());
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   306
					setEnv("inputAttributeType" + i, currentReaderMetadata[i].getTypeName());
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   307
				}
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   308
				for (int i = 0; i < currentWriterMetadata.size(); i++) {
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   309
					setEnv("outputAttributeName" + i, currentWriterMetadata[i].attributeName);
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   310
					// setEnv("outputAttributeType" + i, currentWriterMetadata[i].typeId); // TODO: type?
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   311
				}
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   312
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   313
				// AWK script:
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   314
				std::wstringstream awkScript;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   315
				awkScript << L"BEGIN {" << std::endl;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   316
				awkScript << L"FS=\"\\t\";" << std::endl;
18
2ac59242d0cb environment variables
František Kučera <franta-hg@frantovo.cz>
parents: 17
diff changeset
   317
				awkScript << L"OFS=\"\\t\";" << std::endl;
15
ba91a464d2b3 implement --for-each, --before-records, --after-records
František Kučera <franta-hg@frantovo.cz>
parents: 13
diff changeset
   318
				awkScript << currentRelationConfiguration->awkBeforeRecords << std::endl;
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   319
				awkScript << L"};" << std::endl;
15
ba91a464d2b3 implement --for-each, --before-records, --after-records
František Kučera <franta-hg@frantovo.cz>
parents: 13
diff changeset
   320
				awkScript << std::endl;
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   321
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   322
				awkScript << L"END {" << std::endl;
15
ba91a464d2b3 implement --for-each, --before-records, --after-records
František Kučera <franta-hg@frantovo.cz>
parents: 13
diff changeset
   323
				awkScript << currentRelationConfiguration->awkAfterRecords << std::endl;
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   324
				awkScript << L"};" << std::endl;
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   325
29
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   326
				awkScript << LR"AWK(
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   327
function _escape(value,    i) {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   328
	result = "";
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   329
	split(value, chars, "");
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   330
	for (i = 1; i <= length(chars); i++) {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   331
		ch = chars[i];
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   332
		if (ch == "\\")      { ch = "\\\\"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   333
		else if (ch == "\t") { ch = "\\t"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   334
		else if (ch == "\n") { ch = "\\n"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   335
		result = result ch;
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   336
	}
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   337
	return result;
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   338
};
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   339
						
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   340
function _unescape(value,    i) {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   341
	result = "";
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   342
	split(value, chars, "");
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   343
	for (i = 1; i <= length(chars); i++) {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   344
		ch = chars[i];
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   345
		if (ch == "\\") {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   346
			ch = chars[++i];
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   347
			if (ch == "\\")     { ch = "\\"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   348
			else if (ch == "t") { ch = "\t"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   349
			else if (ch == "n") { ch = "\n"; }
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   350
			else {
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   351
				printf("Unsupported escape sequence: %s\n", ch) > "/dev/stderr";
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   352
				exit 70;
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   353
			}
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   354
		}
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   355
		result = result ch;
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   356
	}
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   357
	return result;
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   358
};
b3d1a671315b AWK escaping and unescaping functions
František Kučera <franta-hg@frantovo.cz>
parents: 28
diff changeset
   359
)AWK";
21
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   360
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   361
				awkScript << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   362
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   363
				awkScript << L"function _readVariables() {" << std::endl;
31
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   364
				for (int i = 0; i < currentReaderMetadata.size(); i++) {
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   365
					AttributeMetadata& a = currentReaderMetadata[i];
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   366
					awkScript << a2v(a.getAttributeName());
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   367
					if (a.getTypeId() == TypeId::INTEGER) awkScript << L"=$" << (i + 1) << L";";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   368
					else if (a.getTypeId() == TypeId::BOOLEAN) awkScript << L"= $" << (i + 1) << L" == \"true\";";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   369
					else awkScript << L"=_unescape($" << (i + 1) << L");";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   370
					awkScript << std::endl;
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   371
				}
21
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   372
				awkScript << L"};" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   373
				awkScript << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   374
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   375
				awkScript << L"function _writeVariables() {" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   376
				awkScript << L"NF=" << currentWriterMetadata.size() << ";" << std::endl;
31
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   377
				for (int i = 0; i < currentWriterMetadata.size(); i++) {
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   378
					writer::AttributeMetadata& a = currentWriterMetadata[i];
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   379
					awkScript << L"$" << (i + 1);
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   380
					if (a.typeId == writer::TypeId::INTEGER) awkScript << L"=" << a2v(a.attributeName) << L";";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   381
					else if (a.typeId == writer::TypeId::BOOLEAN) awkScript << L"= " << a2v(a.attributeName) << L" ? \"true\" : \"false\" ;";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   382
					else awkScript << L"=_escape(" << a2v(a.attributeName) << L");";
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   383
					awkScript << std::endl;
64d9244ee252 integer and boolean types in AWK
František Kučera <franta-hg@frantovo.cz>
parents: 30
diff changeset
   384
				}
21
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   385
				awkScript << L"};" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   386
				awkScript << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   387
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   388
				awkScript << L"function record() {" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   389
				awkScript << L"_writeVariables();" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   390
				awkScript << L"print;" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   391
				awkScript << L"};" << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   392
				awkScript << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   393
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   394
				awkScript << L"{ _readVariables();  }" << std::endl; // read line (input attributes) into AWK variables
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   395
				awkScript << L"{ _writeVariables(); }" << std::endl; // write AWK variables to the line (so it matches the output attributes and can be implicitly printed without explicit record() call)
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   396
				awkScript << std::endl;
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   397
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   398
				awkScript << currentRelationConfiguration->awkForEach << std::endl; // user's code – can modify variables, filter results or explicitly call record() (can generate additional records or duplicate them)
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   399
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   400
				// CLI arguments:
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   401
				std::vector<std::string> args;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   402
				args.push_back("awk");
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   403
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   404
				for (auto d : configuration.definitions) addDefinition(args, d);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   405
				for (auto d : currentRelationConfiguration->definitions) addDefinition(args, d);
3
e086ae6a19c3 generate (some) relational output
František Kučera <franta-hg@frantovo.cz>
parents: 2
diff changeset
   406
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   407
				args.push_back(convertor.to_bytes(awkScript.str()));
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   408
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   409
				// 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).
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   410
				execp(args);
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   411
			} else {
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   412
				// Parent process
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   413
				closeOrThrow(awkInputReaderFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   414
				closeOrThrow(awkOutputWriterFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   415
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   416
				__pid_t writerPid = fork();
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   417
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   418
				if (writerPid < 0) {
28
4fdbe30d8c58 introduce AwkException
František Kučera <franta-hg@frantovo.cz>
parents: 27
diff changeset
   419
					throw AwkException(L"Unable to fork Writer process.");
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   420
				} else if (writerPid == 0) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   421
					// Writer child process
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   422
					closeOrThrow(awkInputWriterFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   423
26
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   424
					if (currentRelationConfiguration->debugVariableMapping) debugVariableMapping(name);
cf57e8c78492 add option: --debug-variable-mapping
František Kučera <franta-hg@frantovo.cz>
parents: 25
diff changeset
   425
19
e4558df9ba2d drop – run AWK code but generate no output for given relation
František Kučera <franta-hg@frantovo.cz>
parents: 18
diff changeset
   426
					if (currentRelationConfiguration->drop) {
e4558df9ba2d drop – run AWK code but generate no output for given relation
František Kučera <franta-hg@frantovo.cz>
parents: 18
diff changeset
   427
						// TODO: omit whole this process and pipe AWK output to /dev/null?
e4558df9ba2d drop – run AWK code but generate no output for given relation
František Kučera <franta-hg@frantovo.cz>
parents: 18
diff changeset
   428
					} else {
21
d46a727b7965 read and write variables, generate real relation
František Kučera <franta-hg@frantovo.cz>
parents: 20
diff changeset
   429
						relationalWriter->startRelation(name, currentWriterMetadata, true);
19
e4558df9ba2d drop – run AWK code but generate no output for given relation
František Kučera <franta-hg@frantovo.cz>
parents: 18
diff changeset
   430
					}
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   431
20
f937ad57351f read and un-escape the AWK output, convert to relational attributes
František Kučera <franta-hg@frantovo.cz>
parents: 19
diff changeset
   432
					processAwkOutput(awkOutputReaderFD);
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   433
					exit(0);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   434
				} else {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   435
					// Parent process
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   436
					closeOrThrow(awkOutputReaderFD);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   437
				}
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   438
			}
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   439
		} else {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   440
			relationalWriter->startRelation(name, currentWriterMetadata, true);
1
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   441
		}
05d969cd90d4 fork() processes
František Kučera <franta-hg@frantovo.cz>
parents: 0
diff changeset
   442
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   443
	}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   444
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   445
	void attribute(const string_t& value) override {
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   446
		if (currentRelationConfiguration) {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   447
			currentAttributeIndex++;
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   448
			currentAttributeIndex = currentAttributeIndex % currentReaderMetadata.size();
7
46db0e6e548b pass name-value pair to AWK
František Kučera <franta-hg@frantovo.cz>
parents: 6
diff changeset
   449
17
54716ea44d52 pass only values to the awk process
František Kučera <franta-hg@frantovo.cz>
parents: 15
diff changeset
   450
			std::string awkValue = convertor.to_bytes(escapeAwkValue(value));
54716ea44d52 pass only values to the awk process
František Kučera <franta-hg@frantovo.cz>
parents: 15
diff changeset
   451
			if (currentAttributeIndex == 0) awkValue += "\n";
54716ea44d52 pass only values to the awk process
František Kučera <franta-hg@frantovo.cz>
parents: 15
diff changeset
   452
			else awkValue += "\t";
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   453
17
54716ea44d52 pass only values to the awk process
František Kučera <franta-hg@frantovo.cz>
parents: 15
diff changeset
   454
			write(awkInputWriterFD, awkValue.c_str(), awkValue.length());
13
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   455
		} else {
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   456
			relationalWriter->writeAttribute(value);
b74001992ec3 implement --relation option (thus some relations might pass unmodified by AWK), support per-relation variables
František Kučera <franta-hg@frantovo.cz>
parents: 12
diff changeset
   457
		}
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   458
	}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   459
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   460
	void endOfPipe() {
2
580ccb511301 for each attribute
František Kučera <franta-hg@frantovo.cz>
parents: 1
diff changeset
   461
		cleanUp();
0
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   462
	}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   463
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   464
};
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   465
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   466
}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   467
}
644fd2ce2580 project skeleton
František Kučera <franta-hg@frantovo.cz>
parents:
diff changeset
   468
}