CMake/Source/cmSystemTools.cxx

1704 lines
43 KiB
C++
Raw Normal View History

2001-01-11 22:55:47 +03:00
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
2002-01-21 23:30:43 +03:00
Copyright (c) 2002 Insight Consortium. All rights reserved.
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
2001-01-11 22:55:47 +03:00
2002-01-21 23:30:43 +03:00
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
2001-01-11 22:55:47 +03:00
=========================================================================*/
2001-09-28 00:50:59 +04:00
#include "cmSystemTools.h"
#include "errno.h"
2001-02-23 03:24:43 +03:00
#include "stdio.h"
#include <sys/stat.h>
#include "cmRegularExpression.h"
2001-04-26 18:49:12 +04:00
#include <ctype.h>
2001-06-21 20:01:18 +04:00
#include "cmDirectory.h"
2001-09-28 00:50:59 +04:00
// support for realpath call
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/wait.h>
2001-09-28 00:50:59 +04:00
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
#include <string.h>
#include <windows.h>
#include <direct.h>
2001-02-23 03:24:43 +03:00
#define _unlink unlink
inline int Mkdir(const char* dir)
{
return _mkdir(dir);
}
inline const char* Getcwd(char* buf, unsigned int len)
{
return _getcwd(buf, len);
}
inline int Chdir(const char* dir)
{
#if defined(__BORLANDC__)
return chdir(dir);
#else
return _chdir(dir);
#endif
}
#else
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
inline int Mkdir(const char* dir)
{
2001-02-27 20:00:36 +03:00
return mkdir(dir, 00777);
}
inline const char* Getcwd(char* buf, unsigned int len)
{
return getcwd(buf, len);
}
inline int Chdir(const char* dir)
{
return chdir(dir);
}
#endif
bool cmSystemTools::s_DisableRunCommandOutput = false;
2001-02-23 03:24:43 +03:00
bool cmSystemTools::s_ErrorOccured = false;
bool cmSystemTools::s_DisableMessages = false;
2001-02-23 03:24:43 +03:00
2001-10-29 18:19:34 +03:00
void (*cmSystemTools::s_ErrorCallback)(const char*, const char*, bool&);
// adds the elements of the env variable path to the arg passed in
void cmSystemTools::GetPath(std::vector<std::string>& path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
const char* pathSep = ";";
#else
const char* pathSep = ":";
#endif
std::string pathEnv = getenv("PATH");
// A hack to make the below algorithm work.
if(pathEnv[pathEnv.length()-1] != ':')
{
pathEnv += pathSep;
}
std::string::size_type start =0;
bool done = false;
while(!done)
{
std::string::size_type endpos = pathEnv.find(pathSep, start);
if(endpos != std::string::npos)
{
path.push_back(pathEnv.substr(start, endpos-start));
start = endpos+1;
}
else
{
done = true;
}
}
for(std::vector<std::string>::iterator i = path.begin();
i != path.end(); ++i)
{
cmSystemTools::ConvertToUnixSlashes(*i);
}
}
const char* cmSystemTools::GetExecutableExtension()
{
#if defined(_WIN32) || defined(__CYGWIN__)
return ".exe";
#else
return "";
#endif
}
bool cmSystemTools::MakeDirectory(const char* path)
{
if(cmSystemTools::FileExists(path))
{
return true;
}
std::string dir = path;
if(dir.size() == 0)
{
return false;
}
cmSystemTools::ConvertToUnixSlashes(dir);
std::string::size_type pos = dir.find(':');
if(pos == std::string::npos)
{
pos = 0;
}
std::string topdir;
while((pos = dir.find('/', pos)) != std::string::npos)
{
topdir = dir.substr(0, pos);
Mkdir(topdir.c_str());
pos++;
}
if(dir[dir.size()-1] == '/')
{
topdir = dir.substr(0, dir.size());
}
else
{
topdir = dir;
}
if(Mkdir(topdir.c_str()) != 0)
{
// There is a bug in the Borland Run time library which makes MKDIR
// return EACCES when it should return EEXISTS
// if it is some other error besides directory exists
// then return false
if( (errno != EEXIST)
#ifdef __BORLANDC__
&& (errno != EACCES)
#endif
)
{
cmSystemTools::Error("Faild to create directory:", path);
return false;
}
}
return true;
}
// replace replace with with as many times as it shows up in source.
// write the result into source.
void cmSystemTools::ReplaceString(std::string& source,
const char* replace,
const char* with)
{
2002-02-26 02:14:01 +03:00
std::string::size_type lengthReplace = strlen(replace);
2000-09-01 18:43:10 +04:00
std::string rest;
2002-02-26 02:14:01 +03:00
std::string::size_type start = source.find(replace);
while(start != std::string::npos)
{
2000-09-01 18:43:10 +04:00
rest = source.substr(start+lengthReplace);
source = source.substr(0, start);
source += with;
2000-09-01 18:43:10 +04:00
source += rest;
start = source.find(replace, start + lengthReplace );
}
}
2001-05-17 23:48:32 +04:00
#if defined(_WIN32) && !defined(__CYGWIN__)
// Get the data of key value.
// Example :
// HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
// => will return the data of the "default" value of the key
// HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
// => will return the data of the "Root" value of the key
bool ReadAValue(std::string &res, const char *key)
{
// find the primary key
std::string primary = key;
std::string second;
std::string valuename;
size_t start = primary.find("\\");
if (start == std::string::npos)
{
return false;
}
size_t valuenamepos = primary.find(";");
if (valuenamepos != std::string::npos)
{
valuename = primary.substr(valuenamepos+1);
}
second = primary.substr(start+1, valuenamepos-start-1);
primary = primary.substr(0, start);
HKEY primaryKey;
if (primary == "HKEY_CURRENT_USER")
{
primaryKey = HKEY_CURRENT_USER;
}
if (primary == "HKEY_CURRENT_CONFIG")
{
primaryKey = HKEY_CURRENT_CONFIG;
}
if (primary == "HKEY_CLASSES_ROOT")
{
primaryKey = HKEY_CLASSES_ROOT;
}
if (primary == "HKEY_LOCAL_MACHINE")
{
primaryKey = HKEY_LOCAL_MACHINE;
}
if (primary == "HKEY_USERS")
{
primaryKey = HKEY_USERS;
}
HKEY hKey;
if(RegOpenKeyEx(primaryKey, second.c_str(),
0, KEY_READ, &hKey) != ERROR_SUCCESS)
{
return false;
}
else
{
DWORD dwType, dwSize;
dwSize = 1023;
char data[1024];
if(RegQueryValueEx(hKey, (LPTSTR)valuename.c_str(), NULL, &dwType,
(BYTE *)data, &dwSize) == ERROR_SUCCESS)
{
if (dwType == REG_SZ)
{
res = data;
return true;
}
}
}
return false;
}
#endif
// replace replace with with as many times as it shows up in source.
// write the result into source.
void cmSystemTools::ExpandRegistryValues(std::string& source)
{
2001-05-17 23:48:32 +04:00
#if defined(_WIN32) && !defined(__CYGWIN__)
// Regular expression to match anything inside [...] that begins in HKEY.
// Note that there is a special rule for regular expressions to match a
// close square-bracket inside a list delimited by square brackets.
// The "[^]]" part of this expression will match any character except
// a close square-bracket. The ']' character must be the first in the
// list of characters inside the [^...] block of the expression.
cmRegularExpression regEntry("\\[(HKEY[^]]*)\\]");
// check for black line or comment
while (regEntry.find(source))
{
// the arguments are the second match
std::string key = regEntry.match(1);
std::string val;
if (ReadAValue(val,key.c_str()))
{
std::string reg = "[";
reg += key + "]";
cmSystemTools::ReplaceString(source, reg.c_str(), val.c_str());
}
else
{
std::string reg = "[";
reg += key + "]";
cmSystemTools::ReplaceString(source, reg.c_str(), "/registry");
}
}
#endif
}
2001-08-28 22:55:14 +04:00
2001-06-22 18:21:08 +04:00
std::string cmSystemTools::EscapeQuotes(const char* str)
{
std::string result = "";
for(const char* ch = str; *ch != '\0'; ++ch)
{
if(*ch == '"')
{
result += '\\';
}
result += *ch;
}
return result;
}
2001-11-22 01:45:01 +03:00
bool cmSystemTools::SameFile(const char* file1, const char* file2)
{
struct stat fileStat1, fileStat2;
if (stat(file1, &fileStat1) == 0 && stat(file2, &fileStat2) == 0)
{
// see if the files are the same file
// check the device inode and size
if(fileStat2.st_dev == fileStat1.st_dev &&
fileStat2.st_ino == fileStat1.st_ino &&
fileStat2.st_size == fileStat1.st_size
)
{
return true;
}
}
return false;
}
// return true if the file exists
bool cmSystemTools::FileExists(const char* filename)
{
struct stat fs;
if (stat(filename, &fs) != 0)
2001-01-11 22:47:38 +03:00
{
return false;
2001-01-11 22:47:38 +03:00
}
else
2001-01-11 22:47:38 +03:00
{
return true;
2001-01-11 22:47:38 +03:00
}
}
// Return a capitalized string (i.e the first letter is uppercased, all other
// are lowercased)
std::string cmSystemTools::Capitalized(const std::string& s)
{
std::string n;
n.resize(s.size());
n[0] = toupper(s[0]);
for (size_t i = 1; i < s.size(); i++)
{
n[i] = tolower(s[i]);
}
return n;
}
2001-09-13 01:09:02 +04:00
// Return a lower case string
std::string cmSystemTools::LowerCase(const std::string& s)
{
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++)
{
n[i] = tolower(s[i]);
}
return n;
}
2001-11-15 02:12:22 +03:00
// Return a lower case string
std::string cmSystemTools::UpperCase(const std::string& s)
{
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++)
{
n[i] = toupper(s[i]);
}
return n;
}
2001-09-13 01:09:02 +04:00
2002-02-26 02:14:01 +03:00
// convert windows slashes to unix slashes
void cmSystemTools::ConvertToUnixSlashes(std::string& path)
{
std::string::size_type pos = 0;
while((pos = path.find('\\', pos)) != std::string::npos)
{
path[pos] = '/';
pos++;
}
// remove any trailing slash
if(path.size() && path[path.size()-1] == '/')
{
path = path.substr(0, path.size()-1);
}
2001-12-07 00:50:54 +03:00
// if there is a tilda ~ then replace it with HOME
if(path.find("~") == 0)
{
if (getenv("HOME"))
{
path = std::string(getenv("HOME")) + path.substr(1);
}
}
// if there is a /tmp_mnt in a path get rid of it!
// stupid sgi's
if(path.find("/tmp_mnt") == 0)
{
path = path.substr(8);
}
}
// change // to /, and escape any spaces in the path
std::string cmSystemTools::ConvertToUnixOutputPath(const char* path)
{
std::string ret = path;
2002-02-25 18:47:56 +03:00
// remove // except at the beginning might be a cygwin drive
std::string::size_type pos = 1;
while((pos = ret.find("//", pos)) != std::string::npos)
{
ret.erase(pos, 1);
}
// now escape spaces if there is a space in the path
if(ret.find(" ") != std::string::npos)
{
std::string result = "";
2002-02-22 23:40:44 +03:00
char lastch = 1;
for(const char* ch = ret.c_str(); *ch != '\0'; ++ch)
{
2002-02-22 23:40:44 +03:00
// if it is already escaped then don't try to escape it again
if(*ch == ' ' && lastch != '\\')
{
result += '\\';
}
result += *ch;
2002-02-22 23:40:44 +03:00
lastch = *ch;
}
ret = result;
}
return ret;
}
std::string cmSystemTools::EscapeSpaces(const char* str)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
std::string result;
// if there are spaces
std::string temp = str;
if (temp.find(" ") != std::string::npos &&
temp.find("\"")==std::string::npos)
{
result = "\"";
result += str;
result += "\"";
return result;
}
return str;
#else
std::string result = "";
for(const char* ch = str; *ch != '\0'; ++ch)
{
if(*ch == ' ')
{
result += '\\';
}
result += *ch;
}
return result;
#endif
}
std::string cmSystemTools::ConvertToOutputPath(const char* path)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
return cmSystemTools::ConvertToWindowsOutputPath(path);
#else
return cmSystemTools::ConvertToUnixOutputPath(path);
#endif
}
// remove double slashes not at the start
std::string cmSystemTools::ConvertToWindowsOutputPath(const char* path)
{
std::string ret = path;
std::string::size_type pos = 0;
// first convert all of the slashes
while((pos = ret.find('/', pos)) != std::string::npos)
{
ret[pos] = '\\';
pos++;
}
// check for really small paths
if(ret.size() < 2)
{
return ret;
}
// now clean up a bit and remove double slashes
// Only if it is not the first position in the path which is a network
// path on windows
pos = 1; // start at position 1
while((pos = ret.find("\\\\", pos)) != std::string::npos)
{
ret.erase(pos, 1);
}
// now double quote the path if it has spaces in it
// and is not already double quoted
if(ret.find(" ") != std::string::npos
&& ret[0] != '\"')
{
std::string result;
result = "\"" + ret + "\"";
ret = result;
}
return ret;
}
bool cmSystemTools::ParseFunction(std::ifstream& fin,
std::string& name,
std::vector<std::string>& arguments,
2001-11-30 00:44:22 +03:00
const char* filename,
bool& parseError)
{
2001-11-30 00:44:22 +03:00
parseError = false;
name = "";
arguments = std::vector<std::string>();
const int BUFFER_SIZE = 4096;
char inbuffer[BUFFER_SIZE];
if(!fin)
{
return false;
}
if(fin.getline(inbuffer, BUFFER_SIZE ) )
{
cmRegularExpression blankLine("^[ \t\r]*$");
cmRegularExpression comment("^[ \t]*#.*$");
cmRegularExpression oneLiner("^[ \t]*([A-Za-z_0-9]*)[ \t]*\\((.*)\\)[ \t\r]*$");
cmRegularExpression multiLine("^[ \t]*([A-Za-z_0-9]*)[ \t]*\\((.*)$");
cmRegularExpression lastLine("^(.*)\\)[ \t\r]*$");
// check for black line or comment
if(blankLine.find(inbuffer) || comment.find(inbuffer))
{
return false;
}
// look for a oneline fun(arg arg2)
else if(oneLiner.find(inbuffer))
{
// the arguments are the second match
std::string args = oneLiner.match(2);
name = oneLiner.match(1);
// break up the arguments
cmSystemTools::GetArguments(args, arguments);
return true;
}
// look for a start of a multiline with no trailing ")" fun(arg arg2
else if(multiLine.find(inbuffer))
{
name = multiLine.match(1);
std::string args = multiLine.match(2);
cmSystemTools::GetArguments(args, arguments);
// Read lines until the closing paren is hit
bool done = false;
while(!done)
{
// read lines until the end paren is found
if(fin.getline(inbuffer, BUFFER_SIZE ) )
{
// Check for comment lines and ignore them.
if(blankLine.find(inbuffer) || comment.find(inbuffer))
{ continue; }
// Is this the last line?
if(lastLine.find(inbuffer))
{
done = true;
std::string args = lastLine.match(1);
cmSystemTools::GetArguments(args, arguments);
}
else
{
std::string line = inbuffer;
cmSystemTools::GetArguments(line, arguments);
}
}
else
{
2001-11-30 00:44:22 +03:00
parseError = true;
cmSystemTools::Error("Parse error in read function missing end )\nIn File: ",
filename, "\nCurrent line:", inbuffer);
return false;
}
}
return true;
}
else
{
2001-11-30 00:44:22 +03:00
parseError = true;
cmSystemTools::Error("Parse error in read function\nIn file:",
filename, "\nCurrent line:", inbuffer);
return false;
}
}
return false;
}
void cmSystemTools::GetArguments(std::string& line,
std::vector<std::string>& arguments)
{
// Match a normal argument (not quoted, no spaces).
cmRegularExpression normalArgument("[ \t]*(([^ \t\r\\]|[\\].)+)[ \t\r]*");
// Match a quoted argument (surrounded by double quotes, spaces allowed).
cmRegularExpression quotedArgument("[ \t]*(\"([^\"\\]|[\\].)*\")[ \t\r]*");
bool done = false;
while(!done)
{
std::string arg;
2002-03-13 18:25:11 +03:00
std::string::size_type endpos;
bool foundQuoted = quotedArgument.find(line.c_str());
bool foundNormal = normalArgument.find(line.c_str());
if(foundQuoted && foundNormal)
{
// Both matches were found. Take the earlier one.
// Favor double-quoted version if there is a tie.
if(normalArgument.start(1) < quotedArgument.start(1))
{
arg = normalArgument.match(1);
endpos = normalArgument.end(1);
}
else
{
arg = quotedArgument.match(1);
endpos = quotedArgument.end(1);
// Strip off the double quotes on the ends.
arg = arg.substr(1, arg.length()-2);
}
}
else if (foundQuoted)
{
arg = quotedArgument.match(1);
endpos = quotedArgument.end(1);
// Strip off the double quotes on the ends.
arg = arg.substr(1, arg.length()-2);
}
else if(foundNormal)
{
arg = normalArgument.match(1);
endpos = normalArgument.end(1);
}
else
{
done = true;
}
if(!done)
{
arguments.push_back(cmSystemTools::RemoveEscapes(arg.c_str()));
line = line.substr(endpos, line.length() - endpos);
}
}
}
std::string cmSystemTools::RemoveEscapes(const char* s)
{
std::string result = "";
for(const char* ch = s; *ch; ++ch)
{
if(*ch == '\\')
{
++ch;
switch (*ch)
{
case '\\': result.insert(result.end(), '\\'); break;
case '"': result.insert(result.end(), '"'); break;
case ' ': result.insert(result.end(), ' '); break;
case 't': result.insert(result.end(), '\t'); break;
case 'n': result.insert(result.end(), '\n'); break;
case 'r': result.insert(result.end(), '\r'); break;
case '0': result.insert(result.end(), '\0'); break;
case '\0':
{
cmSystemTools::Error("Trailing backslash in argument:\n", s);
return result;
}
default:
{
std::string chStr(1, *ch);
cmSystemTools::Error("Invalid escape sequence \\", chStr.c_str(),
"\nin argument ", s);
}
}
}
else
{
result.insert(result.end(), *ch);
}
}
return result;
}
void cmSystemTools::Error(const char* m1, const char* m2,
const char* m3, const char* m4)
{
std::string message = "CMake Error: ";
if(m1)
{
message += m1;
}
if(m2)
{
message += m2;
}
if(m3)
{
message += m3;
}
if(m4)
{
message += m4;
}
2001-02-23 03:24:43 +03:00
cmSystemTools::s_ErrorOccured = true;
2001-06-05 00:55:37 +04:00
cmSystemTools::Message(message.c_str(),"Error");
}
2001-10-29 18:19:34 +03:00
void cmSystemTools::SetErrorCallback(ErrorCallback f)
{
s_ErrorCallback = f;
}
2001-06-05 00:55:37 +04:00
void cmSystemTools::Message(const char* m1, const char *title)
{
if(s_DisableMessages)
{
return;
}
2001-10-29 18:19:34 +03:00
if(s_ErrorCallback)
{
(*s_ErrorCallback)(m1, title, s_DisableMessages);
2001-10-29 18:19:34 +03:00
return;
}
else
{
std::cerr << m1 << std::endl;
}
}
2001-02-23 03:24:43 +03:00
bool cmSystemTools::CopyFileIfDifferent(const char* source,
2001-02-23 03:24:43 +03:00
const char* destination)
{
if(cmSystemTools::FilesDiffer(source, destination))
{
cmSystemTools::cmCopyFile(source, destination);
return true;
2001-02-23 03:24:43 +03:00
}
return false;
2001-02-23 03:24:43 +03:00
}
bool cmSystemTools::FilesDiffer(const char* source,
const char* destination)
{
struct stat statSource;
if (stat(source, &statSource) != 0)
{
return true;
}
struct stat statDestination;
if (stat(destination, &statDestination) != 0)
{
return true;
}
if(statSource.st_size != statDestination.st_size)
{
return true;
}
std::ifstream finSource(source);
std::ifstream finDestination(destination);
if(!finSource || !finDestination)
{
return true;
}
2002-02-18 22:36:04 +03:00
const int buffer_length = 4096;
char bufferSource[buffer_length];
char bufferDest[buffer_length];
2001-02-23 03:24:43 +03:00
while(finSource && finDestination)
{
2002-02-18 22:36:04 +03:00
if(finSource.getline(bufferSource, buffer_length, '\n')
|| finSource.gcount())
2001-02-23 03:24:43 +03:00
{
2002-02-18 22:36:04 +03:00
if(finDestination.getline(bufferDest, buffer_length, '\n')
|| finDestination.gcount())
{
// both if statements passed
if(finSource.eof())
{
if(!finDestination.eof())
{
return true;
}
if(finSource.gcount() != finDestination.gcount())
{
return true;
}
if(strncmp(bufferSource, bufferDest, finSource.gcount()) != 0)
{
return true;
}
}
else if(finSource.fail())
{
if(!finDestination.fail())
{
return true;
}
if(strcmp(bufferSource, bufferDest) != 0)
{
return true;
}
finSource.clear(finSource.rdstate() & ~std::ios::failbit);
finDestination.clear(finDestination.rdstate() & ~std::ios::failbit);
}
else
{
if(strcmp(bufferSource, bufferDest) != 0)
{
return true;
}
}
}
else
{
return true;
}
2001-02-23 03:24:43 +03:00
}
}
return false;
}
/**
* Copy a file named by "source" to the file named by "destination".
*/
2001-02-23 03:24:43 +03:00
void cmSystemTools::cmCopyFile(const char* source,
const char* destination)
2001-02-23 03:24:43 +03:00
{
const int bufferSize = 4096;
char buffer[bufferSize];
std::ifstream fin(source,
#ifdef _WIN32
std::ios::binary |
#endif
std::ios::in);
if(!fin)
2001-02-23 03:24:43 +03:00
{
cmSystemTools::Error("CopyFile failed to open input file \"",
source, "\"");
return;
2001-02-23 03:24:43 +03:00
}
std::ofstream fout(destination,
#ifdef _WIN32
std::ios::binary |
#endif
std::ios::out | std::ios::trunc);
if(!fout)
2001-02-23 03:24:43 +03:00
{
cmSystemTools::Error("CopyFile failed to open output file \"",
destination, "\"");
return;
2001-02-23 03:24:43 +03:00
}
// This copy loop is very sensitive on certain platforms with
// slightly broken stream libraries (like HPUX). Normally, it is
// incorrect to not check the error condition on the fin.read()
// before using the data, but the fin.gcount() will be zero if an
// error occurred. Therefore, the loop should be safe everywhere.
while(fin)
{
fin.read(buffer, bufferSize);
if(fin.gcount())
2001-02-23 03:24:43 +03:00
{
fout.write(buffer, fin.gcount());
2001-02-23 03:24:43 +03:00
}
}
}
// return true if the file exists
long int cmSystemTools::ModifiedTime(const char* filename)
{
struct stat fs;
if (stat(filename, &fs) != 0)
{
return 0;
}
else
{
return (long int)fs.st_mtime;
}
}
bool cmSystemTools::RemoveFile(const char* source)
2001-02-23 03:24:43 +03:00
{
return unlink(source) != 0 ? false : true;
2001-02-23 03:24:43 +03:00
}
2001-04-26 18:49:12 +04:00
bool cmSystemTools::IsOn(const char* val)
{
if (!val)
{
return false;
}
std::basic_string<char> v = val;
for(std::basic_string<char>::iterator c = v.begin();
c != v.end(); c++)
{
*c = toupper(*c);
}
return (v == "ON" || v == "1" || v == "YES" || v == "TRUE" || v == "Y");
}
2001-04-30 22:56:06 +04:00
bool cmSystemTools::IsOff(const char* val)
{
if (!val || strlen(val) == 0)
2001-04-30 22:56:06 +04:00
{
return true;
}
std::basic_string<char> v = val;
for(std::basic_string<char>::iterator c = v.begin();
c != v.end(); c++)
{
*c = toupper(*c);
}
return (v == "OFF" || v == "0" || v == "NO" || v == "FALSE" ||
v == "N" || v == "NOTFOUND" || v == "IGNORE");
2001-04-30 22:56:06 +04:00
}
bool cmSystemTools::RunCommand(const char* command,
std::string& output,
const char* dir,
bool verbose)
2001-08-23 19:12:19 +04:00
{
int foo;
return cmSystemTools::RunCommand(command, output, foo, dir, verbose);
2001-08-23 19:12:19 +04:00
}
#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);
}
//---------------------------------------------------------------------------
bool WindowsRunCommand(const char* command,
const char* dir,
std::string& output,
int& retVal,
bool verbose)
{
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
{
cmSystemTools::Error("CreatePipe");
return false;
}
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) //create stdout pipe
{
cmSystemTools::Error("CreatePipe");
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))
{
cmSystemTools::Error("CreateProcess failed", commandAndArgs);
CloseHandle(newstdin);
CloseHandle(newstdout);
CloseHandle(read_stdout);
CloseHandle(write_stdin);
delete [] commandAndArgs;
return false;
}
delete [] commandAndArgs;
unsigned long exit=0; //process exit code
unsigned long bread; //bytes read
unsigned long avail; //bytes available
memset(buf, 0, sizeof(buf));
for(;;) //main program loop
{
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
PeekNamedPipe(read_stdout,buf,1023,&bread,&avail,NULL);
if (bread != 0)
{
memset(buf, 0, sizeof(buf));
if (avail > 1023)
{
while (bread >= 1023)
{
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::cout << buf << "\n" << std::flush;
}
}
}
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(newstdin); //clean stuff up
CloseHandle(newstdout);
CloseHandle(read_stdout);
CloseHandle(write_stdin);
retVal = exit;
return true;
}
// use this for shell commands like echo and dir
bool RunCommandViaSystem(const char* command,
const char* dir,
std::string& output,
int& retVal,
bool verbose)
{
2001-05-08 02:11:16 +04:00
const int BUFFER_SIZE = 4096;
char buffer[BUFFER_SIZE];
std::string commandInDir;
if(dir)
{
commandInDir = "cd ";
commandInDir += dir;
commandInDir += " && ";
commandInDir += command;
}
else
{
commandInDir = command;
}
command = commandInDir.c_str();
std::string commandToFile = command;
commandToFile += " > ";
std::string tempFile;
2001-11-26 19:32:20 +03:00
tempFile += _tempnam(0, "cmake");
commandToFile += tempFile;
2001-08-23 19:12:19 +04:00
retVal = system(commandToFile.c_str());
std::ifstream fin(tempFile.c_str());
if(!fin)
{
if(verbose)
{
std::string errormsg = "RunCommand produced no output: command: \"";
errormsg += command;
errormsg += "\"";
errormsg += "\nOutput file: ";
errormsg += tempFile;
cmSystemTools::Error(errormsg.c_str());
}
2001-07-06 01:52:31 +04:00
fin.close();
cmSystemTools::RemoveFile(tempFile.c_str());
return false;
}
while(fin)
{
fin.getline(buffer, BUFFER_SIZE);
output += buffer;
}
2001-07-06 01:52:31 +04:00
fin.close();
cmSystemTools::RemoveFile(tempFile.c_str());
return true;
}
#endif // endif WIN32 not CYGWIN
// run a command unix uses popen (easy)
// windows uses CreateProcess (difficult) or system for built in commands
bool cmSystemTools::RunCommand(const char* command,
std::string& output,
int &retVal,
const char* dir,
bool verbose)
{
if(s_DisableRunCommandOutput)
{
verbose = false;
}
#if defined(WIN32) && !defined(__CYGWIN__)
// if the command does not start with a quote, then
// try to find the program, and if the program can not be
// found use system to run the command as it must be a built in
// shell command like echo or dir
if(command[0] != '\"')
{
cmRegularExpression nonQuoted("^([^ \t]*)[ \t](.*)");
if(nonQuoted.find(command))
{
std::string cmd = nonQuoted.match(1);
if(cmSystemTools::FindProgram(cmd.c_str()) == "")
{
return RunCommandViaSystem(command, dir, output, retVal, verbose);
}
}
}
// best case is the command is an executable and we run it this way
return WindowsRunCommand(command, dir, output, retVal, verbose);
2001-05-08 02:11:16 +04:00
#else
std::string commandInDir;
if(dir)
{
commandInDir = "cd ";
commandInDir += dir;
commandInDir += " && ";
commandInDir += command;
}
else
{
commandInDir = command;
}
command = commandInDir.c_str();
const int BUFFER_SIZE = 4096;
char buffer[BUFFER_SIZE];
if(verbose)
{
std::cout << "running " << command << std::endl;
}
fflush(stdout);
fflush(stderr);
2001-05-08 02:11:16 +04:00
FILE* cpipe = popen(command, "r");
if(!cpipe)
{
return false;
}
fgets(buffer, BUFFER_SIZE, cpipe);
while(!feof(cpipe))
{
if(verbose)
{
std::cout << buffer << std::flush;
}
2001-05-08 02:11:16 +04:00
output += buffer;
fgets(buffer, BUFFER_SIZE, cpipe);
}
2001-08-23 19:12:19 +04:00
retVal = pclose(cpipe);
retVal = WEXITSTATUS(retVal);
return true;
2001-05-08 02:11:16 +04:00
#endif
}
/**
* Find the file the given name. Searches the given path and then
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
std::string cmSystemTools::FindFile(const char* name,
const std::vector<std::string>& userPaths)
{
// Add the system search path to our path.
std::vector<std::string> path = userPaths;
cmSystemTools::GetPath(path);
std::string tryPath;
for(std::vector<std::string>::const_iterator p = path.begin();
p != path.end(); ++p)
{
tryPath = *p;
tryPath += "/";
tryPath += name;
if(cmSystemTools::FileExists(tryPath.c_str()) &&
!cmSystemTools::FileIsDirectory(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
}
// Couldn't find the file.
return "";
}
/**
* Find the executable with the given name. Searches the given path and then
* the system search path. Returns the full path to the executable if it is
* found. Otherwise, the empty string is returned.
*/
std::string cmSystemTools::FindProgram(const char* name,
const std::vector<std::string>& userPaths)
{
// See if the executable exists as written.
if(cmSystemTools::FileExists(name) &&
!cmSystemTools::FileIsDirectory(name))
{
return cmSystemTools::CollapseFullPath(name);
}
2001-05-24 00:28:34 +04:00
std::string tryPath = name;
tryPath += cmSystemTools::GetExecutableExtension();
if(cmSystemTools::FileExists(tryPath.c_str()) &&
!cmSystemTools::FileIsDirectory(tryPath.c_str()))
2001-05-24 00:28:34 +04:00
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
// Add the system search path to our path.
std::vector<std::string> path = userPaths;
cmSystemTools::GetPath(path);
for(std::vector<std::string>::const_iterator p = path.begin();
p != path.end(); ++p)
{
2001-05-24 00:28:34 +04:00
tryPath = *p;
tryPath += "/";
tryPath += name;
if(cmSystemTools::FileExists(tryPath.c_str()) &&
!cmSystemTools::FileIsDirectory(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
2002-02-28 18:41:27 +03:00
#ifdef _WIN32
tryPath += ".com";
if(cmSystemTools::FileExists(tryPath.c_str()) &&
!cmSystemTools::FileIsDirectory(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
2002-02-28 19:15:10 +03:00
tryPath = *p;
tryPath += "/";
tryPath += name;
2002-02-28 18:41:27 +03:00
#endif
tryPath += cmSystemTools::GetExecutableExtension();
if(cmSystemTools::FileExists(tryPath.c_str()) &&
!cmSystemTools::FileIsDirectory(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
}
// Couldn't find the program.
return "";
}
/**
* Find the library with the given name. Searches the given path and then
* the system search path. Returns the full path to the library if it is
* found. Otherwise, the empty string is returned.
*/
std::string cmSystemTools::FindLibrary(const char* name,
const std::vector<std::string>& userPaths)
{
// See if the executable exists as written.
if(cmSystemTools::FileExists(name))
{
return cmSystemTools::CollapseFullPath(name);
}
// Add the system search path to our path.
std::vector<std::string> path = userPaths;
cmSystemTools::GetPath(path);
std::string tryPath;
for(std::vector<std::string>::const_iterator p = path.begin();
p != path.end(); ++p)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
tryPath = *p;
tryPath += "/";
tryPath += name;
tryPath += ".lib";
if(cmSystemTools::FileExists(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
#else
2001-05-10 23:50:03 +04:00
tryPath = *p;
tryPath += "/lib";
tryPath += name;
2001-05-12 15:29:23 +04:00
tryPath += ".so";
if(cmSystemTools::FileExists(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
2001-05-10 23:50:03 +04:00
tryPath = *p;
2001-05-21 23:16:19 +04:00
tryPath += "/lib";
2001-05-10 23:50:03 +04:00
tryPath += name;
2001-05-12 15:29:23 +04:00
tryPath += ".a";
if(cmSystemTools::FileExists(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
2001-05-10 23:50:03 +04:00
tryPath = *p;
2001-05-21 23:16:19 +04:00
tryPath += "/lib";
2001-05-10 23:50:03 +04:00
tryPath += name;
2001-05-12 15:29:23 +04:00
tryPath += ".sl";
if(cmSystemTools::FileExists(tryPath.c_str()))
{
return cmSystemTools::CollapseFullPath(tryPath.c_str());
}
#endif
}
// Couldn't find the library.
return "";
}
bool cmSystemTools::FileIsDirectory(const char* name)
{
struct stat fs;
if(stat(name, &fs) == 0)
{
#if _WIN32
return ((fs.st_mode & _S_IFDIR) != 0);
#else
return S_ISDIR(fs.st_mode);
#endif
}
else
{
return false;
}
}
2001-06-22 01:53:15 +04:00
int cmSystemTools::ChangeDirectory(const char *dir)
{
return Chdir(dir);
}
std::string cmSystemTools::GetCurrentWorkingDirectory()
{
char buf[2048];
std::string path = Getcwd(buf, 2048);
return path;
}
/**
* Given the path to a program executable, get the directory part of the path with the
* file stripped off. If there is no directory part, the empty string is returned.
*/
std::string cmSystemTools::GetProgramPath(const char* in_name)
{
std::string dir, file;
cmSystemTools::SplitProgramPath(in_name, dir, file);
return dir;
}
/**
* Given the path to a program executable, get the directory part of the path
* with the file stripped off. If there is no directory part, the empty
* string is returned.
*/
void cmSystemTools::SplitProgramPath(const char* in_name,
std::string& dir,
std::string& file)
{
dir = in_name;
file = "";
cmSystemTools::ConvertToUnixSlashes(dir);
if(!cmSystemTools::FileIsDirectory(dir.c_str()))
{
std::string::size_type slashPos = dir.rfind("/");
if(slashPos != std::string::npos)
{
file = dir.substr(slashPos+1);
dir = dir.substr(0, slashPos);
}
else
{
file = dir;
dir = "";
}
}
if((dir != "") && !cmSystemTools::FileIsDirectory(dir.c_str()))
{
std::string oldDir = in_name;
cmSystemTools::ConvertToUnixSlashes(oldDir);
cmSystemTools::Error("Error splitting file name off end of path:\n",
2001-05-23 22:44:35 +04:00
oldDir.c_str(), "\nDirectory not found: ",
dir.c_str());
dir = in_name;
return;
}
}
/**
* Given a path to a file or directory, convert it to a full path.
* This collapses away relative paths. The full path is returned.
*/
std::string cmSystemTools::CollapseFullPath(const char* in_name)
{
std::string dir, file;
cmSystemTools::SplitProgramPath(in_name, dir, file);
#ifdef _WIN32
// Ultra-hack warning:
// This changes to the target directory, saves the working directory,
// and then changes back to the original working directory.
std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
if(dir != "") { Chdir(dir.c_str()); }
std::string newDir = cmSystemTools::GetCurrentWorkingDirectory();
Chdir(cwd.c_str());
cmSystemTools::ConvertToUnixSlashes(newDir);
std::string newPath = newDir+"/"+file;
return newPath;
2001-09-28 00:50:59 +04:00
#else
# ifdef MAXPATHLEN
char resolved_name[MAXPATHLEN];
# else
2001-09-28 18:40:14 +04:00
# ifdef PATH_MAX
2001-09-28 00:50:59 +04:00
char resolved_name[PATH_MAX];
2001-09-28 18:40:14 +04:00
# else
char resolved_name[5024];
# endif
2001-09-28 00:50:59 +04:00
# endif
if(dir != "")
{
realpath(dir.c_str(), resolved_name);
dir = resolved_name;
}
else
{
dir = cmSystemTools::GetCurrentWorkingDirectory();
}
if(file == "")
{
return dir;
}
return dir + "/" + file;
2001-09-28 00:50:59 +04:00
#endif
}
/**
* Return path of a full filename (no trailing slashes).
* Warning: returned path is converted to Unix slashes format.
*/
std::string cmSystemTools::GetFilenamePath(const std::string& filename)
{
std::string fn = filename;
cmSystemTools::ConvertToUnixSlashes(fn);
std::string::size_type slash_pos = fn.rfind("/");
if(slash_pos != std::string::npos)
{
return fn.substr(0, slash_pos);
}
else
{
return "";
}
}
/**
* Return file name of a full filename (i.e. file name without path).
*/
std::string cmSystemTools::GetFilenameName(const std::string& filename)
{
std::string fn = filename;
cmSystemTools::ConvertToUnixSlashes(fn);
std::string::size_type slash_pos = fn.rfind("/");
if(slash_pos != std::string::npos)
{
return fn.substr(slash_pos + 1);
}
else
{
return filename;
}
}
/**
* Return file extension of a full filename (dot included).
* Warning: this is the longest extension (for example: .tar.gz)
*/
std::string cmSystemTools::GetFilenameExtension(const std::string& filename)
{
std::string name = cmSystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find(".");
if(dot_pos != std::string::npos)
2001-09-13 19:27:54 +04:00
{
return name.substr(dot_pos);
}
else
{
return "";
}
}
/**
* Return file extension of a full filename (dot included).
*/
std::string cmSystemTools::GetFilenameShortestExtension(const std::string& filename)
{
std::string name = cmSystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.rfind(".");
if(dot_pos != std::string::npos)
{
return name.substr(dot_pos);
}
else
{
return "";
}
}
/**
* Return file name without extension of a full filename (i.e. without path).
* Warning: it considers the longest extension (for example: .tar.gz)
*/
std::string cmSystemTools::GetFilenameNameWithoutExtension(const std::string& filename)
{
std::string name = cmSystemTools::GetFilenameName(filename);
std::string::size_type dot_pos = name.find(".");
if(dot_pos != std::string::npos)
{
return name.substr(0, dot_pos);
}
else
{
return name;
}
}
2001-06-21 20:01:18 +04:00
void cmSystemTools::Glob(const char *directory, const char *regexp,
std::vector<std::string>& files)
{
cmDirectory d;
cmRegularExpression reg(regexp);
if (d.Load(directory))
{
2002-03-13 18:25:11 +03:00
size_t numf;
unsigned int i;
2001-06-21 20:01:18 +04:00
numf = d.GetNumberOfFiles();
for (i = 0; i < numf; i++)
{
std::string fname = d.GetFile(i);
if (reg.find(fname))
{
files.push_back(fname);
}
}
}
}
void cmSystemTools::GlobDirs(const char *fullPath,
std::vector<std::string>& files)
{
std::string path = fullPath;
2001-11-13 20:38:53 +03:00
std::string::size_type pos = path.find("/*");
if(pos == std::string::npos)
{
files.push_back(fullPath);
return;
}
std::string startPath = path.substr(0, pos);
std::string finishPath = path.substr(pos+2);
cmDirectory d;
if (d.Load(startPath.c_str()))
{
2002-02-28 02:11:12 +03:00
for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
{
if((std::string(d.GetFile(i)) != ".")
&& (std::string(d.GetFile(i)) != ".."))
{
std::string fname = startPath;
fname +="/";
fname += d.GetFile(i);
if(cmSystemTools::FileIsDirectory(fname.c_str()))
{
fname += finishPath;
cmSystemTools::GlobDirs(fname.c_str(), files);
}
}
}
}
}
void cmSystemTools::ExpandListArguments(std::vector<std::string> const& arguments,
std::vector<std::string>& newargs)
{
std::vector<std::string>::const_iterator i;
for(i = arguments.begin();i != arguments.end(); ++i)
{
if(i->find(';') != std::string::npos)
{
std::string::size_type start = 0;
std::string::size_type endpos = 0;
while(endpos != std::string::npos)
{
endpos = i->find(';', start);
std::string::size_type len;
if(endpos != std::string::npos)
{
len = endpos - start;
}
else
{
len = i->size()-start;
}
newargs.push_back(i->substr(start, len));
start = endpos+1;
}
}
else
{
newargs.push_back(*i);
}
}
}