//----------------------------------------------------------- // Copyright Christian Arnault LAL-Orsay CNRS // arnault@lal.in2p3.fr // See the complete license in cmt_license.txt "http://www.cecill.info". //----------------------------------------------------------- #include #include #include #include #ifdef WIN32 #include #define chdir _chdir #define rmdir _rmdir //#define mkdir _mkdir #define getcwd _getcwd #define popen _popen #define pclose _pclose #define S_IFDIR _S_IFDIR #define USE_GETCWD 1 #include #include #include #include #include #define stat _stat #else #include #include #include #include #include #endif #ifdef __hpux__ #define USE_GETCWD 1 #endif #ifdef __linux__ #define USE_GETCWD 1 #endif #ifdef USE_GETCWD char* getwd (const char* name) { char dir[256]; getcwd (dir, sizeof (dir)); strcpy ((char*) name, dir); return ((char*) name); } #endif #include "cmt_system.h" #include "cmt_error.h" #include "cmt_map.h" #include "cmt_log.h" //-------------------------------------------------- cmt_string CmtSystem::pwd () { char buffer[256] = ""; char* ptr = 0; char* pwd_env = 0; pwd_env = ::getenv ("PWD"); if (pwd_env != 0) { strcpy (buffer, pwd_env); } else { ptr = getcwd (buffer, sizeof (buffer)); } //cerr << "pwd> " << buffer << endl; const char* t = &buffer[0]; return ((cmt_string) t); } //-------------------------------------------------- bool CmtSystem::cd (const cmt_string& dir) { if (!CmtSystem::absolute_path (dir)) { cmt_string d = CmtSystem::pwd (); d += file_separator (); d += dir; return (CmtSystem::cd (d)); } static cmt_string s_dir; s_dir = dir; if ((s_dir.size () == 2) && (s_dir[1] == ':')) { s_dir += file_separator (); } compress_path (s_dir); if (chdir (s_dir.c_str ()) == 0) { putenv ("PWD", s_dir); return (true); } return (false); } //-------------------------------------------------- void CmtSystem::basename (const cmt_string& file_name, cmt_string& result) { int pos = file_name.find_last_of ('/'); if (pos == cmt_string::npos) { pos = file_name.find_last_of ('\\'); } if (pos == cmt_string::npos) { result = file_name; } else { file_name.substr (pos + 1, result); } } //-------------------------------------------------- void CmtSystem::basename (const cmt_string& file_name, const cmt_string& /*suffix*/, cmt_string& result) { basename (file_name, result); int pos; pos = result.find_last_of ('.'); if (pos != cmt_string::npos) { result.erase (pos); } } //-------------------------------------------------- void CmtSystem::dirname (const cmt_string& file_name, cmt_string& result) { int pos = file_name.find_last_of ('/'); if (pos == cmt_string::npos) { pos = file_name.find_last_of ('\\'); } if (pos == cmt_string::npos) { result = ""; } else { result = file_name; result.erase (pos); } } //-------------------------------------------------- void CmtSystem::name (const cmt_string& file_name, cmt_string& result) { int pos; result = file_name; // remove the suffix pos = result.find_last_of ('.'); if (pos != cmt_string::npos) { result.erase (pos); } // remove the directory name pos = result.find_last_of ('/'); if (pos == cmt_string::npos) { pos = result.find_last_of ('\\'); } if (pos != cmt_string::npos) { result.erase (0, pos + 1); } } //------------------------------------------------- void CmtSystem::get_suffix (const cmt_string& file, cmt_string& result) { int pos = file.find_last_of ('.'); int sep = file.find_last_of (file_separator ()); if ((pos == cmt_string::npos) || (pos < sep)) { result = ""; } else { file.substr (pos + 1, result); } } //------------------------------------------------- void CmtSystem::get_dot_suffix (const cmt_string& file, cmt_string& result) { int pos = file.find_last_of ('.'); int sep = file.find_last_of (file_separator ()); if ((pos == cmt_string::npos) || (pos < sep)) { result = ""; } else { file.substr (pos, result); } } //-------------------------------------------------- bool CmtSystem::has_prefix (const cmt_string& name) { if ((name.find ('/') == cmt_string::npos) && (name.find ('\\') == cmt_string::npos)) { return (false); } return (true); } //-------------------------------------------------- bool CmtSystem::realpath (const cmt_string& path, cmt_string& result) { cmt_string here = CmtSystem::pwd (); if (test_directory(path)) { CmtSystem::cd (path); result = CmtSystem::pwd (); CmtSystem::cd (here); return true; } return false; } //-------------------------------------------------- bool CmtSystem::realpath_ (const cmt_string& path, cmt_string& result) { if (test_directory(path)) { cmt_string here = CmtSystem::pwd (); CmtSystem::cd (path); // char buffer[256] = ""; char* ptr = 0; ptr = getcwd (buffer, sizeof (buffer)); const char* t = &buffer[0]; result = t; // cerr << "realpath_> path: " << path << " result: " << result << endl; // CmtSystem::cd (here); return true; } return false; } //-------------------------------------------------- bool CmtSystem::absolute_path (const cmt_string& name) { if (name.size () == 0) return (false); if ((name[0] == '/') || (name[0] == '\\')) return (true); if (name.size () >= 2) { if (name[1] == ':') { return (true); } } return (false); } //-------------------------------------------------- bool CmtSystem::has_device (const cmt_string& name) { #ifdef WIN32 if (name.size () == 0) return (false); if (name.size () >= 2) { if (name[1] == ':') { return (true); } else if ((name[0] == '\\') && (name[1] == '\\')) { return (true); } } #endif return (false); } //-------------------------------------------------- cmt_string CmtSystem::current_branch () { cmt_string result; basename (pwd (), result); return (result); } //-------------------------------------------------- bool CmtSystem::test_directory (const cmt_string& name) { struct stat file_stat; int status; status = stat (name.c_str (), &file_stat); //cerr << "status(stat) for " << name << " : " << status << " st_mode=" << file_stat.st_mode << endl; if (status == 0) { if ((file_stat.st_mode & S_IFDIR) == 0) { return (false); } else { return (true); } } else { return (false); } } //-------------------------------------------------- bool CmtSystem::test_file (const cmt_string& name) { struct stat file_stat; int status; status = stat (name.c_str (), &file_stat); if (status == 0) { if ((file_stat.st_mode & S_IFDIR) == 0) { return (true); } else { return (false); } } else { return (false); } } //-------------------------------------------------- bool CmtSystem::compare_files (const cmt_string& name1, const cmt_string& name2) { struct stat file_stat1; struct stat file_stat2; int status; status = stat (name1.c_str (), &file_stat1); if (status == 0) { if ((file_stat1.st_mode & S_IFDIR) != 0) { return (false); } } else { return (false); } status = stat (name2.c_str (), &file_stat2); if (status == 0) { if ((file_stat2.st_mode & S_IFDIR) != 0) { return (false); } } else { return (false); } if (((int) file_stat1.st_size) != ((int) file_stat2.st_size)) { return (false); } static cmt_string s1; static cmt_string s2; s1.read (name1); s2.read (name2); return ((s1 == s2)); } //-------------------------------------------------- // // Function use to change file timestamps // //-------------------------------------------------- bool CmtSystem::touch_file (const cmt_string& name) { if (CmtSystem::test_file(name)) { static cmt_string s; s.read (name); //unlink (name); FILE* f = fopen (name, "wb"); if (f != NULL) { s.write (f); fclose (f); return (true); } chmod (name.c_str(), 0777); /* FILE* f = fopen (name, "a+"); if (f != NULL) { cmt_string empty = " "; empty.write(f); fclose (f); return true; } */ } return false; } //-------------------------------------------------- // // Check if the file "name1" is identical to "name2" // if they are identical, "name1" will be simply deleted // otherwise "name1" will be copied to "name2" and deleted afterwards // //-------------------------------------------------- bool CmtSystem::compare_and_update_files (const cmt_string& name1, const cmt_string& name2) { struct stat file_stat1; struct stat file_stat2; static cmt_string s1; static cmt_string s2; int status; status = stat (name1.c_str (), &file_stat1); if (status == 0) { if ((file_stat1.st_mode & S_IFDIR) != 0) { // name1 is a directory. return (false); } } else { // name1 does not exist return (false); } s1.read (name1); status = stat (name2.c_str (), &file_stat2); if (status == 0) { if ((file_stat2.st_mode & S_IFDIR) != 0) { // name2 is a directory return (false); } if (((int) file_stat1.st_size) == ((int) file_stat2.st_size)) { s2.read (name2); if (s1 == s2) { unlink (name1); return (true); } } } FILE* f = fopen (name2, "wb"); if (f != NULL) { s1.write (f); fclose (f); unlink (name1); return (true); } else { // // keep the new file "name1" since it cannot be // copied to "name2" // return (false); } } //-------------------------------------------------- int CmtSystem::file_size (const cmt_string& name) { struct stat file_stat; int status; status = stat (name.c_str (), &file_stat); if (status == 0) { return ((int) file_stat.st_size); } else { return (0); } } //-------------------------------------------------- char CmtSystem::file_separator () { #ifdef WIN32 return ('\\'); #else return ('/'); #endif } /** * Transform all / or \ characters in the text into the current file_separator * Reduce all multiple file_separator into single ones. */ void CmtSystem::reduce_file_separators (cmt_string& text) { if (file_separator () == '/') { text.replace_all ("\\", "/"); while (text.find ("//") != cmt_string::npos) { text.replace_all ("//", "/"); } } else { text.replace_all ("/", "\\"); while (text.find ("\\\\") != cmt_string::npos) { text.replace_all ("\\\\", "\\"); } } } //-------------------------------------------------- char CmtSystem::path_separator () { #ifdef WIN32 return (';'); #else return (':'); #endif } //-------------------------------------------------- char CmtSystem::command_separator () { #ifdef WIN32 return ('&'); #else return (';'); #endif } //-------------------------------------------------- const cmt_string& CmtSystem::ev_open () { #ifdef WIN32 static const cmt_string s = "%"; #else static const cmt_string s = "${"; #endif return (s); } //-------------------------------------------------- const cmt_string& CmtSystem::ev_close () { #ifdef WIN32 static const cmt_string s = "%"; #else static const cmt_string s = "}"; #endif return (s); } //------------------------------------------------- bool CmtSystem::create_symlink (const cmt_string& oldname, const cmt_string& newname) { ::unlink (newname.c_str ()); #ifdef WIN32 int status = 1; #else int status = ::symlink (oldname.c_str (), newname.c_str ()); #endif if (status == 0) return (true); return (false); } //------------------------------------------------- bool CmtSystem::remove_file (const cmt_string& name) { if (::unlink (name) != 0) { CmtMessage::error ("Cannot remove file " + name); // cerr << "#CMT> Cannot remove file " << name << endl; return (false); } return (true); } //------------------------------------------------- bool CmtSystem::remove_directory (const cmt_string& name) { //cerr << "Try to remove directory " << name << endl; cmt_string_vector files; scan_dir (name, files); for (int i = 0; i < files.size (); i++) { cmt_string& file = files[i]; if (test_directory (file)) { //cerr << "D=" << file << endl; if (!remove_directory (file)) return (false); } else { //cerr << "F=" << file << endl; if (!remove_file (file)) return (false); } } int status = ::rmdir (name); if (status != 0) { char num[32]; sprintf (num, "%d", errno); CmtMessage::error ("Cannot remove directory " + name + " errno=" + num); // cerr << "#CMT> Cannot remove directory " << name << " errno=" << errno << endl; return (false); } return (true); } //------------------------------------------------- bool CmtSystem::mkdir (const cmt_string& name) { static cmt_string_vector path_vector; int i; static cmt_string full_path; char double_fs[] = " "; double_fs[0] = file_separator (); double_fs[1] = file_separator (); full_path = name; if (file_separator () == '/') { full_path.replace_all ("\\", file_separator ()); } else { full_path.replace_all ("/", file_separator ()); } full_path.replace_all (double_fs, file_separator ()); split (full_path, file_separator (), path_vector); full_path = ""; if (absolute_path (name)) { if (!has_device (name)) { full_path = file_separator (); } } for (i = 0; i < path_vector.size (); i++) { const cmt_string& path = path_vector[i]; if (i > 0) full_path += file_separator (); full_path += path; if (has_device (path)) continue; if (!test_directory (full_path)) { #ifdef WIN32 if (::_mkdir (full_path.c_str ()) != 0) { // cerr << "CMT> cannot create directory " << full_path << endl; return (false); } #else if (::mkdir (full_path.c_str (), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) != 0) { // cerr << "CMT> cannot create directory " << full_path << endl; return (false); } #endif } } return (true); } //---------------------------------------------------------- void CmtSystem::scan_dir (const cmt_string& dir_name, cmt_string_vector& list) { static cmt_string dir_prefix; static cmt_string name_prefix; dir_prefix = dir_name; if (dir_name == "") dir_prefix = "."; if (!test_directory (dir_prefix)) { dirname (dir_prefix, dir_prefix); basename (dir_name, name_prefix); } else { name_prefix = ""; } bool need_filter = false; int wild_card; wild_card = name_prefix.find ('*'); if (wild_card != cmt_string::npos) { name_prefix.erase (wild_card); } if (name_prefix.size () > 0) { need_filter = true; } list.clear (); #ifdef WIN32 long dir; struct _finddata_t entry; static cmt_string search; search = dir_prefix; search += file_separator (); search += "*"; dir = _findfirst (search.c_str (), &entry); if (dir > 0) { for (;;) { if ((strcmp ((char*) entry.name, ".") != 0) && (strcmp ((char*) entry.name, "..") != 0) && (strncmp ((char*) entry.name, ".nfs", 4) != 0)) { const char* name = entry.name; if (!need_filter || (strncmp (name, name_prefix.c_str (), name_prefix.size ()) == 0)) { cmt_string& name_entry = list.add (); name_entry = dir_prefix; name_entry += file_separator (); name_entry += name; } } int status = _findnext (dir, &entry); if (status != 0) { break; } } _findclose (dir); } #else //cerr << "scan_dir> dir=" << dir_name << endl; DIR* dir = opendir (dir_prefix.c_str ()); struct dirent* entry; if (dir != 0) { while ((entry = readdir (dir)) != 0) { //if (entry->d_name[0] == '.') continue; if (!strcmp ((char*) entry->d_name, ".")) continue; if (!strcmp ((char*) entry->d_name, "..")) continue; if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue; const char* name = entry->d_name; if (need_filter && (strncmp (name, name_prefix.c_str (), name_prefix.size ()) != 0)) continue; //cerr << "scan_dir> name=" << name << endl; cmt_string& name_entry = list.add (); name_entry = dir_prefix; name_entry += file_separator (); name_entry += name; } closedir (dir); } #endif } //---------------------------------------------------------- void CmtSystem::scan_dir (const cmt_string& dir_name, const cmt_regexp& expression, cmt_string_vector& list) { static cmt_string dir_prefix; dir_prefix = dir_name; if (dir_name == "") dir_prefix = "."; if (!test_directory (dir_prefix)) { dirname (dir_prefix, dir_prefix); } list.clear (); #ifdef WIN32 long dir; struct _finddata_t entry; static cmt_string search; search = dir_prefix; search += file_separator (); search += "*"; dir = _findfirst (search.c_str (), &entry); if (dir > 0) { for (;;) { if ((entry.name[0] != '.') && (strcmp ((char*) entry.name, ".") != 0) && (strcmp ((char*) entry.name, "..") != 0) && (strncmp ((char*) entry.name, ".nfs", 4) != 0)) { const char* name = entry.name; if (expression.match (name)) { cmt_string& name_entry = list.add (); name_entry = dir_prefix; name_entry += file_separator (); name_entry += name; } } int status = _findnext (dir, &entry); if (status != 0) { break; } } _findclose (dir); } #else //cerr << "scan_dir> dir=" << dir_name << endl; DIR* dir = opendir (dir_prefix.c_str ()); struct dirent* entry; if (dir != 0) { while ((entry = readdir (dir)) != 0) { //if (entry->d_name[0] == '.') continue; if (!strcmp ((char*) entry->d_name, ".")) continue; if (!strcmp ((char*) entry->d_name, "..")) continue; if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue; const char* name = entry->d_name; if (!expression.match (name)) continue; cmt_string& name_entry = list.add (); name_entry = dir_prefix; name_entry += file_separator (); name_entry += name; } closedir (dir); } #endif } //---------------------------------------------------------- CmtSystem::cmt_string_vector& CmtSystem::scan_dir (const cmt_string& dir_name) { static cmt_string_vector result; scan_dir (dir_name, result); return (result); } //---------------------------------------------------------- const cmt_string& CmtSystem::get_cmt_root () { static cmt_string root; root = ""; const char* env = ::getenv ("CMTROOT"); if (env != 0) { root = env; dirname (root, root); dirname (root, root); root.replace_all ("\"", ""); return (root); } #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { char temp[256]; DWORD length = sizeof (temp) - 1; DWORD type; status = RegQueryValueEx (key, "root", 0, &type, (LPBYTE) temp, &length); if (status == ERROR_SUCCESS) { root = temp; return (root); } } #endif return (root); } //---------------------------------------------------------- void CmtSystem::get_cmt_version (cmt_string& version) { version = ""; const char* env = ::getenv ("CMTROOT"); if (env != 0) { cmt_string s = env; basename (s, version); version.replace_all ("\"", ""); } else { #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { char temp[256]; DWORD length = sizeof (temp) - 1; DWORD type; status = RegQueryValueEx (key, "version", 0, &type, (LPBYTE) temp, &length); if (status == ERROR_SUCCESS) { version = temp; } } #endif } } //---------------------------------------------------------- cmt_string CmtSystem::get_cmt_config () { const char* env = ::getenv ("CMTCONFIG"); if (env != 0) { return (cmt_string (env)); } env = ::getenv ("CMTBIN"); if (env != 0) { return (cmt_string (env)); } #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { char temp[256]; DWORD length = sizeof (temp) - 1; DWORD type; status = RegQueryValueEx (key, "config", 0, &type, (LPBYTE) temp, &length); if (status == ERROR_SUCCESS) { cmt_string config (temp); return (config); } } return ("VisualC"); #endif return (""); } //---------------------------------------------------------- cmt_string CmtSystem::get_cmt_site () { const char* env = ::getenv ("CMTSITE"); if (env != 0) { return (cmt_string (env)); } #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { char temp[256]; DWORD length = sizeof (temp) - 1; DWORD type; status = RegQueryValueEx (key, "site", 0, &type, (LPBYTE) temp, &length); if (status == ERROR_SUCCESS) { cmt_string site (temp); return (site); } } #endif return (""); } //---------------------------------------------------------- void CmtSystem::get_uname (cmt_string& uname) { #ifdef WIN32 uname = "WIN32"; #else uname = ""; FILE* file; file = popen ("uname", "r"); if (file != 0) { char line[1024]; char* ptr; char* nl; line[0] = 0; ptr = fgets (line, sizeof (line), file); if (ptr != 0) { nl = strrchr (ptr, '\n'); if (nl != 0) *nl = 0; uname = ptr; } pclose (file); } #endif } //---------------------------------------------------------- void CmtSystem::get_hosttype (cmt_string& hosttype) { hosttype = ""; char* ptr; ptr = ::getenv ("HOSTTYPE"); if (ptr != 0) { hosttype = ptr; } } //---------------------------------------------------------- cmt_string CmtSystem::get_temporary_name () { cmt_string name; name = ::tmpnam (NULL); return (name); } //---------------------------------------------------------- cmt_string CmtSystem::get_home_package () { cmt_string name = "CMTHOME"; return (name); } //---------------------------------------------------------- bool CmtSystem::is_home_package (const cmt_string& name, const cmt_string& version) { if (name == "CMTHOME") return (true); return (false); } //---------------------------------------------------------- cmt_string CmtSystem::get_user_context_package () { cmt_string name = "CMTUSERCONTEXT"; return (name); } //---------------------------------------------------------- bool CmtSystem::is_user_context_package (const cmt_string& name, const cmt_string& version) { if (name == "CMTUSERCONTEXT") return (true); return (false); } //---------------------------------------------------------- cmt_string CmtSystem::get_project_package () { cmt_string name = "PROJECT"; return (name); } //---------------------------------------------------------- bool CmtSystem::is_project_package (const cmt_string& name, const cmt_string& version) { if (name == "PROJECT") return (true); return (false); } //---------------------------------------------------------- bool CmtSystem::testenv (const cmt_string& name) { const char* env = ::getenv (name); if (env == 0) return (false); return (true); } //---------------------------------------------------------- cmt_string CmtSystem::getenv (const cmt_string& name) { cmt_string result; const char* env = ::getenv (name); if (env != 0) { result = env; } if (name == "CMTCONFIG") { return (get_cmt_config ()); } /* if (name == "CMTROOT") { return (get_cmt_root ()); } if (name == "CMTSITE") { return (get_cmt_site ()); } */ return (result); } /** Implementation based on a local static map of used environment variables to ensure a stable character string. The OS requires that the character string sent via a putenv is kept untouched forever */ bool CmtSystem::putenv (const cmt_string& name, const cmt_string& value) { static cmt_map envs; if (!envs.has (name)) { cmt_string& v = *(new cmt_string); v = name; v += "="; v += value; envs.add (name, v); } else { cmt_string& v = *(envs.find (name)); v = name; v += "="; v += value; } { const cmt_string& v = *envs.find (name); //cerr << "#CmtSystem::putenv> name=" << name << " &v=" << &v << endl; int status = ::putenv ((char*) v.c_str ()); if (status == 0) return (true); else return (false); } } //---------------------------------------------------------- // // This singleton interacts with the ProjectFactory to consistently create // the project graph. // // In particular a single-depth stack of the top project is maintained. // //---------------------------------------------------------- class CMTPathManager { public: static CMTPathManager& instance (); static void reset (); static void add_cmt_path (const cmt_string& path, const cmt_string& path_source, IProjectFactory& factory); private: CMTPathManager () : m_project (0) { } void do_reset () { m_project = 0; } void do_add_cmt_path (const cmt_string& path, const cmt_string& path_source, IProjectFactory& factory) { cmt_string npath = path; if (npath == "") return; #ifdef WIN32 if (npath.size () == 2) { if (npath[1] == ':') { npath += CmtSystem::file_separator (); } } #endif npath.replace_all ("\\", CmtSystem::file_separator ()); npath.replace_all ("/", CmtSystem::file_separator ()); if (!CmtSystem::absolute_path (npath)) { cmt_string h = CmtSystem::pwd (); h += CmtSystem::file_separator (); h += npath; npath = h; } CmtSystem::compress_path (npath); //cerr << "adding npath=" << npath << endl; while (npath[npath.size ()-1] == CmtSystem::file_separator ()) { npath.erase (npath.size ()-1); } //cerr << "adding npath=[" << npath << "]" << endl; if (npath != "") { cmt_string project_name; if ((path_source == "CMTUSERCONTEXT") || (path_source == "CMTHOME")) { project_name = path_source; } m_project = factory.create_project (project_name, npath, path_source, m_project); } } Project* m_project; }; CMTPathManager& CMTPathManager::instance () { static CMTPathManager me; return (me); } void CMTPathManager::reset () { static CMTPathManager& me = instance (); me.do_reset (); } void CMTPathManager::add_cmt_path (const cmt_string& path, const cmt_string& path_source, IProjectFactory& factory) { static CMTPathManager& me = instance (); me.do_add_cmt_path (path, path_source, factory); } //---------------------------------------------------------- static void add_cmt_paths_from_text (const cmt_string& text, const cmt_string& context, IProjectFactory& factory) { static CmtSystem::cmt_string_vector path_vector; int i; CmtSystem::split (text, CmtSystem::path_separator (), path_vector); for (i = 0; i < path_vector.size (); i++) { const cmt_string& path = path_vector[i]; CMTPathManager::add_cmt_path (path, context, factory); } } //---------------------------------------------------------- static void add_cmt_paths_from_file (const cmt_string& file_name, IProjectFactory& factory) { if (!CmtSystem::test_file (file_name)) return; static cmt_string text; text.read (file_name); int pos = text.find ("CMTPATH"); if (pos == cmt_string::npos) return; pos += strlen ("CMTPATH"); pos = text.find (pos, "="); if (pos == cmt_string::npos) return; pos++; text.erase (0, pos); int nl = text.find (pos, "\n"); if (nl != cmt_string::npos) text.erase (nl); add_cmt_paths_from_text (text, file_name, factory); } //---------------------------------------------------------- // // With this function we analyse all possible ways of // externally entering CMTPATH items // + from the environment variable // + from .cmtrc files // + from registry on Windows // + from EV settings for CMTUSERCONTEXT and CMTHOME // // Then projects are created from these settings. // // (The other way to enter project graph is through project files) //---------------------------------------------------------- void CmtSystem::get_cmt_paths (IProjectFactory& factory, const cmt_string& init_text, const cmt_string& cmt_user_context, const cmt_string& cmt_home) { CMTPathManager::reset (); if (init_text != "") { add_cmt_paths_from_text (init_text, "initialization", factory); } #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\CMT\\path", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { DWORD index = 0; char name[256]; char temp[256]; for (;;) { DWORD name_length = sizeof (name) - 1; DWORD length = sizeof (temp) - 1; DWORD type; status = RegEnumValue (key, index, name, &name_length, 0, &type, (LPBYTE) temp, &length); if ((status == ERROR_SUCCESS) || (status == 234)) { const cmt_string path = temp; CMTPathManager::add_cmt_path (path, "HKEY_CURRENT_USER", factory); } if (status == 259) { break; } index++; } } status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT\\path", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { DWORD index = 0; char name[256]; char temp[256]; for (;;) { DWORD type; DWORD name_length = sizeof (name) - 1; DWORD length = sizeof (temp) - 1; status = RegEnumValue (key, index, name, &name_length, 0, &type, (LPBYTE) temp, &length); if (status != ERROR_NO_MORE_ITEMS) { const cmt_string path = temp; CMTPathManager::add_cmt_path (path, "HKEY_LOCAL_MACHINE", factory); } else { break; } index++; } } #endif //----------------------------------------- // look for .cmtrc files : // first look in ./ // then in "~/" // then in ${CMTROOT}/mgr //----------------------------------------- cmt_string rc_name; add_cmt_paths_from_file (".cmtrc", factory); if (get_home_directory (rc_name)) { rc_name += file_separator (); rc_name += ".cmtrc"; add_cmt_paths_from_file (rc_name, factory); } rc_name = get_cmt_root (); rc_name += file_separator (); rc_name += "CMT"; rc_name += file_separator (); cmt_string version; get_cmt_version (version); rc_name += version; rc_name += file_separator (); rc_name += "mgr"; rc_name += file_separator (); rc_name += ".cmtrc"; add_cmt_paths_from_file (rc_name, factory); CMTPathManager::add_cmt_path (cmt_user_context, "CMTUSERCONTEXT", factory); CMTPathManager::add_cmt_path (cmt_home, "CMTHOME", factory); } //---------------------------------------------------------- int CmtSystem::execute (const cmt_string& command) { //cerr << "CmtSystem::execute1> [" << command << "]" << endl; return (system (command.c_str ())); } //---------------------------------------------------------- int CmtSystem::execute (const cmt_string& command, cmt_string& output) { output = ""; //cerr << "CmtSystem::execute2> [" << command << "]" << endl; FILE* f = popen (command.c_str (), "r"); if (f != 0) { char line[256]; char* ptr; while ((ptr = fgets (line, sizeof (line), f)) != NULL) { output += ptr; } if (pclose (f) == -1) { if (errno == ECHILD) { return (0); } return (1); } return (0); } return (1); } //---------------------------------------------------------- bool CmtSystem::is_package_directory (const cmt_string& name) { cmt_string_vector dirs; cmt_regexp exp ("^[a-zA-Z.][0-9]+([a-zA-Z.][0-9]+([a-zA-Z.][0-9]+)?)?"); scan_dir (name, exp, dirs); cmt_string req; req = name; req += file_separator (); req += "cmt"; req += file_separator (); req += "requirements"; if (test_file (req)) return (true); if (dirs.size () == 0) { return (false); } for (int i = 0; i < dirs.size (); i++) { const cmt_string& d = dirs[i]; req = d; req += file_separator (); req += "mgr"; req += file_separator (); req += "requirements"; if (test_file (req)) return (true); req = d; req += file_separator (); req += "cmt"; req += file_separator (); req += "requirements"; if (test_file (req)) return (true); } return (false); } //---------------------------------------------------------- bool CmtSystem::is_version_directory (const cmt_string& name) { int v; int r; int p; return (is_version_directory (name, v, r, p)); } //---------------------------------------------------------- bool CmtSystem::is_version_directory (const cmt_string& name, int& v, int& r, int& p) { if ((name == "HEAD") || (name == "head")) { v = 0; r = 0; p = 0; return (true); } static const cmt_string numbers = "0123456789"; static const int id_version = 0; static const int id_release = 1; static const int id_patch = 2; cmt_string buffer; enum { starting, at_key, at_number } state; int id; int pos; int value; v = 0; r = 0; p = 0; // // version : v-field // | v-field r-field // | v-field r-field p-field // // v-field : field // r-field : field // p-field : field // // field : key '*' // | key number // // key : letters // state = starting; id = id_version; for (pos = 0; pos < name.size (); pos++) { char c = name[pos]; if (c == '*') { // A wild card switch (state) { case starting: // cannot start with a wild card ?? v = -1; r = -1; p = -1; return (false); case at_key: // the numeric field is valued with a wild card switch (id) { case id_version: v = -1; case id_release: r = -1; case id_patch: p = -1; break; } return (true); case at_number: // question: // a number followed by a wild-card is considered as: // 1) a wild card on the number itself (1* comp with 1, 10, 12, 120, etc) // 2) a wild card on the next fields (1* comp with 1r1, 1-12 etc) // // Here we select option 1) sscanf (buffer.c_str (), "%d", &value); switch (id) { case id_version: // // lazy option 1 implies v = -1; // strict option 1 would imply v = -value; // option 2 implies v = value; // v = -1; r = -1; p = -1; break; case id_release: r = value; p = -1; break; case id_patch: p = value; break; } return (true); } } else if (numbers.find (c) == cmt_string::npos) { // A letter switch (state) { case starting: state = at_key; break; case at_key: // Multiple letter key (is it permitted??) break; case at_number: sscanf (buffer.c_str (), "%d", &value); switch (id) { case id_version: v = value; break; case id_release: r = value; break; case id_patch: p = value; break; } buffer = ""; id++; state = at_key; break; } } else { // a number switch (state) { case starting: // not starting by a letter (syntax error) //return (false); case at_key: // the numeric field for the current id is starting now buffer += c; state = at_number; break; case at_number: // continuing the current numeric field buffer += c; break; } } } switch (state) { case starting: // Empty version string return (false); case at_key: // Syntax error (when only letters. Ending letters is not an error) if (id == id_version) return (false); else return (true); case at_number: sscanf (buffer.c_str (), "%d", &value); switch (id) { case id_version: v = value; break; case id_release: r = value; break; case id_patch: p = value; break; } id++; state = at_key; return (true); } return (false); } //---------------------------------------------------------- // Split a line into words. Separators are spaces and tabs // Text enclosed in double quotes is one word. //---------------------------------------------------------- void CmtSystem::split (const cmt_string& text, const cmt_string& separators, cmt_string_vector& strings) { static char* buffer = 0; static int allocated = 0; bool finished = false; strings.clear (); if (text.size () == 0) return; /* We are going to work in a copy of the text, since \0 will be inserted right after each found word. Then the vector of strings is iteratively filled by each found word. */ if (buffer == 0) { allocated = text.size (); buffer = (char*) malloc (allocated + 1); } else { if (text.size () > allocated) { allocated = text.size (); buffer = (char*) realloc (buffer, allocated + 1); } } strcpy (buffer, text.c_str ()); /* Algorithm : We look for words separated by which may be o spaces (' ' or '\t') o other characters such as ':' A word is a character string not containing any separator. A substring in this word my be enclosed between quotes (" or ') which permits separator inclusion within words. */ char* current_word = buffer; while (*current_word != 0) { size_t prefix_length; size_t word_length; /* while ((*current_word == ' ') || (*current_word == '\t')) { current_word++; } */ // first skip all starting separators. prefix_length = strspn (current_word, separators.c_str ()); if (prefix_length > 0) { // Move to the first non-separator character current_word += prefix_length; } /* Parse the next word. It may contain enclosures in quote characters or not. Quotes must be identical on both sides of each enclosure. */ char* running_char = current_word; word_length = 0; for (;;) { size_t unquoted_length; size_t separator_offset; for (int p = 0;;) { unquoted_length = strcspn (running_char + p, "\"\'") + p; if ((unquoted_length > 0) && (running_char[unquoted_length-1] == '\\')) { p = unquoted_length + 1; } else { break; } } separator_offset = strcspn (running_char, separators.c_str ()); if (separator_offset <= unquoted_length) { // no quote in this word -> we are finished for this one. running_char += separator_offset; break; } // We have found a quoted enclosure. Move to it. running_char += unquoted_length; char quote = running_char[0]; // Remove it. { char* p = running_char; while (p[1] != 0) { *p = p[1]; p++; } *p = 0; } // Look for the next occurence of this quote. { char* p = strchr (running_char, quote); if (p == 0) { // Unmatched quote : the rest of the line will be taken as a word... running_char += strlen (running_char); finished = true; break; } else { running_char = p; } } // Now we remove the ending quote from the word // (by shifting all remaining characters by one place to the left) { char* p = running_char; while (p[1] != 0) { *p = p[1]; p++; } *p = 0; } } word_length = running_char - current_word; if (current_word[word_length] == 0) { finished = true; } else { current_word[word_length] = 0; } /* if ((t[0] == '"') || (t[0] == '\'') || (t[0] == ':')) { char* quote; t++; quote = strchr (t, sep); if (quote != 0) *quote = 0; else finished = true; } else { int offset; offset = strcspn (t, " \t:"); if ((offset < 0) || (t[offset] == 0)) finished = true; if (!finished) { space = t + offset; *space = 0; } } */ // Store the current word into the vector of strings { cmt_string& s = strings.add (); s = current_word; } if (finished) break; // Move to the next possible word. current_word += word_length + 1; } } //---------------------------------------------------------- void CmtSystem::compress_path (const cmt_string& dir, cmt_string& new_dir) { new_dir = dir; compress_path (new_dir); } //---------------------------------------------------------- // // We try to detect the aaaa/xxxx/../bbbb patterns which should be // equivalent to aaaa/bbbb // this therefore consists in removing all /xxxx/../ when // xxxx is different from ".." // xxxx is different from "." // xxxx does not contain any macro reference // // Also replace "/.." with "/". One cannot walk down past the root. //---------------------------------------------------------- void CmtSystem::compress_path (cmt_string& dir) { #ifdef WIN32 static const char pattern[] = "\\.."; static const char fs[] = "\\\\"; #else static const char pattern[] = "/.."; static const char fs[] = "//"; #endif if (dir.size () == 0) return; // // We first synchronize to using file_separator() in any case. // if (file_separator () == '/') { dir.replace_all ("\\", file_separator ()); } else { dir.replace_all ("/", file_separator ()); } // Suppress all duplicated file separators dir.replace_all (fs, file_separator ()); for (;;) { int pos0 (0); int pos1; int pos2; int pos3; //pos1 = dir.find (pattern); //if (pos1 == cmt_string::npos) break; do { pos1 = dir.find (pos0, pattern); if (pos1 == cmt_string::npos) break; pos0 = pos1 + 3; } while (pos0 < dir.size () && dir[pos0] != file_separator ()); if (pos1 == cmt_string::npos) break; // // One cannot walk down past the root: "/.." is the same as "/". // #ifdef WIN32 if (pos1 == 0) { dir.erase (pos1, 3); if (dir == "") dir = file_separator (); continue; } else if (pos1 == 2 && dir[1] == ':') { dir.erase (pos1, 3); if (dir.size () == 2) dir += file_separator (); continue; } #else if (pos1 == 0) { dir.erase (pos1, 3); if (dir == "") dir = file_separator (); continue; } #endif // // extract "aaaa/xxxx" from "aaaa/xxxx/../bbbb" // cmt_string p = dir.substr (0, pos1); cmt_string dn; basename (p, dn); if (dn == "..") break; if (dn == ".") break; if (dn == "") break; // // Is "aaaa/xxxx" only made of "xxxx" ? // pos2 = p.find_last_of (file_separator ()); if (pos2 == cmt_string::npos) { // the pattern was xxxx/../bbbb // // so xxxx is [0:pos1-1] // // erase the "xxxx/.." pattern // result will be "/bbbb" // so, need to process a little more // pos3 = p.find ("$"); if (pos3 == cmt_string::npos) { dir.erase (0, pos1 + 3); if (dir.size () < 2) { dir = "."; } else { dir.erase (0, 1); } } else { break; } } else { // 01234567890123456 // aaaa/xxxx/../bbbb // 2 1 3 // // erase the "/xxxx/.." pattern // result will be "aaaa/bbbb" // // Here xxxx is [pos2+1:pos1-1] // pos3 = p.find (pos2, "$"); if (pos3 == cmt_string::npos) { dir.erase (pos2, pos1 + 3 - pos2); #ifdef WIN32 if (dir == "") { dir = file_separator (); } else if (dir.size () == 2 && dir[1] == ':') { dir += file_separator (); } #else if (dir == "") dir = file_separator (); #endif } else { break; } } } //if (dir[dir.size () - 1] == file_separator ()) dir.erase (dir.size () - 1); } //---------------------------------------------------------- cmt_string CmtSystem::now () { cmt_string result; time_t ltime; time (<ime); result = ctime (<ime); result.replace_all ("\n", ""); return (result); } //---------------------------------------------------------- cmt_string CmtSystem::user () { #ifdef _WIN32 cmt_string result = getenv ("USERNAME"); #else cmt_string result = getenv ("USER"); #endif return (result); } //---------------------------------------------------------- void CmtSystem::get_cvsroot (cmt_string& cvsroot) { cvsroot = ""; const char* env = ::getenv ("CVSROOT"); if (env != 0) { cvsroot = env; return; } #ifdef WIN32 LONG status; HKEY key = 0; status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 0, KEY_READ, &key); if (status == ERROR_SUCCESS) { char temp[256]; DWORD length = sizeof (temp) - 1; DWORD type; status = RegQueryValueEx (key, "CVSROOT", 0, &type, (LPBYTE) temp, &length); if (status == ERROR_SUCCESS) { cvsroot = temp; return; } } #endif } //---------------------------------------------------------- bool CmtSystem::get_home_directory (cmt_string& dir) { bool status = false; #ifdef WIN32 const char* homedrive = ::getenv ("HOMEDRIVE"); const char* homepath = ::getenv ("HOMEPATH"); if ((homedrive != 0) && (homepath != 0)) { dir = homedrive; dir += homepath; status = true; } #else const char* home_env = ::getenv ("HOME"); if (home_env != 0) { dir = home_env; status = true; } #endif return (status); } //---------------------------------------------------------- cmt_string CmtSystem::get_makefile_suffix () { #ifdef WIN32 return "nmake"; #else return "make"; #endif } //---------------------------------------------------------- FilePath::FilePath () { p_name = ""; l_name = ""; alternates.resize (0); } //---------------------------------------------------------- FilePath::FilePath (const FilePath& other) { set (other); } //---------------------------------------------------------- FilePath::FilePath (const cmt_string& other) { set (other); } //---------------------------------------------------------- FilePath::FilePath (const char* other) { set (other); } //---------------------------------------------------------- FilePath& FilePath::operator = (const FilePath& other) { FilePath& me = *this; me.set (other); return (me); } //---------------------------------------------------------- FilePath& FilePath::operator = (const cmt_string& other) { FilePath& me = *this; me.set (other); return (me); } //---------------------------------------------------------- FilePath& FilePath::operator = (const char* other) { FilePath& me = *this; me.set (other); return (me); } //---------------------------------------------------------- bool FilePath::operator == (const FilePath& other) const { if (other.p_name == p_name) return (true); return (false); } //---------------------------------------------------------- bool FilePath::operator == (const cmt_string& other) const { if (p_name == other) return (true); if (l_name == other) return (true); for (int i = 0; i < alternates.size (); i++) { if (alternates[i] == other) return (true); } cmt_string here = CmtSystem::pwd (); CmtSystem::cd (other); cmt_string p = CmtSystem::pwd (); CmtSystem::cd (here); if (p_name == p) return (true); return (false); } //---------------------------------------------------------- bool FilePath::operator == (const char* other) const { const FilePath& me = *this; const cmt_string o = other; return ((me == o)); return (false); } //---------------------------------------------------------- bool FilePath::operator != (const FilePath& other) const { const FilePath& me = *this; return (!(me == other)); } //---------------------------------------------------------- bool FilePath::operator != (const cmt_string& other) const { const FilePath& me = *this; return (!(me == other)); } //---------------------------------------------------------- bool FilePath::operator != (const char* other) const { const FilePath& me = *this; return (!(me == other)); } //---------------------------------------------------------- bool FilePath::cd () const { CmtSystem::cd (l_name); return (false); } //---------------------------------------------------------- void FilePath::set (const FilePath& other) { p_name = other.p_name; l_name = other.l_name; alternates = other.alternates; } //---------------------------------------------------------- void FilePath::set (const cmt_string& other) { // Skip if no change. if (p_name == other) return; if (l_name == other) return; for (int i = 0; i < alternates.size (); i++) { if (alternates[i] == other) return; } // Something changes cmt_string here = CmtSystem::pwd (); CmtSystem::cd (other); cmt_string p = CmtSystem::pwd (); CmtSystem::cd (here); if (p == p_name) { // The physical name does not change => we are just adding a new logical if (l_name == "") { // the logical name was not set => set it l_name = other; } else { // add a new logical name cmt_string& n = alternates.add (); n = other; } } else { // The physical names differ => we completely reset the object p_name = p; l_name = other; alternates.resize (0); } } //---------------------------------------------------------- void FilePath::set (const char* other) { const cmt_string o = other; set (o); } //---------------------------------------------------------- const cmt_string& FilePath::name () const { if (l_name != "") return (l_name); else return (p_name); } //---------------------------------------------------------- FilePath::operator const cmt_string& () const { if (l_name != "") return (l_name); else return (p_name); } //---------------------------------------------------------- bool FilePath::in (const FilePath& other) const { const cmt_string& o = other.name (); return (in (o)); return (false); } //---------------------------------------------------------- bool FilePath::in (const cmt_string& other) const { if (p_name.find (other) == 0) return (true); if (l_name.find (other) == 0) return (true); for (int i = 0; i < alternates.size (); i++) { const cmt_string& a = alternates[i]; if (a.find (other) == 0) return (true); } return (false); } //---------------------------------------------------------- bool FilePath::in (const char* other) const { const cmt_string o = other; return (in (o)); }