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