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