@@ -75,6 +75,64 @@ static int stdio_redirection(int fd, const std::string &file)
75
75
}
76
76
#endif
77
77
78
+ #ifdef _WIN32
79
+ // Read
80
+ // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
81
+ std::wstring quote_windows_arg (const std::wstring &src)
82
+ {
83
+ if (src.find_first_of (L" \t\n\v\" " ) == src.npos )
84
+ return src;
85
+
86
+ std::wstring result = L" \" " ;
87
+
88
+ for (auto it = src.begin ();; ++it)
89
+ {
90
+ std::size_t NumberBackslashes = 0 ;
91
+
92
+ while (it != src.end () && *it == L' \\ ' )
93
+ {
94
+ ++it;
95
+ ++NumberBackslashes;
96
+ }
97
+
98
+ if (it == src.end ())
99
+ {
100
+ //
101
+ // Escape all backslashes, but let the terminating
102
+ // double quotation mark we add below be interpreted
103
+ // as a metacharacter.
104
+ //
105
+
106
+ result.append (NumberBackslashes * 2 , L' \\ ' );
107
+ break ;
108
+ }
109
+ else if (*it == L' "' )
110
+ {
111
+ //
112
+ // Escape all backslashes and the following
113
+ // double quotation mark.
114
+ //
115
+
116
+ result.append (NumberBackslashes * 2 + 1 , L' \\ ' );
117
+ result.push_back (*it);
118
+ }
119
+ else
120
+ {
121
+ //
122
+ // Backslashes aren't special here.
123
+ //
124
+
125
+ result.append (NumberBackslashes, L' \\ ' );
126
+ result.push_back (*it);
127
+ }
128
+ }
129
+
130
+ result.push_back (L' "' );
131
+
132
+ return result;
133
+ }
134
+ #endif
135
+
78
136
int run (
79
137
const std::string &what,
80
138
const std::vector<std::string> &argv,
@@ -112,13 +170,13 @@ int run(
112
170
return run (new_argv[0 ], new_argv, " " , " " , " " );
113
171
}
114
172
115
- // unicode version of the arguments
173
+ // unicode and whitespace-quoted version of the arguments
116
174
std::vector<std::wstring> wargv;
117
175
118
176
wargv.resize (argv.size ());
119
177
120
178
for (std::size_t i=0 ; i<argv.size (); i++)
121
- wargv[i]=widen (argv[i]);
179
+ wargv[i]=quote_windows_arg ( widen (argv[i]) );
122
180
123
181
std::vector<const wchar_t *> _argv (argv.size ()+1 );
124
182
@@ -127,10 +185,6 @@ int run(
127
185
128
186
_argv[argv.size ()]=NULL ;
129
187
130
- // warning: the arguments may still need escaping,
131
- // as windows will concatenate the argv strings back together,
132
- // separating them with spaces
133
-
134
188
std::wstring wide_what=widen (what);
135
189
int status=_wspawnvp (_P_WAIT, wide_what.c_str (), _argv.data ());
136
190
return status;
0 commit comments