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";