pass name-value pair to AWK v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 05 May 2019 23:09:20 +0200
branchv_0
changeset 7 46db0e6e548b
parent 6 efa96f51b308
child 8 513ea30d2fa3
pass name-value pair to AWK
src/AwkHandler.h
--- a/src/AwkHandler.h	Sun May 05 12:38:09 2019 +0200
+++ b/src/AwkHandler.h	Sun May 05 23:09:20 2019 +0200
@@ -62,8 +62,11 @@
 private:
 	Configuration configuration;
 	writer::RelationalWriter* relationalWriter;
+	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
 
 	int awkInputWriterFD = -1;
+	std::vector<AttributeMetadata> currentReaderMetadata;
+	integer_t currentAttributeIndex = 0;
 
 	void createPipe(int& readerFD, int& writerFD) {
 		int fds[2];
@@ -91,6 +94,21 @@
 			__pid_t waitResult2 = wait(NULL);
 			awkInputWriterFD = -1;
 		}
+
+		currentAttributeIndex = 0;
+		currentReaderMetadata.clear();
+	}
+
+	string_t a2v(const string_t& attributeName) {
+		// FIXME: escape reserved names; prefix with _ ?
+		// cat awkgram.y | awk -v FS='\\{"|",' -v ORS='|' '/static const struct token tokentab/, /\};/ { if (/^\{/) { print $2} }'
+		// 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
+		return attributeName;
+	}
+
+	string_t escapeAwkValue(const string_t& value) {
+		// FIXME: escape field and record separators
+		return value;
 	}
 
 public:
@@ -101,6 +119,7 @@
 	void startRelation(string_t name, vector<AttributeMetadata> attributes) override {
 		cleanUp();
 
+		currentReaderMetadata = attributes;
 
 		int awkInputReaderFD;
 		int awkOutputReaderFD;
@@ -122,7 +141,7 @@
 			redirectFD(awkOutputWriterFD, STDOUT_FILENO);
 
 			// 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).
-			execlp("awk", "awk", "{print \"AWK says: line \" NR \" = \" $0;}", nullptr);
+			execlp("awk", "awk", "BEGIN { FS=\"\\t\" }; {print \"AWK says: line \" NR \" '\" $0 \"' has \" NF \" fields; first field is '\" $1 \"'\";}", nullptr);
 		} else {
 			// Parent process
 			closeOrThrow(awkInputReaderFD);
@@ -158,7 +177,20 @@
 	}
 
 	void attribute(const string_t& value) override {
-		dprintf(awkInputWriterFD, "attribute!\n");
+		string_t variableName = a2v(currentReaderMetadata[currentAttributeIndex].getAttributeName());
+		string_t variableValue = escapeAwkValue(value);
+
+		currentAttributeIndex++;
+		currentAttributeIndex = currentAttributeIndex % currentReaderMetadata.size();
+
+		// TODO: just the value – move name to the AWK function
+		std::string variablePair = convertor.to_bytes(variableName + L"=" + variableValue);
+
+		if (currentAttributeIndex == 0) variablePair += "\n";
+		else variablePair += "\t";
+
+		write(awkInputWriterFD, variablePair.c_str(), variablePair.length());
+
 	}
 
 	void endOfPipe() {