]> Creatis software - bbtk.git/blob - kernel/src/bbtkUtilities.cxx
are now generated in user's .bbtk dir
[bbtk.git] / kernel / src / bbtkUtilities.cxx
1 /*=========================================================================                                                                               
2   Program:   bbtk
3   Module:    $RCSfile: bbtkUtilities.cxx,v $
4   Language:  C++
5   Date:      $Date: 2009/01/27 14:22:57 $
6   Version:   $Revision: 1.11 $
7 =========================================================================*/
8
9 /* ---------------------------------------------------------------------
10
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
13 *
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.
20 *
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
25 *  liability. 
26 *
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 * ------------------------------------------------------------------------ */                                                                         
30
31
32 #include "bbtkUtilities.h"
33 #include "bbtkMessageManager.h"
34
35  
36
37 namespace bbtk
38 {
39
40
41
42             // ======================================================================
43     // See : http://www.techbytes.ca/techbyte103.html for more O.S.
44     bool Utilities::FileExists(std::string strFilename) 
45     {
46       struct stat stFileInfo;
47      bool blnReturn;
48      int intStat;
49      
50      // Attempt to get the file attributes
51      intStat = stat(strFilename.c_str(),&stFileInfo);
52      if(intStat == 0) 
53        {
54          // We were able to get the file attributes
55          // so the file obviously exists.
56          blnReturn = true;
57        } 
58      else 
59        {
60          // We were not able to get the file attributes.
61          // This may mean that we don't have permission to
62          // access the folder which contains this file. If you
63          // need to do that level of checking, lookup the
64          // return values of stat which will give you
65          // more details on why stat failed.
66          blnReturn = false;
67        }
68      
69      return(blnReturn);
70     }
71     
72     
73     // =====================================================================
74     
75     std::string Utilities::ExtractPackageName(const std::string  &name, 
76                                           std::string& path)
77     {
78       std::string pkgname;
79       path = "";
80       
81       std::string::size_type slash_position = name.find_last_of("/\\");
82       if (slash_position != std::string::npos) 
83         {
84           pkgname = name.substr(slash_position+1,std::string::npos);
85           path = name.substr(0,slash_position);
86           //    std::cout << "F:P='"<<path<<"'"<<std::endl;//+1,std::string::npos);
87         }
88       else 
89         {
90           pkgname = name;
91         }
92       
93       // remove {.so | dll} if any
94       std::string::size_type dot_position = pkgname.find_last_of('.');      
95       if (dot_position != std::string::npos){
96         pkgname = pkgname.substr(0,dot_position);
97       }      
98 #if defined(__GNUC__)
99       
100       // GCC mechanism
101       // shared lib name = libbb<name>.so
102       
103       // remove {libbb} if any
104       if (memcmp ( pkgname.c_str(), "libbb", 5) == 0) {
105         pkgname =  pkgname.substr(5, pkgname.length());
106       }
107       /*
108      /// \ \todo     what would happen if (stupid) user names his package 'libbb' ?!?
109       /// \ --> Should be forbidden!
110       */
111 #elif defined(_WIN32)
112       
113       // WIN 32 mechanism
114       // shared lib name = <name>.dll
115       
116       // EED Problem loading package call bbtkTools
117       //     // remove {bb} if any
118       if (memcmp (pkgname.c_str(), "bb", 2) == 0) {
119         pkgname =  pkgname.substr(2, pkgname.length());  
120       }
121       
122       /*
123      /// \ \todo     what would happen if (stupid) user names his package 'bb' ?!?
124      /// \ --> Should be forbidden!
125      */
126 #else
127       bbtkError("neither __GNUC__ nor _WIN32 ?!? How did you compile ?");
128 #endif      
129       return pkgname;
130     }
131     
132     //=====================================================================
133     std::string Utilities::ExtractScriptName(const std::string &name,
134                                          std::string& path)
135     {
136       std::string pkgname;
137       
138       std::string::size_type slash_position = name.find_last_of("/\\");
139       if (slash_position != std::string::npos) {
140         pkgname =name.substr(slash_position+1,std::string::npos);
141         path = name.substr(0,slash_position);      
142       } else {
143         pkgname = name;
144       }
145       // remove {.bbs } if any
146       std::string::size_type dot_position = pkgname.find_last_of('.');
147       if (dot_position != std::string::npos){
148         pkgname = pkgname.substr(0,dot_position);
149       }
150       return pkgname;
151     }
152     
153     // ========================================================================
154
155     std::string Utilities::ExpandLibName(const std::string &name, bool verbose)
156     {
157       // -----   Think of expanding path name ( ./ ../ ../../ )
158       
159       char buf[2048]; // for getcwd
160       char * currentDir = getcwd(buf, 2048);
161       std::string cwd(currentDir);
162       std::string libname(name);
163       std::string fileSeparator;
164       fileSeparator = ConfigurationFile::GetInstance().Get_file_separator();
165       // tooHigh : true is user supplies a library pathname with too many "../"
166       bool tooHigh = false;
167       
168       //std::cout << "------------------cwd ["  << cwd << "] name [" << name << "]" << std::endl;
169       
170       if ( name[0] == '/' ||  name[1] == ':' ) // Linux or Windows absolute name
171         {
172           return(libname);
173         }
174       else if  ( name =="." )
175         {
176           libname = cwd  + fileSeparator;
177           return(libname);
178         }
179       else if  (name[0] == '.' && (name[1] == '/' || name[1] == '\\') )
180         {
181           libname = cwd  + fileSeparator + name.substr(2, name.length());
182           return(libname);
183         }
184       else if ( name[0] == '.' &&  name[1] == '.' /*  && (name[2] == '/' || name[2] == '\\') */ ) 
185         {
186           if ( IsAtRoot(cwd) )  // hope it gets / (for Linux),  C: D: (for Windows)
187       {  
188      // if we are already at / or c: --> hopeless  
189          if (verbose)
190            std::cout << "   File path [" <<  name << "] doesn't exist" << std::endl;
191          tooHigh = true;
192       }
193       else
194       {
195          // iterate on ../ and go up from the current working dir!
196          std::string a(name); 
197          bool alreadyProcessRoot = false;
198
199           //if (a[a.size()-1] != fileSeparator[0])
200           //   a.append(fileSeparator);
201 //std::cout << "------------------a ["  << a << "]" << std::endl;
202
203          for(;;)  // wild loop !
204          {
205             std::string::size_type slash_position = cwd.find_last_of(fileSeparator);
206             if (slash_position != std::string::npos) {
207              if (slash_position == 0)
208                 slash_position = 1;
209               cwd = cwd.substr(0,slash_position/*+1*/);
210 //std::cout << "------------------cwd ["  << cwd << "]" << std::endl;
211             //  if (a == "..") {
212             //    a = "";
213             //    break;
214             //   }
215             //   else
216                  a = a.substr(3, /*name.length()*/ a.length());  // remove ../
217 //std::cout << "------------------a ["  << a << "]" << std::endl;  
218               if (a == "" || alreadyProcessRoot)
219               {
220                 if (verbose)
221                   std::cout << "   File path : [" <<  name << "] doesn't exist" << std::endl;
222                 tooHigh = true;
223                 break;
224               }
225              // std::string b = cwd + a;
226               libname =  cwd;
227               char c = cwd[cwd.size()-1];
228               if (c != '/' && c != '\\' )
229                 libname += fileSeparator;
230               libname += a;
231
232               if ( a[0] != '.' ) // if . (probabely ../), loop again
233                 break;
234
235               if (IsAtRoot(cwd))
236                 alreadyProcessRoot = true;
237             }
238          } // end iterating on ../
239       }
240 //std::cout << "------------------out of loop]" << std::endl;        
241       if (tooHigh)
242          libname="";
243       return (libname);
244
245     }  // -----   End of expanding path name   ( ./ ../ ../../ )
246
247     std::cout <<"* ERROR in ExpandLibName : should never get here!" << std::endl;
248     // To avoid warning
249     return(""); // Will never get here!
250   }
251
252 // ===================================================================================
253
254   std::string Utilities::MakeLibnameFromPath(std::string path, std::string pkgname)
255   {
256     std::string libname = path;
257     char c = path[path.size()-1];    
258 #if defined(__GNUC__)
259        if (c != '/')
260           libname += "/libbb";
261        else
262           libname += "libbb";
263        libname += pkgname;
264 #if defined(MACOSX)
265           libname += ".dylib";
266 #else
267           libname += ".so";
268 #endif  
269           
270 #elif defined(_WIN32)
271        if (c != '\\')
272           libname = path+"\\bb";
273        libname += pkgname;
274        libname += ".dll";
275 #endif
276     return libname;    
277   }
278
279 // ===================================================================================
280
281   std::string Utilities::MakePkgnameFromPath(std::string path, std::string pkgname, bool addExt)
282   {
283     std::string libname = path;
284     char c = path[path.size()-1];
285     if (c != '/' && c != '\\')
286     {
287        libname +=  ConfigurationFile::GetInstance().Get_file_separator ();
288     }
289     libname += pkgname;
290     if (addExt)
291     {
292        int l = libname.size();
293        if (l>4)
294        {
295           if (libname.substr(l-4, 4) != ".bbs")
296           {
297                libname = libname + ".bbs";
298           }
299        }
300     }
301     return libname;
302   }
303   // =======================================================================
304
305   // =======================================================================
306   /// Returns the user settings dir, e.g. /home/username/.bbtk
307   std::string Utilities::GetUserSettingsDir()
308   {
309 #if defined(__GNUC__)
310     std::string str_home(getenv("HOME"));
311 #elif defined(_WIN32)
312     std::string str_home(getenv("USERPROFILE"));
313 #endif
314     std::string fullname = str_home + "/.bbtk";
315     MakeValidFileName(fullname);
316     return fullname;
317   }
318   
319
320   // =======================================================================
321   /// Builds the complete path to the file 'name' located 
322   /// in user settings dir, e.g. /home/username/.bbtk/
323   std::string Utilities::MakeUserSettingsFullFileName(const std::string& name)
324   {
325 #if defined(__GNUC__)
326     std::string str_home(getenv("HOME"));
327 #elif defined(_WIN32)
328     std::string str_home(getenv("USERPROFILE"));
329 #endif
330     std::string fullname = str_home + "/.bbtk/" + name;
331     MakeValidFileName(fullname);
332     return fullname;
333   }
334   // =======================================================================
335   
336
337   // =======================================================================
338   void Utilities::CreateDirectoryIfNeeded( std::string const &dirName)
339   {
340     if (FileExists(dirName)) return;
341     std::string cmd("mkdir \"");
342     cmd += dirName;
343     cmd += "\"";
344     system(cmd.c_str());
345   }  
346   // =======================================================================
347   
348   
349   //========================================================================
350   bool Utilities::IsAtRoot(std::string cwd)
351   {
352     if ( cwd == "/"              // hope it gets /     (for Linux)
353          || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
354       return (true);
355     else
356       return(false);
357   }
358   // ======================================================================
359
360   // ======================================================================
361   bool Utilities::IsDirectory(std::string const &dirName)
362   {
363     struct stat fs;
364     
365     if ( stat(dirName.c_str(), &fs) == 0 )
366       {
367 #if _WIN32
368         return ((fs.st_mode & _S_IFDIR) != 0);
369 #else
370         return S_ISDIR(fs.st_mode);
371 #endif
372       }
373     else
374       {
375         return false;
376       }
377   }
378   // =======================================================================
379     
380   // =======================================================================
381   void Utilities::SplitAroundFirstDot( const std::string& in,
382                                        std::string& left,
383                                        std::string& right)
384   {
385     std::string delimiter = ".";
386     std::string::size_type pos = in.find_first_of(delimiter);
387     if (std::string::npos != pos) 
388       {
389         left = in.substr(0,pos);
390         right = in.substr(pos+1,in.size());
391         
392       }
393     else
394       {
395         left ="";
396         right = "";
397         bbtkGlobalError("Token '"<<in<<"' : expected 'a.b' format but no dot found");
398       }
399   }
400   //=======================================================================
401
402   //=======================================================================
403   void Utilities::SplitString ( const std::string& str, 
404                                 const std::string& delimiters, 
405                                 std::vector<std::string>& tokens)
406   {
407     // Skip delimiters at beginning.
408     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
409     // Find first delimiter.
410     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
411     
412     while (std::string::npos != pos || std::string::npos != lastPos)
413       {
414         // Found a token, add it to the vector.
415         tokens.push_back(str.substr(lastPos, pos - lastPos));
416         // Skip delimiters.  Note the "not_of"
417         lastPos = str.find_first_not_of(delimiters, pos);
418         // Find next delimiter
419         pos = str.find_first_of(delimiters, lastPos);
420       }
421     
422   }
423   //=======================================================================
424   
425   
426   // ======================================================================
427   std::string Utilities::get_file_name(const std::string& s) 
428   { 
429     std::string::size_type slash_position = s.find_last_of("/\\");
430     if (slash_position != std::string::npos) 
431       {
432         return  s.substr(slash_position+1,std::string::npos);   
433       }
434     else 
435       {
436         return s;
437       }
438   }
439   //=======================================================================
440  
441
442   // ========================================================================
443   /**
444    * \brief   Explore a directory with possibility of recursion
445    *          return number of files read
446    * @param  dirpath   directory to explore
447    * @param  recursive whether we want recursion or not
448    */
449   int Utilities::Explore(std::string const &dirpath, bool recursive, std::vector<std::string> &Filenames)
450   {
451     int numberOfFiles = 0;
452     std::string fileName;
453       
454       std::string dirName = dirpath;
455       
456 #ifdef _MSC_VER
457       WIN32_FIND_DATA fileData;
458    HANDLE hFile = FindFirstFile((dirName+"\\*").c_str(), &fileData);
459
460    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
461        b = FindNextFile(hFile, &fileData))
462    {
463       fileName = fileData.cFileName;
464       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
465       {
466          // Need to check for . and .. to avoid infinite loop
467          if ( fileName != "." && fileName != ".." && recursive )
468          {
469             numberOfFiles += Explore(dirName+ "\\"+fileName,recursive,Filenames);
470          }
471       }
472       else
473       {
474          Filenames.push_back(dirName+"\\"+fileName);
475          numberOfFiles++;
476       }
477    }
478    DWORD dwError = GetLastError();
479    if (hFile != INVALID_HANDLE_VALUE) 
480       FindClose(hFile);
481    if (dwError != ERROR_NO_MORE_FILES) 
482    {
483       LPVOID lpMsgBuf;
484       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
485                     FORMAT_MESSAGE_FROM_SYSTEM|
486                     FORMAT_MESSAGE_IGNORE_INSERTS,
487                     NULL,GetLastError(),
488                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
489                     (LPTSTR) &lpMsgBuf,0,NULL);
490
491      // ErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
492      //             <<" for the directory : "<<dirName);
493       
494       return 0;
495    }
496
497 #else
498   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
499   // work on debian for example
500 //std::cout <<"in Explor dirname[" << dirName << "]" << std::endl; 
501    DIR* dir = opendir(dirName.c_str());
502    if (!dir)
503    {
504       return 0;
505    }
506 //std::cout <<"Open OK" << std::endl; 
507    // According to POSIX, the dirent structure contains a field char d_name[]
508    // of unspecified size, with at most NAME_MAX characters preceeding the
509    // terminating null character. Use of other fields will harm the  porta-
510    // bility of your programs.
511
512    struct stat buf;
513    dirent *d;
514    for (d = readdir(dir); d; d = readdir(dir))
515    {
516       fileName = dirName + "/" + d->d_name;
517 //std::cout <<"in Explor filename[" << fileName << "]" << std::endl;      
518       if( stat(fileName.c_str(), &buf) != 0 )
519       {
520          //ErrorMacro( strerror(errno) );
521       }
522       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
523       {
524          Filenames.push_back( fileName );
525          numberOfFiles++;
526       }
527       else if ( S_ISDIR(buf.st_mode) ) //directory?
528       {
529          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
530          {
531             numberOfFiles += Explore( fileName, recursive, Filenames);
532          }
533       }
534       else
535       {
536          //ErrorMacro( "Unexpected error" );
537          return -1;
538       }
539    }
540    if( closedir(dir) != 0 )
541    {
542      // ErrorMacro( strerror(errno) );
543    }
544 #endif
545
546   return numberOfFiles;
547
548 }
549   //=======================================================================
550  
551
552     //=======================================================================
553     // Replaces substrings "\\n" by a real carriage return "\n"
554     void Utilities::SubsBackslashN ( std::string& s )
555     {
556       std::string ss("\\n");
557       std::string::size_type pos = 0;
558       pos = s.find(ss,0);
559       const char* cr = "\n";
560       while ( pos != std::string::npos )
561         {
562           s.replace(pos,2,cr,1);
563           pos = s.find(ss, pos-1);
564         }
565     }
566     //=======================================================================
567
568
569    //=======================================================================
570
571   bool Utilities::loosematch(std::string stdLine,std::string stdOptions) 
572   {
573     bool result=false;
574     std::vector<std::string> tokens;
575     SplitString ( stdOptions,"|", tokens);
576     int i,size=tokens.size();  
577     for (i=0; i<size; i++)
578       {           
579 #ifdef WIN32
580         if ( strcmpi(stdLine.c_str(),tokens[i].c_str())==0) 
581           { 
582             result=true; 
583           }               
584 #else
585         if ( strcasecmp(stdLine.c_str(),tokens[i].c_str())==0) 
586           { 
587             result=true; 
588           }               
589 #endif
590         
591       }
592     return result;
593   }
594   //=========================================================================  
595   
596   //=========================================================================  
597   // From http://www.fltk.org/newsgroups.php?gfltk.general+v:22083
598   //
599   int get_app_path (char *pname, size_t pathsize)
600   {
601 #ifdef LINUX
602     /* Oddly, the readlink(2) man page says no NULL is appended. */
603     /* So you have to do it yourself, based on the return value: */
604     pathsize --; /* Preserve a space to add the trailing NULL */
605     long result = readlink("/proc/self/exe", pname, pathsize);
606     if (result > 0)
607       {
608         pname[result] = 0; /* add the #@!%ing NULL */
609         
610         if ((access(pname, 0) == 0))
611           return 0; /* file exists, return OK */
612         /*else name doesn't seem to exist, return FAIL (falls
613           through) */
614       }
615 #endif /* LINUX */
616     
617 #ifdef WIN32
618     long result = GetModuleFileName(NULL, pname, pathsize);
619     if (result > 0)
620       {
621         /* fix up the dir slashes... */
622         int len = strlen(pname);
623         int idx;
624         for (idx = 0; idx < len; idx++)
625           {
626             if (pname[idx] == '\\') pname[idx] = '/';
627           }
628         
629         for (idx = len-1; idx >=0 ; idx--)
630           {
631             if (pname[idx] == '/')
632               { 
633                 pname[idx+1] = '\0';
634                 idx = -1;
635               }
636           }
637         
638         if ((access(pname, 0) == 0))
639           return 0; /* file exists, return OK */
640         /*else name doesn't seem to exist, return FAIL (falls
641           through) */
642       }
643 #endif /* WIN32 */
644     
645 #ifdef SOLARIS
646     char *p = getexecname();
647     if (p)
648       {
649         /* According to the Sun manpages, getexecname will
650            "normally" return an */
651         /* absolute path - BUT might not... AND that IF it is not,
652            pre-pending */
653         /* getcwd() will "usually" be the correct thing... Urgh!
654          */
655         
656         /* check pathname is absolute (begins with a / ???) */
657         if (p[0] == '/') /* assume this means we have an
658                             absolute path */
659           {
660             strncpy(pname, p, pathsize);
661             if ((access(pname, 0) == 0))
662               return 0; /* file exists, return OK */
663           }
664         else /* if not, prepend getcwd() then check if file
665                 exists */
666           {
667             getcwd(pname, pathsize);
668             long result = strlen(pname);
669             strncat(pname, "/", (pathsize - result));
670             result ++;
671             strncat(pname, p, (pathsize - result));
672             
673             if ((access(pname, 0) == 0))
674               return 0; /* file exists, return OK */
675             /*else name doesn't seem to exist, return FAIL
676               (falls through) */
677           }
678       }
679 #endif /* SOLARIS */
680     
681 #ifdef MACOSX /* assume this is OSX */
682     /*
683       from http://www.hmug.org/man/3/NSModule.html
684       
685       extern int _NSGetExecutablePath(char *buf, unsigned long
686       *bufsize);
687       
688       _NSGetExecutablePath  copies  the  path  of the executable
689       into the buffer and returns 0 if the path was successfully
690       copied  in the provided buffer. If the buffer is not large
691       enough, -1 is returned and the  expected  buffer  size  is
692       copied  in  *bufsize.  Note that _NSGetExecutablePath will
693       return "a path" to the executable not a "real path" to the
694       executable.  That  is  the path may be a symbolic link and
695       not the real file. And with  deep  directories  the  total
696       bufsize needed could be more than MAXPATHLEN.
697     */
698     int status = -1;
699     char *given_path = (char*)malloc(MAXPATHLEN * 2);
700     if (!given_path) return status;
701     
702     uint32_t npathsize = MAXPATHLEN * 2;
703     long result = _NSGetExecutablePath(given_path, &npathsize);
704     if (result == 0)
705       { /* OK, we got something - now try and resolve the real path...
706          */
707         if (realpath(given_path, pname) != NULL)
708           {
709             if ((access(pname, 0) == 0))
710               status = 0; /* file exists, return OK */
711           }
712       }
713     free (given_path);
714     return status;
715 #endif /* MACOSX */
716     
717     return -1; /* Path Lookup Failed */
718   } 
719   //=========================================================================
720         
721
722         
723   //=========================================================================
724   std::string Utilities::GetExecutablePath()
725   {
726     char name[PATH_MAX];
727     int err = get_app_path(name, PATH_MAX);
728     if (err) 
729       {
730         bbtkGlobalError("Could not determine current executable path ?");  
731       }
732     
733     // remove the exe name
734     char *slash;                
735     slash = strrchr(name, VALID_FILE_SEPARATOR_CHAR);
736     if (slash)
737       {
738         *slash = 0;
739       }
740     return name;
741   }
742   //=========================================================================
743
744
745
746 }