streamlets: separate parsing from searching v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 19 Jan 2020 17:05:46 +0100
branchv_0
changeset 48 26a8b1a14889
parent 47 beefddde951e
child 49 ab48ad4ecb91
streamlets: separate parsing from searching
src/StreamletAttributeFinder.h
--- a/src/StreamletAttributeFinder.h	Sun Jan 19 15:44:30 2020 +0100
+++ b/src/StreamletAttributeFinder.h	Sun Jan 19 17:05:46 2020 +0100
@@ -45,24 +45,36 @@
 	std::map<int, std::shared_ptr<SubProcess>> subProcesses;
 	std::map<int, std::vector<AttributeMetadata>> cachedMetadata;
 
+	std::vector<string_t> splitBySeparator(const string_t& originalString, const wchar_t separator = L':', const wchar_t escape = L'\\') {
+		std::vector<string_t> result;
+		std::wstringstream current;
+		for (int i = 0, size = originalString.size(); i < size; i++) {
+			wchar_t ch = originalString[i];
+			if (ch == escape) {
+				if (i + 1 < size) {
+					ch = originalString[++i];
+					if (ch == separator || ch == escape) current.put(ch);
+					else RelpipeWriterException(L"Invalid escape sequence at position " + std::to_wstring(i) + L" of: " + originalString);
+				} else {
+					throw RelpipeWriterException(L"Invalid use of escape character at the end of: " + originalString);
+				}
+			} else if (ch == separator || i + 1 == size) {
+				if (current.str().size()) result.push_back(current.str());
+				current.str(L"");
+				current.clear();
+			} else {
+				current.put(ch);
+			}
+		}
+		return result;
+	}
+
 	string_t getStreamletCommand(const RequestedField& field) {
 		const char* streamletPathChars = getenv("RELPIPE_IN_FILESYSTEM_STREAMLET_PATH");
 		if (streamletPathChars) {
-			std::wstringstream current;
-			string_t streamletPath = convertor.from_bytes(streamletPathChars);
-			for (int i = 0, streamletPathSize = streamletPath.size(); i < streamletPathSize; i++) {
-				if (streamletPath[i] == ':' || i == streamletPathSize - 1) { // FIXME: support \: and \\ escaping
-					current << L"/" << field.name;
-					fs::path streamletFile(current.str());
-					if (fs::exists(streamletFile) && ::access(streamletFile.c_str(), X_OK) == 0) { // n.b. must be set executable using e.g. chmod – files executable through only ACL, are actually not executable
-						return current.str();
-					} else {
-						current.str(L"");
-						current.clear();
-					}
-				} else {
-					current.put(streamletPath[i]);
-				}
+			for (string_t path : splitBySeparator(convertor.from_bytes(streamletPathChars))) {
+				fs::path file = fs::path(path) / fs::path(field.name);
+				if (fs::exists(file) && ::access(file.c_str(), X_OK) == 0) return file.wstring();
 			}
 			throw RelpipeWriterException(L"Streamlet „" + field.name + L"“ was not found at $RELPIPE_IN_FILESYSTEM_STREAMLET_PATH");
 		} else {
@@ -99,9 +111,7 @@
 
 public:
 
-	static const string_t SCRIPT_PREFIX;
-
-	virtual vector<AttributeMetadata> toMetadata(RelationalWriter* writer, const string_t& relationName, const RequestedField& field) override {
+	virtual vector<AttributeMetadata> toMetadata(RelationalWriter* writer, const string_t& relationName, const RequestedField & field) override {
 		if (field.group == RequestedField::GROUP_STREAMLET) {
 
 			if (cachedMetadata.count(field.id)) {
@@ -160,8 +170,6 @@
 	}
 };
 
-const relpipe::writer::string_t StreamletAttributeFinder::SCRIPT_PREFIX = L"__relpipe_in_filesystem_script_";
-
 }
 }
 }