summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmSystemTools.cxx274
-rw-r--r--Source/cmSystemTools.h10
-rw-r--r--Source/cmake.cxx35
3 files changed, 313 insertions, 6 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index f4fd0da..3717a90 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -74,6 +74,19 @@ bool cmSystemTools::s_DisableRunCommandOutput = false;
bool cmSystemTools::s_ErrorOccured = false;
bool cmSystemTools::s_DisableMessages = false;
+std::string cmSystemTools::s_Windows9xComspecSubstitute = "command.com";
+void cmSystemTools::SetWindows9xComspecSubstitute(const char* str)
+{
+ if ( str )
+ {
+ cmSystemTools::s_Windows9xComspecSubstitute = str;
+ }
+}
+const char* cmSystemTools::GetWindows9xComspecSubstitute()
+{
+ return cmSystemTools::s_Windows9xComspecSubstitute.c_str();
+}
+
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, bool&, void*);
void* cmSystemTools::s_ErrorCallbackClientData = 0;
@@ -1004,7 +1017,7 @@ void cmSystemTools::Message(const char* m1, const char *title)
}
else
{
- std::cerr << m1 << std::endl;
+ std::cerr << m1 << std::endl << std::flush;
}
}
@@ -1249,6 +1262,250 @@ bool cmSystemTools::RunCommand(const char* command,
}
#if defined(WIN32) && !defined(__CYGWIN__)
+// Code from a Borland web site with the following explaination :
+/* In this article, I will explain how to spawn a console application
+ * and redirect its standard input/output using anonymous pipes. An
+ * anonymous pipe is a pipe that goes only in one direction (read
+ * pipe, write pipe, etc.). Maybe you are asking, "why would I ever
+ * need to do this sort of thing?" One example would be a Windows
+ * telnet server, where you spawn a shell and listen on a port and
+ * send and receive data between the shell and the socket
+ * client. (Windows does not really have a built-in remote
+ * shell). First, we should talk about pipes. A pipe in Windows is
+ * simply a method of communication, often between process. The SDK
+ * defines a pipe as "a communication conduit with two ends;
+ a process
+ * with a handle to one end can communicate with a process having a
+ * handle to the other end." In our case, we are using "anonymous"
+ * pipes, one-way pipes that "transfer data between a parent process
+ * and a child process or between two child processes of the same
+ * parent process." It's easiest to imagine a pipe as its namesake. An
+ * actual pipe running between processes that can carry data. We are
+ * using anonymous pipes because the console app we are spawning is a
+ * child process. We use the CreatePipe function which will create an
+ * anonymous pipe and return a read handle and a write handle. We will
+ * create two pipes, on for stdin and one for stdout. We will then
+ * monitor the read end of the stdout pipe to check for display on our
+ * child process. Every time there is something availabe for reading,
+ * we will display it in our app. Consequently, we check for input in
+ * our app and send it off to the write end of the stdin pipe. */
+
+inline bool IsWinNT()
+//check if we're running NT
+{
+ OSVERSIONINFO osv;
+ osv.dwOSVersionInfoSize = sizeof(osv);
+ GetVersionEx(&osv);
+ return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+
+void DisplayErrorMessage()
+{
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ // Process any inserts in lpMsgBuf.
+ // ...
+ // Display the string.
+ MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+}
+
+//---------------------------------------------------------------------------
+bool WindowsRunCommand(const char* command, const char* dir,
+ std::string& output, int& retVal, bool verbose)
+{
+ //verbose = true;
+ std::cerr << std::endl
+ << "WindowsRunCommand(" << command << ")" << std::endl
+ << std::flush;
+ const int BUFFER_SIZE = 4096;
+ char buf[BUFFER_SIZE];
+
+//i/o buffer
+ STARTUPINFO si;
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_DESCRIPTOR sd;
+
+//security information for pipes
+ PROCESS_INFORMATION pi;
+ HANDLE newstdin,newstdout,read_stdout,write_stdin;
+
+//pipe handles
+ if (IsWinNT())
+//initialize security descriptor (Windows NT)
+ {
+ InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
+ SetSecurityDescriptorDacl(&sd, true, NULL, false);
+ sa.lpSecurityDescriptor = &sd;
+
+ }
+ else sa.lpSecurityDescriptor = NULL;
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = true;
+
+//allow inheritable handles
+ if (!CreatePipe(&newstdin,&write_stdin,&sa,0))
+//create stdin pipe
+ {
+ std::cerr << "CreatePipe" << std::endl;
+ return false;
+
+ }
+ if (!CreatePipe(&read_stdout,&newstdout,&sa,0))
+//create stdout pipe
+ {
+ std::cerr << "CreatePipe" << std::endl;
+ CloseHandle(newstdin);
+ CloseHandle(write_stdin);
+ return false;
+
+ }
+ GetStartupInfo(&si);
+
+//set startupinfo for the spawned process
+ /* The dwFlags member tells CreateProcess how to make the
+ * process. STARTF_USESTDHANDLES validates the hStd*
+ * members. STARTF_USESHOWWINDOW validates the wShowWindow
+ * member. */
+
+ si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+ si.hStdOutput = newstdout;
+ si.hStdError = newstdout;
+
+//set the new handles for the child process si.hStdInput = newstdin;
+ char* commandAndArgs = strcpy(new char[strlen(command)+1], command);
+ if (!CreateProcess(NULL,commandAndArgs,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,
+ NULL,dir,&si,&pi))
+ {
+ std::cerr << "CreateProcess failed " << commandAndArgs << std::endl;
+ CloseHandle(newstdin);
+ CloseHandle(newstdout);
+ CloseHandle(read_stdout);
+ CloseHandle(write_stdin);
+ delete [] commandAndArgs;
+ return false;
+
+ }
+ delete [] commandAndArgs;
+ unsigned long exit=0;
+
+//process exit code unsigned
+ unsigned long bread;
+
+//bytes read unsigned
+ unsigned long avail;
+
+//bytes available
+ memset(buf, 0, sizeof(buf));
+ for(;;)
+//main program loop
+ {
+ Sleep(10);
+ //std::cout << "Check for process..." << std::endl;
+ GetExitCodeProcess(pi.hProcess,&exit);
+
+//while the process is running
+ if (exit != STILL_ACTIVE) break;
+
+//check to see if there is any data to read from stdout
+ //std::cout << "Peek for data..." << std::endl;
+ PeekNamedPipe(read_stdout,buf,1023,&bread,&avail,NULL);
+ if (bread != 0)
+ {
+ memset(buf, 0, sizeof(buf));
+ if (avail > 1023)
+ {
+ while (bread >= 1023)
+ {
+ //std::cout << "Read data..." << std::endl;
+ ReadFile(read_stdout,buf,1023,&bread,NULL);
+
+//read the stdout pipe
+ printf("%s",buf);
+ memset(buf, 0, sizeof(buf));
+
+ }
+
+ }
+ else
+ {
+ ReadFile(read_stdout,buf,1023,&bread,NULL);
+ output += buf;
+ output += "\n";
+ if(verbose)
+ {
+ std::cerr << verbose << " [{" << buf << "}]"
+ << std::endl << std::flush;
+
+ }
+
+ }
+
+ }
+
+ }
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ CloseHandle(newstdin);
+
+//clean stuff up
+ CloseHandle(newstdout);
+ CloseHandle(read_stdout);
+ CloseHandle(write_stdin);
+ retVal = exit;
+ std::cerr << std::endl << "End of WindowsRunCommand(" << command << ")" << std::endl << std::flush;
+ return true;
+
+}
+
+#include "cmWin32ProcessExecution.h"
+// use this for shell commands like echo and dir
+bool RunCommandViaWin32(const char* command,
+ const char* dir,
+ std::string& output,
+ int& retVal,
+ bool verbose)
+{
+ if ( ! command )
+ {
+ cmSystemTools::Error("No command specified");
+ return false;
+ }
+ //std::cout << "Command: " << command << std::endl;
+ if ( dir )
+ {
+ //std::cout << "Dir: " << dir << std::endl;
+ }
+
+ cmWin32ProcessExecution resProc;
+ if ( cmSystemTools::GetWindows9xComspecSubstitute() )
+ {
+ resProc.SetConsoleSpawn(cmSystemTools::GetWindows9xComspecSubstitute() );
+ }
+ if ( !resProc.StartProcess(command, dir, verbose) )
+ {
+ std::cout << "Problem starting command" << std::endl;
+ return false;
+ }
+ resProc.Wait(INFINITE);
+ output = resProc.GetOutput();
+ retVal = resProc.GetExitValue();
+ return true;
+}
+
// use this for shell commands like echo and dir
bool RunCommandViaSystem(const char* command,
const char* dir,
@@ -1256,6 +1513,8 @@ bool RunCommandViaSystem(const char* command,
int& retVal,
bool verbose)
{
+ std::cout << "@@ " << command << std::endl;
+
const int BUFFER_SIZE = 4096;
char buffer[BUFFER_SIZE];
std::string commandInDir;
@@ -1366,8 +1625,13 @@ bool cmSystemTools::RunCommand(const char* command,
}
shortCmd += " ";
shortCmd += args;
- return RunCommandViaSystem(shortCmd.c_str(), dir,
- output, retVal, verbose);
+
+ //return RunCommandViaSystem(shortCmd.c_str(), dir,
+ // output, retVal, verbose);
+ //return WindowsRunCommand(shortCmd.c_str(), dir,
+ //output, retVal, verbose);
+ return RunCommandViaWin32(shortCmd.c_str(), dir,
+ output, retVal, verbose);
}
else
{
@@ -1377,7 +1641,9 @@ bool cmSystemTools::RunCommand(const char* command,
}
}
// if there is only one set of quotes or no quotes then just run the command
- return RunCommandViaSystem(command, dir, output, retVal, verbose);
+ //return RunCommandViaSystem(command, dir, output, retVal, verbose);
+ //return WindowsRunCommand(command, dir, output, retVal, verbose);
+ return RunCommandViaWin32(command, dir, output, retVal, verbose);
#else
// if only popen worked on windows.....
std::string commandInDir;
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 716c2cf..7ef4a4d 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -311,6 +311,14 @@ public:
*/
static e_FileFormat GetFileFormat(const char* ext);
+ /**
+ * On Windows 9x we need a comspec (command.com) substitute to run
+ * programs correctly. This string has to be constant available
+ * through the running of program. This method does not create a copy.
+ */
+ static void SetWindows9xComspecSubstitute(const char*);
+ static const char* GetWindows9xComspecSubstitute();
+
protected:
// these two functions can be called from ConvertToOutputPath
/**
@@ -333,6 +341,8 @@ private:
static bool s_DisableRunCommandOutput;
static ErrorCallback s_ErrorCallback;
static void* s_ErrorCallbackClientData;
+
+ static std::string s_Windows9xComspecSubstitute;
};
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 684116a..887091e 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -28,6 +28,7 @@
#include "cmGlobalVisualStudio7Generator.h"
#include "cmGlobalBorlandMakefileGenerator.h"
#include "cmGlobalNMakeMakefileGenerator.h"
+#include "cmWin32ProcessExecution.h"
#else
#include "cmGlobalUnixMakefileGenerator.h"
#endif
@@ -430,6 +431,11 @@ int cmake::AddCMakePaths(const char *arg0)
this->m_CacheManager->AddCacheEntry
("CMAKE_ROOT", cMakeRoot.c_str(),
"Path to CMake installation.", cmCacheManager::INTERNAL);
+
+#ifdef _WIN32
+ cmSystemTools::SetWindows9xComspecSubstitute(
+ (cMakeSelf + " -E comspec").c_str());
+#endif
return 1;
}
@@ -448,12 +454,14 @@ void CMakeCommandUsage(const char* program)
<< "Available commands: \n"
<< " chdir dir cmd [args]... - run command in a given directory\n"
<< " copy file destination - copy file to destination (either file or directory)\n"
+ << " echo [string]... - displays arguments as text\n"
<< " remove file1 file2 ... - remove the file(s)\n"
<< " time command [args] ... - run command and return elapsed time\n";
#if defined(_WIN32) && !defined(__CYGWIN__)
errorStream
<< " write_regv key value - write registry value\n"
- << " delete_regv key - delete registry value\n";
+ << " delete_regv key - delete registry value\n"
+ << " comspec - on windows 9x use this for RunCommand\n";
#endif
cmSystemTools::Error(errorStream.str().c_str());
@@ -470,6 +478,18 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
return cmSystemTools::GetErrorOccuredFlag();
}
+ // Echo string
+ else if (args[1] == "echo" )
+ {
+ int cc;
+ for ( cc = 2; cc < args.size(); cc ++ )
+ {
+ std::cout << args[cc] << " ";
+ }
+ std::cout << std::endl;
+ return 0;
+ }
+
// Remove file
else if (args[1] == "remove" && args.size() > 2)
{
@@ -522,7 +542,7 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
}
// Clock command
- else if (args[1] == "chdir" && args.size() > 2)
+ else if (args[1] == "chdir" && args.size() == 4)
{
std::string directory = args[2];
std::string command = args[3];
@@ -557,6 +577,17 @@ int cmake::CMakeCommand(std::vector<std::string>& args)
{
return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
}
+ // Remove file
+ else if (args[1] == "comspec" && args.size() > 2)
+ {
+ int cc;
+ std::string command = args[2];
+ for ( cc = 3; cc < args.size(); cc ++ )
+ {
+ command += " " + args[cc];
+ }
+ return cmWin32ProcessExecution::Windows9xHack(command.c_str());
+ }
#endif
}