1 /*=========================================================================
3 Module: $RCSfile: bbtkUtilities.cxx,v $
5 Date: $Date: 2009/01/28 11:54:04 $
6 Version: $Revision: 1.12 $
7 =========================================================================*/
9 /* ---------------------------------------------------------------------
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
14 * This software is governed by the CeCILL-B license under French law and
15 * abiding by the rules of distribution of free software. You can use,
16 * modify and/ or redistribute the software under the terms of the CeCILL-B
17 * license as circulated by CEA, CNRS and INRIA at the following URL
18 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
19 * or in the file LICENSE.txt.
21 * As a counterpart to the access to the source code and rights to copy,
22 * modify and redistribute granted by the license, users are provided only
23 * with a limited warranty and the software's author, the holder of the
24 * economic rights, and the successive licensors have only limited
27 * The fact that you are presently reading this means that you have had
28 * knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */
32 #include "bbtkUtilities.h"
33 #include "bbtkMessageManager.h"
35 #if defined(MACOSX) // assume this is OSX
36 # include <sys/param.h>
37 # include <mach-o/dyld.h> // _NSGetExecutablePath : must add -framework CoreFoundation to link line
40 # define PATH_MAX MAXPATHLEN
44 #ifndef PATH_MAX // If not defined yet : do it
45 # define PATH_MAX 2048
53 // ======================================================================
54 // See : http://www.techbytes.ca/techbyte103.html for more O.S.
55 bool Utilities::FileExists(std::string strFilename)
57 struct stat stFileInfo;
61 // Attempt to get the file attributes
62 intStat = stat(strFilename.c_str(),&stFileInfo);
65 // We were able to get the file attributes
66 // so the file obviously exists.
71 // We were not able to get the file attributes.
72 // This may mean that we don't have permission to
73 // access the folder which contains this file. If you
74 // need to do that level of checking, lookup the
75 // return values of stat which will give you
76 // more details on why stat failed.
84 // =====================================================================
86 std::string Utilities::ExtractPackageName(const std::string &name,
92 std::string::size_type slash_position = name.find_last_of("/\\");
93 if (slash_position != std::string::npos)
95 pkgname = name.substr(slash_position+1,std::string::npos);
96 path = name.substr(0,slash_position);
97 // std::cout << "F:P='"<<path<<"'"<<std::endl;//+1,std::string::npos);
104 // remove {.so | dll} if any
105 std::string::size_type dot_position = pkgname.find_last_of('.');
106 if (dot_position != std::string::npos){
107 pkgname = pkgname.substr(0,dot_position);
109 #if defined(__GNUC__)
112 // shared lib name = libbb<name>.so
114 // remove {libbb} if any
115 if (memcmp ( pkgname.c_str(), "libbb", 5) == 0) {
116 pkgname = pkgname.substr(5, pkgname.length());
119 /// \ \todo what would happen if (stupid) user names his package 'libbb' ?!?
120 /// \ --> Should be forbidden!
122 #elif defined(_WIN32)
125 // shared lib name = <name>.dll
127 // EED Problem loading package call bbtkTools
128 // // remove {bb} if any
129 if (memcmp (pkgname.c_str(), "bb", 2) == 0) {
130 pkgname = pkgname.substr(2, pkgname.length());
134 /// \ \todo what would happen if (stupid) user names his package 'bb' ?!?
135 /// \ --> Should be forbidden!
138 bbtkError("neither __GNUC__ nor _WIN32 ?!? How did you compile ?");
143 //=====================================================================
144 std::string Utilities::ExtractScriptName(const std::string &name,
149 std::string::size_type slash_position = name.find_last_of("/\\");
150 if (slash_position != std::string::npos) {
151 pkgname =name.substr(slash_position+1,std::string::npos);
152 path = name.substr(0,slash_position);
156 // remove {.bbs } if any
157 std::string::size_type dot_position = pkgname.find_last_of('.');
158 if (dot_position != std::string::npos){
159 pkgname = pkgname.substr(0,dot_position);
164 // ========================================================================
166 std::string Utilities::ExpandLibName(const std::string &name, bool verbose)
168 // ----- Think of expanding path name ( ./ ../ ../../ )
170 char buf[2048]; // for getcwd
171 char * currentDir = getcwd(buf, 2048);
172 std::string cwd(currentDir);
173 std::string libname(name);
174 std::string fileSeparator;
175 fileSeparator = ConfigurationFile::GetInstance().Get_file_separator();
176 // tooHigh : true is user supplies a library pathname with too many "../"
177 bool tooHigh = false;
179 //std::cout << "------------------cwd [" << cwd << "] name [" << name << "]" << std::endl;
181 if ( name[0] == '/' || name[1] == ':' ) // Linux or Windows absolute name
185 else if ( name =="." )
187 libname = cwd + fileSeparator;
190 else if (name[0] == '.' && (name[1] == '/' || name[1] == '\\') )
192 libname = cwd + fileSeparator + name.substr(2, name.length());
195 else if ( name[0] == '.' && name[1] == '.' /* && (name[2] == '/' || name[2] == '\\') */ )
197 if ( IsAtRoot(cwd) ) // hope it gets / (for Linux), C: D: (for Windows)
199 // if we are already at / or c: --> hopeless
201 std::cout << " File path [" << name << "] doesn't exist" << std::endl;
206 // iterate on ../ and go up from the current working dir!
208 bool alreadyProcessRoot = false;
210 //if (a[a.size()-1] != fileSeparator[0])
211 // a.append(fileSeparator);
212 //std::cout << "------------------a [" << a << "]" << std::endl;
214 for(;;) // wild loop !
216 std::string::size_type slash_position = cwd.find_last_of(fileSeparator);
217 if (slash_position != std::string::npos) {
218 if (slash_position == 0)
220 cwd = cwd.substr(0,slash_position/*+1*/);
221 //std::cout << "------------------cwd [" << cwd << "]" << std::endl;
227 a = a.substr(3, /*name.length()*/ a.length()); // remove ../
228 //std::cout << "------------------a [" << a << "]" << std::endl;
229 if (a == "" || alreadyProcessRoot)
232 std::cout << " File path : [" << name << "] doesn't exist" << std::endl;
236 // std::string b = cwd + a;
238 char c = cwd[cwd.size()-1];
239 if (c != '/' && c != '\\' )
240 libname += fileSeparator;
243 if ( a[0] != '.' ) // if . (probabely ../), loop again
247 alreadyProcessRoot = true;
249 } // end iterating on ../
251 //std::cout << "------------------out of loop]" << std::endl;
256 } // ----- End of expanding path name ( ./ ../ ../../ )
258 std::cout <<"* ERROR in ExpandLibName : should never get here!" << std::endl;
260 return(""); // Will never get here!
263 // ===================================================================================
265 std::string Utilities::MakeLibnameFromPath(std::string path, std::string pkgname)
267 std::string libname = path;
268 char c = path[path.size()-1];
269 #if defined(__GNUC__)
281 #elif defined(_WIN32)
283 libname = path+"\\bb";
290 // ===================================================================================
292 std::string Utilities::MakePkgnameFromPath(std::string path, std::string pkgname, bool addExt)
294 std::string libname = path;
295 char c = path[path.size()-1];
296 if (c != '/' && c != '\\')
298 libname += ConfigurationFile::GetInstance().Get_file_separator ();
303 int l = libname.size();
306 if (libname.substr(l-4, 4) != ".bbs")
308 libname = libname + ".bbs";
314 // =======================================================================
316 // =======================================================================
317 /// Returns the user settings dir, e.g. /home/username/.bbtk
318 std::string Utilities::GetUserSettingsDir()
320 #if defined(__GNUC__)
321 std::string str_home(getenv("HOME"));
322 #elif defined(_WIN32)
323 std::string str_home(getenv("USERPROFILE"));
325 std::string fullname = str_home + "/.bbtk";
326 MakeValidFileName(fullname);
331 // =======================================================================
332 /// Builds the complete path to the file 'name' located
333 /// in user settings dir, e.g. /home/username/.bbtk/
334 std::string Utilities::MakeUserSettingsFullFileName(const std::string& name)
336 #if defined(__GNUC__)
337 std::string str_home(getenv("HOME"));
338 #elif defined(_WIN32)
339 std::string str_home(getenv("USERPROFILE"));
341 std::string fullname = str_home + "/.bbtk/" + name;
342 MakeValidFileName(fullname);
345 // =======================================================================
348 // =======================================================================
349 void Utilities::CreateDirectoryIfNeeded( std::string const &dirName)
351 if (FileExists(dirName)) return;
352 std::string cmd("mkdir \"");
357 // =======================================================================
360 //========================================================================
361 bool Utilities::IsAtRoot(std::string cwd)
363 if ( cwd == "/" // hope it gets / (for Linux)
364 || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
369 // ======================================================================
371 // ======================================================================
372 bool Utilities::IsDirectory(std::string const &dirName)
376 if ( stat(dirName.c_str(), &fs) == 0 )
379 return ((fs.st_mode & _S_IFDIR) != 0);
381 return S_ISDIR(fs.st_mode);
389 // =======================================================================
391 // =======================================================================
392 void Utilities::SplitAroundFirstDot( const std::string& in,
396 std::string delimiter = ".";
397 std::string::size_type pos = in.find_first_of(delimiter);
398 if (std::string::npos != pos)
400 left = in.substr(0,pos);
401 right = in.substr(pos+1,in.size());
408 bbtkGlobalError("Token '"<<in<<"' : expected 'a.b' format but no dot found");
411 //=======================================================================
413 //=======================================================================
414 void Utilities::SplitString ( const std::string& str,
415 const std::string& delimiters,
416 std::vector<std::string>& tokens)
418 // Skip delimiters at beginning.
419 std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
420 // Find first delimiter.
421 std::string::size_type pos = str.find_first_of(delimiters, lastPos);
423 while (std::string::npos != pos || std::string::npos != lastPos)
425 // Found a token, add it to the vector.
426 tokens.push_back(str.substr(lastPos, pos - lastPos));
427 // Skip delimiters. Note the "not_of"
428 lastPos = str.find_first_not_of(delimiters, pos);
429 // Find next delimiter
430 pos = str.find_first_of(delimiters, lastPos);
434 //=======================================================================
437 // ======================================================================
438 std::string Utilities::get_file_name(const std::string& s)
440 std::string::size_type slash_position = s.find_last_of("/\\");
441 if (slash_position != std::string::npos)
443 return s.substr(slash_position+1,std::string::npos);
450 //=======================================================================
453 // ========================================================================
455 * \brief Explore a directory with possibility of recursion
456 * return number of files read
457 * @param dirpath directory to explore
458 * @param recursive whether we want recursion or not
460 int Utilities::Explore(std::string const &dirpath, bool recursive, std::vector<std::string> &Filenames)
462 int numberOfFiles = 0;
463 std::string fileName;
465 std::string dirName = dirpath;
468 WIN32_FIND_DATA fileData;
469 HANDLE hFile = FindFirstFile((dirName+"\\*").c_str(), &fileData);
471 for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
472 b = FindNextFile(hFile, &fileData))
474 fileName = fileData.cFileName;
475 if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
477 // Need to check for . and .. to avoid infinite loop
478 if ( fileName != "." && fileName != ".." && recursive )
480 numberOfFiles += Explore(dirName+ "\\"+fileName,recursive,Filenames);
485 Filenames.push_back(dirName+"\\"+fileName);
489 DWORD dwError = GetLastError();
490 if (hFile != INVALID_HANDLE_VALUE)
492 if (dwError != ERROR_NO_MORE_FILES)
495 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
496 FORMAT_MESSAGE_FROM_SYSTEM|
497 FORMAT_MESSAGE_IGNORE_INSERTS,
499 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
500 (LPTSTR) &lpMsgBuf,0,NULL);
502 // ErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
503 // <<" for the directory : "<<dirName);
509 // Real POSIX implementation: scandir is a BSD extension only, and doesn't
510 // work on debian for example
511 //std::cout <<"in Explor dirname[" << dirName << "]" << std::endl;
512 DIR* dir = opendir(dirName.c_str());
517 //std::cout <<"Open OK" << std::endl;
518 // According to POSIX, the dirent structure contains a field char d_name[]
519 // of unspecified size, with at most NAME_MAX characters preceeding the
520 // terminating null character. Use of other fields will harm the porta-
521 // bility of your programs.
525 for (d = readdir(dir); d; d = readdir(dir))
527 fileName = dirName + "/" + d->d_name;
528 //std::cout <<"in Explor filename[" << fileName << "]" << std::endl;
529 if( stat(fileName.c_str(), &buf) != 0 )
531 //ErrorMacro( strerror(errno) );
533 if ( S_ISREG(buf.st_mode) ) //is it a regular file?
535 Filenames.push_back( fileName );
538 else if ( S_ISDIR(buf.st_mode) ) //directory?
540 if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
542 numberOfFiles += Explore( fileName, recursive, Filenames);
547 //ErrorMacro( "Unexpected error" );
551 if( closedir(dir) != 0 )
553 // ErrorMacro( strerror(errno) );
557 return numberOfFiles;
560 //=======================================================================
563 //=======================================================================
564 // Replaces substrings "\\n" by a real carriage return "\n"
565 void Utilities::SubsBackslashN ( std::string& s )
567 std::string ss("\\n");
568 std::string::size_type pos = 0;
570 const char* cr = "\n";
571 while ( pos != std::string::npos )
573 s.replace(pos,2,cr,1);
574 pos = s.find(ss, pos-1);
577 //=======================================================================
580 //=======================================================================
582 bool Utilities::loosematch(std::string stdLine,std::string stdOptions)
585 std::vector<std::string> tokens;
586 SplitString ( stdOptions,"|", tokens);
587 int i,size=tokens.size();
588 for (i=0; i<size; i++)
591 if ( strcmpi(stdLine.c_str(),tokens[i].c_str())==0)
596 if ( strcasecmp(stdLine.c_str(),tokens[i].c_str())==0)
605 //=========================================================================
607 //=========================================================================
608 // From http://www.fltk.org/newsgroups.php?gfltk.general+v:22083
610 int get_app_path (char *pname, size_t pathsize)
613 /* Oddly, the readlink(2) man page says no NULL is appended. */
614 /* So you have to do it yourself, based on the return value: */
615 pathsize --; /* Preserve a space to add the trailing NULL */
616 long result = readlink("/proc/self/exe", pname, pathsize);
619 pname[result] = 0; /* add the #@!%ing NULL */
621 if ((access(pname, 0) == 0))
622 return 0; /* file exists, return OK */
623 /*else name doesn't seem to exist, return FAIL (falls
629 long result = GetModuleFileName(NULL, pname, pathsize);
632 /* fix up the dir slashes... */
633 int len = strlen(pname);
635 for (idx = 0; idx < len; idx++)
637 if (pname[idx] == '\\') pname[idx] = '/';
640 for (idx = len-1; idx >=0 ; idx--)
642 if (pname[idx] == '/')
649 if ((access(pname, 0) == 0))
650 return 0; /* file exists, return OK */
651 /*else name doesn't seem to exist, return FAIL (falls
657 char *p = getexecname();
660 /* According to the Sun manpages, getexecname will
661 "normally" return an */
662 /* absolute path - BUT might not... AND that IF it is not,
664 /* getcwd() will "usually" be the correct thing... Urgh!
667 /* check pathname is absolute (begins with a / ???) */
668 if (p[0] == '/') /* assume this means we have an
671 strncpy(pname, p, pathsize);
672 if ((access(pname, 0) == 0))
673 return 0; /* file exists, return OK */
675 else /* if not, prepend getcwd() then check if file
678 getcwd(pname, pathsize);
679 long result = strlen(pname);
680 strncat(pname, "/", (pathsize - result));
682 strncat(pname, p, (pathsize - result));
684 if ((access(pname, 0) == 0))
685 return 0; /* file exists, return OK */
686 /*else name doesn't seem to exist, return FAIL
692 #ifdef MACOSX /* assume this is OSX */
694 from http://www.hmug.org/man/3/NSModule.html
696 extern int _NSGetExecutablePath(char *buf, unsigned long
699 _NSGetExecutablePath copies the path of the executable
700 into the buffer and returns 0 if the path was successfully
701 copied in the provided buffer. If the buffer is not large
702 enough, -1 is returned and the expected buffer size is
703 copied in *bufsize. Note that _NSGetExecutablePath will
704 return "a path" to the executable not a "real path" to the
705 executable. That is the path may be a symbolic link and
706 not the real file. And with deep directories the total
707 bufsize needed could be more than MAXPATHLEN.
710 char *given_path = (char*)malloc(MAXPATHLEN * 2);
711 if (!given_path) return status;
713 uint32_t npathsize = MAXPATHLEN * 2;
714 long result = _NSGetExecutablePath(given_path, &npathsize);
716 { /* OK, we got something - now try and resolve the real path...
718 if (realpath(given_path, pname) != NULL)
720 if ((access(pname, 0) == 0))
721 status = 0; /* file exists, return OK */
728 return -1; /* Path Lookup Failed */
730 //=========================================================================
734 //=========================================================================
735 std::string Utilities::GetExecutablePath()
738 int err = get_app_path(name, PATH_MAX);
741 bbtkGlobalError("Could not determine current executable path ?");
744 // remove the exe name
746 slash = strrchr(name, VALID_FILE_SEPARATOR_CHAR);
753 //=========================================================================