From e4c4b298056170a383d4b413e8f382f48a30cda5 Mon Sep 17 00:00:00 2001
From: Tim Felgentreff <timfelgentreff@gmail.com>
Date: Thu, 28 Apr 2022 21:01:27 +0200
Subject: [PATCH] extract arg quoting for iwndows

---
 src/include/iolib.h      |  2 ++
 src/stratagus/iolib.cpp  | 42 ++++++++++++++++++++++++++++++++++++++++
 src/stratagus/script.cpp | 36 +++++-----------------------------
 3 files changed, 49 insertions(+), 31 deletions(-)

diff --git a/src/include/iolib.h b/src/include/iolib.h
index 065f1a224..7aa4a8659 100644
--- a/src/include/iolib.h
+++ b/src/include/iolib.h
@@ -146,6 +146,8 @@ extern bool CanAccessFile(const char *filename);
 /// Read the contents of a directory
 extern int ReadDataDirectory(const char *dirname, std::vector<FileList> &flp);
 
+extern std::vector<std::string> QuoteArguments(std::vector<std::string> args);
+
 //@}
 
 #endif // !__IOLIB_H__
diff --git a/src/stratagus/iolib.cpp b/src/stratagus/iolib.cpp
index 6dc5cd93a..1bb9f4578 100644
--- a/src/stratagus/iolib.cpp
+++ b/src/stratagus/iolib.cpp
@@ -837,4 +837,46 @@ FileWriter *CreateFileWriter(const std::string &filename)
 	}
 }
 
+/**
+ * Quote arguments for usage in calls to system(), popen() and similar.
+ * Really only needed on Windows, where all these calls just concatenate
+ * all arguments with a space and pass the full string to the next process.
+ */
+std::vector<std::string> QuoteArguments(std::vector<std::string> args)
+{
+	std::vector<std::string> outArgs;
+	for (auto arg : args) {
+#ifdef WIN32
+		if (!arg.empty() && arg.find_first_of(" \t\n\v\"") == std::string::npos) {
+			outArgs.push_back(arg);
+		} else {
+			// Windows always needs argument quoting around arguments with spaces
+			std::string ss = "\"";
+			for (auto ch = arg.begin(); ; ch++) {
+				int backslashes = 0;
+				while (ch != arg.end() && *ch == '\\') {
+					ch++;
+					backslashes++;
+				}
+				if (ch == arg.end()) {
+					ss.append(backslashes * 2, '\\');
+					break;
+				} else if (*ch == '"') {
+					ss.append(backslashes * 2 + 1, '\\');
+					ss.push_back(*ch);
+				} else {
+					ss.append(backslashes, '\\');
+					ss.push_back(*ch);
+				}
+			}
+			ss.push_back('"');
+			outArgs.push_back(ss);
+		}
+#else
+		outArgs.push_back(arg);
+#endif
+	}
+	return outArgs;
+}
+
 //@}
diff --git a/src/stratagus/script.cpp b/src/stratagus/script.cpp
index c78615e3b..9757a23bc 100644
--- a/src/stratagus/script.cpp
+++ b/src/stratagus/script.cpp
@@ -2158,38 +2158,12 @@ static int CclRestartStratagus(lua_State *l)
 			break;
 		}
 	}
-	int newArgc = OriginalArgv.size() + (insertRestartArgument ? 2 : 1);
+	std::vector<std::string> quotedArgs = QuoteArguments(OriginalArgv);
+
+	int newArgc = quotedArgs.size() + (insertRestartArgument ? 2 : 1);
 	char **argv = new char*[newArgc];
-	for (unsigned int i = 0; i < OriginalArgv.size(); i++) {
-#ifdef WIN32
-		if (!OriginalArgv[i].empty() && OriginalArgv[i].find_first_of(" \t\n\v\"") == std::string::npos) {
-			argv[i] = const_cast<char*>(OriginalArgv[i].c_str());
-		} else {
-			// Windows always needs argument quoting around arguments with spaces
-			std::string ss = "\"";
-			for (auto ch = OriginalArgv[i].begin(); ; ch++) {
-				int backslashes = 0;
-				while (ch != OriginalArgv[i].end() && *ch == '\\') {
-					ch++;
-					backslashes++;
-				}
-				if (ch == OriginalArgv[i].end()) {
-					ss.append(backslashes * 2, '\\');
-					break;
-				} else if (*ch == '"') {
-					ss.append(backslashes * 2 + 1, '\\');
-					ss.push_back(*ch);
-				} else {
-					ss.append(backslashes, '\\');
-					ss.push_back(*ch);
-				}
-			}
-			ss.push_back('"');
-			argv[i] = strdup(ss.c_str());
-		}
-#else
-		argv[i] = const_cast<char*>(OriginalArgv[i].c_str());
-#endif
+	for (unsigned int i = 0; i < quotedArgs.size(); i++) {
+		argv[i] = const_cast<char*>(quotedArgs[i].c_str());
 	}
 	if (insertRestartArgument) {
 		argv[newArgc - 2] = (char*)"-r";