@@ -164,32 +164,35 @@ static std::string cmdFileName(std::string f)
164164 return f;
165165}
166166
167- static bool executeShellCommand ( std::string exe, const std::string &args, std::string *output )
167+ static std::vector<std:: string> split ( const std::string &str, const std::string &sep= " " )
168168{
169- output-> clear () ;
170-
171- # ifdef _WIN32
172- // Extra quoutes are needed in windows if filename has space
173- if (exe .find (" " ) != std::string::npos)
174- exe = " \" " + exe + " \" " ;
175- const std::string cmd = exe + " " + args + " 2>&1 " ;
176- std::unique_ptr<FILE, decltype (&_pclose)> pipe ( _popen (cmd. c_str (), " r " ), _pclose);
177- # else
178- const std::string cmd = exe + " " + args + " 2>&1 " ;
179- std::unique_ptr<FILE, decltype (&pclose)> pipe ( popen (cmd. c_str (), " r " ), pclose);
180- # endif
181- if (!pipe)
182- return false ;
183- char buffer[ 1024 ] ;
184- while ( fgets (buffer, sizeof (buffer), pipe. get ()) != nullptr )
185- *output += buffer;
186- return true ;
169+ std::vector<std::string> ret ;
170+ for (std::string::size_type startPos = 0U ; startPos < str. size ();) {
171+ std::string::size_type endPos;
172+ if (str[startPos] == ' \" ' ) {
173+ endPos = str .find (" \" " , startPos + 1 );
174+ if (endPos < str. size ())
175+ endPos++ ;
176+ } else {
177+ endPos = str. find (sep, startPos + 1 );
178+ }
179+ if (endPos == std::string::npos) {
180+ ret. push_back (str. substr (startPos));
181+ break ;
182+ }
183+ ret. push_back (str. substr (startPos, endPos - startPos)) ;
184+ startPos = str. find_first_not_of (sep, endPos);
185+ }
186+ return ret ;
187187}
188188
189189static std::string executeAddon (const AddonInfo &addonInfo,
190190 const std::string &defaultPythonExe,
191- const std::string &dumpFile)
191+ const std::string &dumpFile,
192+ std::function<bool (std::string,std::vector<std::string>,std::string,std::string*)> executeCommand)
192193{
194+ const std::string redirect = " 2>&1" ;
195+
193196 std::string pythonExe;
194197
195198 if (!addonInfo.python .empty ())
@@ -204,7 +207,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
204207#endif
205208 for (int i = 0 ; i < 2 ; ++i) {
206209 std::string out;
207- if (executeShellCommand (p[i], " --version" , &out) && out.compare (0 , 7 , " Python " ) == 0 && std::isdigit (out[7 ])) {
210+ if (executeCommand (p[i], split ( " --version" ), redirect , &out) && out.compare (0 , 7 , " Python " ) == 0 && std::isdigit (out[7 ])) {
208211 pythonExe = p[i];
209212 break ;
210213 }
@@ -215,7 +218,7 @@ static std::string executeAddon(const AddonInfo &addonInfo,
215218
216219 const std::string args = cmdFileName (addonInfo.scriptFile ) + " --cli" + addonInfo.args + " " + cmdFileName (dumpFile);
217220 std::string result;
218- if (!executeShellCommand (pythonExe, args, &result))
221+ if (!executeCommand (pythonExe, split ( args), redirect , &result))
219222 throw InternalError (nullptr , " Failed to execute addon (command: '" + pythonExe + " " + args + " ')" );
220223
221224 // Validate output..
@@ -230,48 +233,16 @@ static std::string executeAddon(const AddonInfo &addonInfo,
230233 return result;
231234}
232235
233- static std::vector<std::string> split (const std::string &str, const std::string &sep)
234- {
235- std::vector<std::string> ret;
236- for (std::string::size_type startPos = 0U ; startPos < str.size ();) {
237- std::string::size_type endPos;
238- if (str[startPos] == ' \" ' ) {
239- endPos = str.find (" \" " , startPos + 1 );
240- if (endPos < str.size ())
241- endPos++;
242- } else {
243- endPos = str.find (sep, startPos + 1 );
244- }
245- if (endPos == std::string::npos) {
246- ret.push_back (str.substr (startPos));
247- break ;
248- }
249- ret.push_back (str.substr (startPos, endPos - startPos));
250- startPos = str.find_first_not_of (sep, endPos);
251- }
252- return ret;
253- }
254-
255- static std::pair<bool ,std::string> executeCommand (const std::string &cmd)
256- {
257- #ifdef _WIN32
258- std::unique_ptr<FILE, decltype (&_pclose)> pipe (_popen (cmd.c_str (), " r" ), _pclose);
259- #else
260- std::unique_ptr<FILE, decltype (&pclose)> pipe (popen (cmd.c_str (), " r" ), pclose);
261- #endif
262-
263- if (!pipe)
264- return std::pair<bool , std::string>(false , " " );
265-
266- char buffer[1024 ];
267- std::string result;
268- while (fgets (buffer, sizeof (buffer), pipe.get ()) != nullptr )
269- result += buffer;
270- return std::pair<bool , std::string>(true , result);
271- }
272-
273- CppCheck::CppCheck (ErrorLogger &errorLogger, bool useGlobalSuppressions)
274- : mErrorLogger(errorLogger), mExitCode(0 ), mSuppressInternalErrorFound(false ), mUseGlobalSuppressions(useGlobalSuppressions), mTooManyConfigs(false ), mSimplify(true )
236+ CppCheck::CppCheck (ErrorLogger &errorLogger,
237+ bool useGlobalSuppressions,
238+ std::function<bool (std::string,std::vector<std::string>,std::string,std::string*)> executeCommand)
239+ : mErrorLogger(errorLogger)
240+ , mExitCode(0 )
241+ , mSuppressInternalErrorFound(false )
242+ , mUseGlobalSuppressions(useGlobalSuppressions)
243+ , mTooManyConfigs(false )
244+ , mSimplify(true )
245+ , mExecuteCommand(executeCommand)
275246{
276247}
277248
@@ -349,14 +320,18 @@ unsigned int CppCheck::check(const std::string &path)
349320 const std::string analyzerInfo = mSettings .buildDir .empty () ? std::string () : AnalyzerInformation::getAnalyzerInfoFile (mSettings .buildDir , path, " " );
350321 const std::string clangcmd = analyzerInfo + " .clang-cmd" ;
351322 const std::string clangStderr = analyzerInfo + " .clang-stderr" ;
352-
353- const std::string cmd1 = " clang -v -fsyntax-only " + lang + " " + tempFile + " 2>&1" ;
354- const std::pair<bool , std::string> &result1 = executeCommand (cmd1);
355- if (!result1.first || result1.second .find (" -cc1 " ) == std::string::npos) {
356- mErrorLogger .reportOut (" Failed to execute '" + cmd1 + " ':" + result1.second );
323+ #ifdef _WIN32
324+ const std::string exe = " clang.exe" ;
325+ #else
326+ const std::string exe = " clang" ;
327+ #endif
328+ const std::string args1 = " -v -fsyntax-only " + lang + " " + tempFile;
329+ std::string output1;
330+ if (!mExecuteCommand (exe, split (args1), " 2>&1" , &output1) || output1.find (" -cc1 " ) == std::string::npos) {
331+ mErrorLogger .reportOut (" Failed to execute '" + exe + " ':" + output1);
357332 return 0 ;
358333 }
359- std::istringstream details (result1. second );
334+ std::istringstream details (output1 );
360335 std::string line;
361336 std::string flags (lang + " " );
362337 while (std::getline (details, line)) {
@@ -374,15 +349,16 @@ unsigned int CppCheck::check(const std::string &path)
374349 for (const std::string &i: mSettings .includePaths )
375350 flags += " -I" + i + " " ;
376351
377- const std::string cmd = " clang -cc1 -ast-dump " + flags + path + (analyzerInfo.empty () ? std::string (" 2>&1" ) : (" 2> " + clangStderr));
352+ const std::string args2 = " -cc1 -ast-dump " + flags + path;
353+ const std::string redirect2 = analyzerInfo.empty () ? std::string (" 2>&1" ) : (" 2> " + clangStderr);
378354 if (!mSettings .buildDir .empty ()) {
379355 std::ofstream fout (clangcmd);
380- fout << cmd << std::endl;
356+ fout << exe << " " << args2 << " " << redirect2 << std::endl;
381357 }
382358
383- const std::pair< bool , std:: string> &result2 = executeCommand (cmd) ;
384- if (!result2. first || result2. second .find (" TranslationUnitDecl" ) == std::string::npos) {
385- std::cerr << " Failed to execute '" + cmd + " '" << std::endl;
359+ std::string output2 ;
360+ if (!mExecuteCommand (exe, split (args2),redirect2,&output2) || output2 .find (" TranslationUnitDecl" ) == std::string::npos) {
361+ std::cerr << " Failed to execute '" << exe << " " << args2 << " " << redirect2 << " '" << std::endl;
386362 return 0 ;
387363 }
388364
@@ -395,7 +371,7 @@ unsigned int CppCheck::check(const std::string &path)
395371 if (reportClangErrors (fin, reportError))
396372 return 0 ;
397373 } else {
398- std::istringstream istr (result2. second );
374+ std::istringstream istr (output2 );
399375 auto reportError = [this ](const ErrorLogger::ErrorMessage& errorMessage) {
400376 reportErr (errorMessage);
401377 };
@@ -404,7 +380,7 @@ unsigned int CppCheck::check(const std::string &path)
404380 }
405381
406382 // std::cout << "Checking Clang ast dump:\n" << result2.second << std::endl;
407- std::istringstream ast (result2. second );
383+ std::istringstream ast (output2 );
408384 Tokenizer tokenizer (&mSettings , this );
409385 tokenizer.list .appendFileIfNew (path);
410386 clangimport::parseClangAstDump (&tokenizer, ast);
@@ -427,7 +403,7 @@ unsigned int CppCheck::check(const std::string &path, const std::string &content
427403
428404unsigned int CppCheck::check (const ImportProject::FileSettings &fs)
429405{
430- CppCheck temp (mErrorLogger , mUseGlobalSuppressions );
406+ CppCheck temp (mErrorLogger , mUseGlobalSuppressions , mExecuteCommand );
431407 temp.mSettings = mSettings ;
432408 if (!temp.mSettings .userDefines .empty ())
433409 temp.mSettings .userDefines += ' ;' ;
@@ -849,7 +825,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
849825 continue ;
850826 }
851827 const std::string results =
852- executeAddon (addonInfo, mSettings .addonPython , dumpFile);
828+ executeAddon (addonInfo, mSettings .addonPython , dumpFile, mExecuteCommand );
853829 std::istringstream istr (results);
854830 std::string line;
855831
@@ -1441,15 +1417,21 @@ void CppCheck::analyseClangTidy(const ImportProject::FileSettings &fileSettings)
14411417 pos += 3 ;
14421418 }
14431419
1444- const std::string cmd = " clang-tidy -quiet -checks=*,-clang-analyzer-*,-llvm* \" " + fileSettings.filename + " \" -- " + allIncludes + allDefines;
1445- std::pair<bool , std::string> result = executeCommand (cmd);
1446- if (!result.first ) {
1447- std::cerr << " Failed to execute '" + cmd + " '" << std::endl;
1420+ #ifdef _WIN32
1421+ const char exe[] = " clang-tidy.exe" ;
1422+ #else
1423+ const char exe[] = " clang-tidy" ;
1424+ #endif
1425+
1426+ const std::string args = " -quiet -checks=*,-clang-analyzer-*,-llvm* \" " + fileSettings.filename + " \" -- " + allIncludes + allDefines;
1427+ std::string output;
1428+ if (!mExecuteCommand (exe, split (args), " " , &output)) {
1429+ std::cerr << " Failed to execute '" << exe << " '" << std::endl;
14481430 return ;
14491431 }
14501432
14511433 // parse output and create error messages
1452- std::istringstream istr (result. second );
1434+ std::istringstream istr (output );
14531435 std::string line;
14541436
14551437 if (!mSettings .buildDir .empty ()) {
0 commit comments