]> Creatis software - bbtk.git/blob - kernel/src/bbtkUtilities.cxx
Fixed SplitAroundFirstDot which did not throw on error
[bbtk.git] / kernel / src / bbtkUtilities.cxx
1 /*=========================================================================                                                                               
2   Program:   bbtk
3   Module:    $RCSfile: bbtkUtilities.cxx,v $
4   Language:  C++
5   Date:      $Date: 2008/11/26 12:49:57 $
6   Version:   $Revision: 1.9 $
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   /// Builds the complete path to the file 'name' located 
306   /// in user settings dir, e.g. /home/username/.bbtk/
307   std::string Utilities::MakeUserSettingsFullFileName(const std::string& name)
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/" + name;
315     Utilities::replace( fullname, 
316                         INVALID_FILE_SEPARATOR , 
317                         VALID_FILE_SEPARATOR);
318     return fullname;
319   }
320   
321
322
323     //========================================================================
324     
325     bool Utilities::IsAtRoot(std::string cwd)
326     {
327       if ( cwd == "/"              // hope it gets /     (for Linux)
328            || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
329         return (true);
330       else
331         return(false);
332     }
333     
334     // ======================================================================
335     
336     bool Utilities::IsDirectory(std::string const &dirName)
337     {
338       struct stat fs;
339       
340       if ( stat(dirName.c_str(), &fs) == 0 )
341         {
342 #if _WIN32
343           return ((fs.st_mode & _S_IFDIR) != 0);
344 #else
345           return S_ISDIR(fs.st_mode);
346 #endif
347         }
348       else
349         {
350           return false;
351         }
352     }
353     
354     // ===================================================================================
355     
356     void Utilities::SplitAroundFirstDot( const std::string& in,
357                                             std::string& left,
358                                             std::string& right)
359     {
360       std::string delimiter = ".";
361       std::string::size_type pos = in.find_first_of(delimiter);
362       if (std::string::npos != pos) 
363         {
364           left = in.substr(0,pos);
365           right = in.substr(pos+1,in.size());
366           
367         }
368       else
369         {
370           left ="";
371           right = "";
372           bbtkGlobalError("Token '"<<in<<"' : expected 'a.b' format but no dot found");
373         }
374     }
375     //=======================================================================
376     void Utilities::SplitString ( const std::string& str, 
377                                      const std::string& delimiters, 
378                                      std::vector<std::string>& tokens)
379     {
380       // Skip delimiters at beginning.
381       std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
382       // Find first delimiter.
383       std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
384       
385       while (std::string::npos != pos || std::string::npos != lastPos)
386         {
387           // Found a token, add it to the vector.
388           tokens.push_back(str.substr(lastPos, pos - lastPos));
389           // Skip delimiters.  Note the "not_of"
390           lastPos = str.find_first_not_of(delimiters, pos);
391           // Find next delimiter
392           pos = str.find_first_of(delimiters, lastPos);
393         }
394       
395     }
396     //=======================================================================
397     
398     
399     // ===================================================================================
400     
401     std::string Utilities::get_file_name(const std::string& s) 
402     { 
403       std::string::size_type slash_position = s.find_last_of("/\\");
404       if (slash_position != std::string::npos) 
405         {
406           return  s.substr(slash_position+1,std::string::npos);   
407         }
408       else 
409         {
410           return s;
411         }
412     }
413     
414     // ===================================================================================
415     /**
416      * \brief   Explore a directory with possibility of recursion
417      *          return number of files read
418      * @param  dirpath   directory to explore
419      * @param  recursive whether we want recursion or not
420      */
421     int Utilities::Explore(std::string const &dirpath, bool recursive, std::vector<std::string> &Filenames)
422     {
423       int numberOfFiles = 0;
424       std::string fileName;
425       
426       std::string dirName = dirpath;
427       
428 #ifdef _MSC_VER
429       WIN32_FIND_DATA fileData;
430    HANDLE hFile = FindFirstFile((dirName+"\\*").c_str(), &fileData);
431
432    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
433        b = FindNextFile(hFile, &fileData))
434    {
435       fileName = fileData.cFileName;
436       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
437       {
438          // Need to check for . and .. to avoid infinite loop
439          if ( fileName != "." && fileName != ".." && recursive )
440          {
441             numberOfFiles += Explore(dirName+ "\\"+fileName,recursive,Filenames);
442          }
443       }
444       else
445       {
446          Filenames.push_back(dirName+"\\"+fileName);
447          numberOfFiles++;
448       }
449    }
450    DWORD dwError = GetLastError();
451    if (hFile != INVALID_HANDLE_VALUE) 
452       FindClose(hFile);
453    if (dwError != ERROR_NO_MORE_FILES) 
454    {
455       LPVOID lpMsgBuf;
456       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
457                     FORMAT_MESSAGE_FROM_SYSTEM|
458                     FORMAT_MESSAGE_IGNORE_INSERTS,
459                     NULL,GetLastError(),
460                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
461                     (LPTSTR) &lpMsgBuf,0,NULL);
462
463      // ErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
464      //             <<" for the directory : "<<dirName);
465       
466       return 0;
467    }
468
469 #else
470   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
471   // work on debian for example
472 //std::cout <<"in Explor dirname[" << dirName << "]" << std::endl; 
473    DIR* dir = opendir(dirName.c_str());
474    if (!dir)
475    {
476       return 0;
477    }
478 //std::cout <<"Open OK" << std::endl; 
479    // According to POSIX, the dirent structure contains a field char d_name[]
480    // of unspecified size, with at most NAME_MAX characters preceeding the
481    // terminating null character. Use of other fields will harm the  porta-
482    // bility of your programs.
483
484    struct stat buf;
485    dirent *d;
486    for (d = readdir(dir); d; d = readdir(dir))
487    {
488       fileName = dirName + "/" + d->d_name;
489 //std::cout <<"in Explor filename[" << fileName << "]" << std::endl;      
490       if( stat(fileName.c_str(), &buf) != 0 )
491       {
492          //ErrorMacro( strerror(errno) );
493       }
494       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
495       {
496          Filenames.push_back( fileName );
497          numberOfFiles++;
498       }
499       else if ( S_ISDIR(buf.st_mode) ) //directory?
500       {
501          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
502          {
503             numberOfFiles += Explore( fileName, recursive, Filenames);
504          }
505       }
506       else
507       {
508          //ErrorMacro( "Unexpected error" );
509          return -1;
510       }
511    }
512    if( closedir(dir) != 0 )
513    {
514      // ErrorMacro( strerror(errno) );
515    }
516 #endif
517
518   return numberOfFiles;
519
520 }
521
522
523     //=======================================================================
524     // Replaces substrings "\\n" by a real carriage return "\n"
525     void Utilities::SubsBackslashN ( std::string& s )
526     {
527       std::string ss("\\n");
528       std::string::size_type pos = 0;
529       pos = s.find(ss,0);
530       char* cr = "\n";
531       while ( pos != std::string::npos )
532         {
533           s.replace(pos,2,cr,1);
534           pos = s.find(ss, pos-1);
535         }
536     }
537     //=======================================================================
538
539
540
541 bool Utilities::loosematch(std::string stdLine,std::string stdOptions) 
542 {
543         bool result=false;
544           std::vector<std::string> tokens;
545           SplitString ( stdOptions,"|", tokens);
546           int i,size=tokens.size();  
547           for (i=0; i<size; i++)
548           {               
549 #ifdef WIN32
550                   if ( strcmpi(stdLine.c_str(),tokens[i].c_str())==0) 
551                   { 
552                           result=true; 
553                   }               
554 #else
555                   if ( strcasecmp(stdLine.c_str(),tokens[i].c_str())==0) 
556                   { 
557                           result=true; 
558                   }               
559 #endif
560
561           }
562           return result;
563 }
564
565
566
567 }