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