]> Creatis software - bbtk.git/blob - kernel/src/bbtkUtilities.cxx
b0eda99f67cbd9db5739e83436edf08c74be4660
[bbtk.git] / kernel / src / bbtkUtilities.cxx
1 /*=========================================================================                                                                               
2   Program:   bbtk
3   Module:    $RCSfile: bbtkUtilities.cxx,v $
4   Language:  C++
5   Date:      $Date: 2008/11/12 12:47:01 $
6   Version:   $Revision: 1.8 $
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
34  
35
36 namespace bbtk
37 {
38
39
40
41             // ======================================================================
42     // See : http://www.techbytes.ca/techbyte103.html for more O.S.
43     bool Utilities::FileExists(std::string strFilename) 
44     {
45       struct stat stFileInfo;
46      bool blnReturn;
47      int intStat;
48      
49      // Attempt to get the file attributes
50      intStat = stat(strFilename.c_str(),&stFileInfo);
51      if(intStat == 0) 
52        {
53          // We were able to get the file attributes
54          // so the file obviously exists.
55          blnReturn = true;
56        } 
57      else 
58        {
59          // We were not able to get the file attributes.
60          // This may mean that we don't have permission to
61          // access the folder which contains this file. If you
62          // need to do that level of checking, lookup the
63          // return values of stat which will give you
64          // more details on why stat failed.
65          blnReturn = false;
66        }
67      
68      return(blnReturn);
69     }
70     
71     
72     // =====================================================================
73     
74     std::string Utilities::ExtractPackageName(const std::string  &name, 
75                                           std::string& path)
76     {
77       std::string pkgname;
78       path = "";
79       
80       std::string::size_type slash_position = name.find_last_of("/\\");
81       if (slash_position != std::string::npos) 
82         {
83           pkgname = name.substr(slash_position+1,std::string::npos);
84           path = name.substr(0,slash_position);
85           //    std::cout << "F:P='"<<path<<"'"<<std::endl;//+1,std::string::npos);
86         }
87       else 
88         {
89           pkgname = name;
90         }
91       
92       // remove {.so | dll} if any
93       std::string::size_type dot_position = pkgname.find_last_of('.');      
94       if (dot_position != std::string::npos){
95         pkgname = pkgname.substr(0,dot_position);
96       }      
97 #if defined(__GNUC__)
98       
99       // GCC mechanism
100       // shared lib name = libbb<name>.so
101       
102       // remove {libbb} if any
103       if (memcmp ( pkgname.c_str(), "libbb", 5) == 0) {
104         pkgname =  pkgname.substr(5, pkgname.length());
105       }
106       /*
107      /// \ \todo     what would happen if (stupid) user names his package 'libbb' ?!?
108       /// \ --> Should be forbidden!
109       */
110 #elif defined(_WIN32)
111       
112       // WIN 32 mechanism
113       // shared lib name = <name>.dll
114       
115       // EED Problem loading package call bbtkTools
116       //     // remove {bb} if any
117       if (memcmp (pkgname.c_str(), "bb", 2) == 0) {
118         pkgname =  pkgname.substr(2, pkgname.length());  
119       }
120       
121       /*
122      /// \ \todo     what would happen if (stupid) user names his package 'bb' ?!?
123      /// \ --> Should be forbidden!
124      */
125 #else
126       bbtkError("neither __GNUC__ nor _WIN32 ?!? How did you compile ?");
127 #endif      
128       return pkgname;
129     }
130     
131     //=====================================================================
132     std::string Utilities::ExtractScriptName(const std::string &name,
133                                          std::string& path)
134     {
135       std::string pkgname;
136       
137       std::string::size_type slash_position = name.find_last_of("/\\");
138       if (slash_position != std::string::npos) {
139         pkgname =name.substr(slash_position+1,std::string::npos);
140         path = name.substr(0,slash_position);      
141       } else {
142         pkgname = name;
143       }
144       // remove {.bbs } if any
145       std::string::size_type dot_position = pkgname.find_last_of('.');
146       if (dot_position != std::string::npos){
147         pkgname = pkgname.substr(0,dot_position);
148       }
149       return pkgname;
150     }
151     
152     // ========================================================================
153
154     std::string Utilities::ExpandLibName(const std::string &name, bool verbose)
155     {
156       // -----   Think of expanding path name ( ./ ../ ../../ )
157       
158       char buf[2048]; // for getcwd
159       char * currentDir = getcwd(buf, 2048);
160       std::string cwd(currentDir);
161       std::string libname(name);
162       std::string fileSeparator;
163       fileSeparator = ConfigurationFile::GetInstance().Get_file_separator();
164       // tooHigh : true is user supplies a library pathname with too many "../"
165       bool tooHigh = false;
166       
167       //std::cout << "------------------cwd ["  << cwd << "] name [" << name << "]" << std::endl;
168       
169       if ( name[0] == '/' ||  name[1] == ':' ) // Linux or Windows absolute name
170         {
171           return(libname);
172         }
173       else if  ( name =="." )
174         {
175           libname = cwd  + fileSeparator;
176           return(libname);
177         }
178       else if  (name[0] == '.' && (name[1] == '/' || name[1] == '\\') )
179         {
180           libname = cwd  + fileSeparator + name.substr(2, name.length());
181           return(libname);
182         }
183       else if ( name[0] == '.' &&  name[1] == '.' /*  && (name[2] == '/' || name[2] == '\\') */ ) 
184         {
185           if ( IsAtRoot(cwd) )  // hope it gets / (for Linux),  C: D: (for Windows)
186       {  
187      // if we are already at / or c: --> hopeless  
188          if (verbose)
189            std::cout << "   File path [" <<  name << "] doesn't exist" << std::endl;
190          tooHigh = true;
191       }
192       else
193       {
194          // iterate on ../ and go up from the current working dir!
195          std::string a(name); 
196          bool alreadyProcessRoot = false;
197
198           //if (a[a.size()-1] != fileSeparator[0])
199           //   a.append(fileSeparator);
200 //std::cout << "------------------a ["  << a << "]" << std::endl;
201
202          for(;;)  // wild loop !
203          {
204             std::string::size_type slash_position = cwd.find_last_of(fileSeparator);
205             if (slash_position != std::string::npos) {
206              if (slash_position == 0)
207                 slash_position = 1;
208               cwd = cwd.substr(0,slash_position/*+1*/);
209 //std::cout << "------------------cwd ["  << cwd << "]" << std::endl;
210             //  if (a == "..") {
211             //    a = "";
212             //    break;
213             //   }
214             //   else
215                  a = a.substr(3, /*name.length()*/ a.length());  // remove ../
216 //std::cout << "------------------a ["  << a << "]" << std::endl;  
217               if (a == "" || alreadyProcessRoot)
218               {
219                 if (verbose)
220                   std::cout << "   File path : [" <<  name << "] doesn't exist" << std::endl;
221                 tooHigh = true;
222                 break;
223               }
224              // std::string b = cwd + a;
225               libname =  cwd;
226               char c = cwd[cwd.size()-1];
227               if (c != '/' && c != '\\' )
228                 libname += fileSeparator;
229               libname += a;
230
231               if ( a[0] != '.' ) // if . (probabely ../), loop again
232                 break;
233
234               if (IsAtRoot(cwd))
235                 alreadyProcessRoot = true;
236             }
237          } // end iterating on ../
238       }
239 //std::cout << "------------------out of loop]" << std::endl;        
240       if (tooHigh)
241          libname="";
242       return (libname);
243
244     }  // -----   End of expanding path name   ( ./ ../ ../../ )
245
246     std::cout <<"* ERROR in ExpandLibName : should never get here!" << std::endl;
247     // To avoid warning
248     return(""); // Will never get here!
249   }
250
251 // ===================================================================================
252
253   std::string Utilities::MakeLibnameFromPath(std::string path, std::string pkgname)
254   {
255     std::string libname = path;
256     char c = path[path.size()-1];    
257 #if defined(__GNUC__)
258        if (c != '/')
259           libname += "/libbb";
260        else
261           libname += "libbb";
262        libname += pkgname;
263 #if defined(MACOSX)
264           libname += ".dylib";
265 #else
266           libname += ".so";
267 #endif  
268           
269 #elif defined(_WIN32)
270        if (c != '\\')
271           libname = path+"\\bb";
272        libname += pkgname;
273        libname += ".dll";
274 #endif
275     return libname;    
276   }
277
278 // ===================================================================================
279
280   std::string Utilities::MakePkgnameFromPath(std::string path, std::string pkgname, bool addExt)
281   {
282     std::string libname = path;
283     char c = path[path.size()-1];
284     if (c != '/' && c != '\\')
285     {
286        libname +=  ConfigurationFile::GetInstance().Get_file_separator ();
287     }
288     libname += pkgname;
289     if (addExt)
290     {
291        int l = libname.size();
292        if (l>4)
293        {
294           if (libname.substr(l-4, 4) != ".bbs")
295           {
296                libname = libname + ".bbs";
297           }
298        }
299     }
300     return libname;
301   }
302
303   // =======================================================================
304   /// Builds the complete path to the file 'name' located 
305   /// in user settings dir, e.g. /home/username/.bbtk/
306   std::string Utilities::MakeUserSettingsFullFileName(const std::string& name)
307   {
308 #if defined(__GNUC__)
309     std::string str_home(getenv("HOME"));
310 #elif defined(_WIN32)
311     std::string str_home(getenv("USERPROFILE"));
312 #endif
313     std::string fullname = str_home + "/.bbtk/" + name;
314     Utilities::replace( fullname, 
315                         INVALID_FILE_SEPARATOR , 
316                         VALID_FILE_SEPARATOR);
317     return fullname;
318   }
319   
320
321
322     //========================================================================
323     
324     bool Utilities::IsAtRoot(std::string cwd)
325     {
326       if ( cwd == "/"              // hope it gets /     (for Linux)
327            || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
328         return (true);
329       else
330         return(false);
331     }
332     
333     // ======================================================================
334     
335     bool Utilities::IsDirectory(std::string const &dirName)
336     {
337       struct stat fs;
338       
339       if ( stat(dirName.c_str(), &fs) == 0 )
340         {
341 #if _WIN32
342           return ((fs.st_mode & _S_IFDIR) != 0);
343 #else
344           return S_ISDIR(fs.st_mode);
345 #endif
346         }
347       else
348         {
349           return false;
350         }
351     }
352     
353     // ===================================================================================
354     
355     void Utilities::SplitAroundFirstDot( const std::string& in,
356                                             std::string& left,
357                                             std::string& right)
358     {
359       std::string delimiter = ".";
360       std::string::size_type pos = in.find_first_of(delimiter);
361       if (std::string::npos != pos) 
362         {
363           left = in.substr(0,pos);
364           right = in.substr(pos+1,in.size());
365           
366         }
367       else
368         {
369           // bbtkError(in<<" : expected 'a.b' format but no dot found");
370           left ="";
371           right = "";
372         }
373     }
374     //=======================================================================
375     void Utilities::SplitString ( const std::string& str, 
376                                      const std::string& delimiters, 
377                                      std::vector<std::string>& tokens)
378     {
379       // Skip delimiters at beginning.
380       std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
381       // Find first delimiter.
382       std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
383       
384       while (std::string::npos != pos || std::string::npos != lastPos)
385         {
386           // Found a token, add it to the vector.
387           tokens.push_back(str.substr(lastPos, pos - lastPos));
388           // Skip delimiters.  Note the "not_of"
389           lastPos = str.find_first_not_of(delimiters, pos);
390           // Find next delimiter
391           pos = str.find_first_of(delimiters, lastPos);
392         }
393       
394     }
395     //=======================================================================
396     
397     
398     // ===================================================================================
399     
400     std::string Utilities::get_file_name(const std::string& s) 
401     { 
402       std::string::size_type slash_position = s.find_last_of("/\\");
403       if (slash_position != std::string::npos) 
404         {
405           return  s.substr(slash_position+1,std::string::npos);   
406         }
407       else 
408         {
409           return s;
410         }
411     }
412     
413     // ===================================================================================
414     /**
415      * \brief   Explore a directory with possibility of recursion
416      *          return number of files read
417      * @param  dirpath   directory to explore
418      * @param  recursive whether we want recursion or not
419      */
420     int Utilities::Explore(std::string const &dirpath, bool recursive, std::vector<std::string> &Filenames)
421     {
422       int numberOfFiles = 0;
423       std::string fileName;
424       
425       std::string dirName = dirpath;
426       
427 #ifdef _MSC_VER
428       WIN32_FIND_DATA fileData;
429    HANDLE hFile = FindFirstFile((dirName+"\\*").c_str(), &fileData);
430
431    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
432        b = FindNextFile(hFile, &fileData))
433    {
434       fileName = fileData.cFileName;
435       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
436       {
437          // Need to check for . and .. to avoid infinite loop
438          if ( fileName != "." && fileName != ".." && recursive )
439          {
440             numberOfFiles += Explore(dirName+ "\\"+fileName,recursive,Filenames);
441          }
442       }
443       else
444       {
445          Filenames.push_back(dirName+"\\"+fileName);
446          numberOfFiles++;
447       }
448    }
449    DWORD dwError = GetLastError();
450    if (hFile != INVALID_HANDLE_VALUE) 
451       FindClose(hFile);
452    if (dwError != ERROR_NO_MORE_FILES) 
453    {
454       LPVOID lpMsgBuf;
455       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
456                     FORMAT_MESSAGE_FROM_SYSTEM|
457                     FORMAT_MESSAGE_IGNORE_INSERTS,
458                     NULL,GetLastError(),
459                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
460                     (LPTSTR) &lpMsgBuf,0,NULL);
461
462      // ErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
463      //             <<" for the directory : "<<dirName);
464       
465       return 0;
466    }
467
468 #else
469   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
470   // work on debian for example
471 //std::cout <<"in Explor dirname[" << dirName << "]" << std::endl; 
472    DIR* dir = opendir(dirName.c_str());
473    if (!dir)
474    {
475       return 0;
476    }
477 //std::cout <<"Open OK" << std::endl; 
478    // According to POSIX, the dirent structure contains a field char d_name[]
479    // of unspecified size, with at most NAME_MAX characters preceeding the
480    // terminating null character. Use of other fields will harm the  porta-
481    // bility of your programs.
482
483    struct stat buf;
484    dirent *d;
485    for (d = readdir(dir); d; d = readdir(dir))
486    {
487       fileName = dirName + "/" + d->d_name;
488 //std::cout <<"in Explor filename[" << fileName << "]" << std::endl;      
489       if( stat(fileName.c_str(), &buf) != 0 )
490       {
491          //ErrorMacro( strerror(errno) );
492       }
493       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
494       {
495          Filenames.push_back( fileName );
496          numberOfFiles++;
497       }
498       else if ( S_ISDIR(buf.st_mode) ) //directory?
499       {
500          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
501          {
502             numberOfFiles += Explore( fileName, recursive, Filenames);
503          }
504       }
505       else
506       {
507          //ErrorMacro( "Unexpected error" );
508          return -1;
509       }
510    }
511    if( closedir(dir) != 0 )
512    {
513      // ErrorMacro( strerror(errno) );
514    }
515 #endif
516
517   return numberOfFiles;
518
519 }
520
521
522     //=======================================================================
523     // Replaces substrings "\\n" by a real carriage return "\n"
524     void Utilities::SubsBackslashN ( std::string& s )
525     {
526       std::string ss("\\n");
527       std::string::size_type pos = 0;
528       pos = s.find(ss,0);
529       char* cr = "\n";
530       while ( pos != std::string::npos )
531         {
532           s.replace(pos,2,cr,1);
533           pos = s.find(ss, pos-1);
534         }
535     }
536     //=======================================================================
537
538
539
540 bool Utilities::loosematch(std::string stdLine,std::string stdOptions) 
541 {
542         bool result=false;
543           std::vector<std::string> tokens;
544           SplitString ( stdOptions,"|", tokens);
545           int i,size=tokens.size();  
546           for (i=0; i<size; i++)
547           {               
548 #ifdef WIN32
549                   if ( strcmpi(stdLine.c_str(),tokens[i].c_str())==0) 
550                   { 
551                           result=true; 
552                   }               
553 #else
554                   if ( strcasecmp(stdLine.c_str(),tokens[i].c_str())==0) 
555                   { 
556                           result=true; 
557                   }               
558 #endif
559
560           }
561           return result;
562 }
563
564
565
566 }