]> Creatis software - bbtk.git/blob - kernel/src/bbtkUtilities.h
BUG slash
[bbtk.git] / kernel / src / bbtkUtilities.h
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkUtilities.h,v $
5   Language:  C++
6   Date:      $Date: 2008/03/10 06:24:13 $
7   Version:   $Revision: 1.13 $
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 // EED Problem loading package call bbtkTools
132 //     // remove {bb} if any
133     if (memcmp (pkgname.c_str(), "bb", 2) == 0) {
134        pkgname =  pkgname.substr(2, pkgname.length());  
135     }
136
137      /*
138      /// \ \todo     what would happen if (stupid) user names his package 'bb' ?!?
139      /// \ --> Should be forbidden!
140      */
141 #else
142     bbtkError("neither __GNUC__ nor _WIN32 ?!? How did you compile ?");
143 #endif      
144     return pkgname;
145   }
146
147 // ===================================================================================
148
149   static std::string ExtractScriptName(const std::string &name,
150                                           std::string& path)
151   {
152     std::string pkgname;
153
154     std::string::size_type slash_position = name.find_last_of("/\\");
155     if (slash_position != std::string::npos) {
156       pkgname =name.substr(slash_position+1,std::string::npos);
157           path = name.substr(0,slash_position);      
158     } else {
159       pkgname = name;
160     }
161     // remove {.bbs } if any
162     std::string::size_type dot_position = pkgname.find_last_of('.');
163     if (dot_position != std::string::npos){
164       pkgname = pkgname.substr(0,dot_position);
165     }
166     return pkgname;
167   }
168
169 // ===================================================================================
170
171   static std::string ExpandLibName(const std::string &name, bool verbose)
172   {
173      // -----   Think of expanding path name ( ./ ../ ../../ )
174
175     char buf[2048]; // for getcwd
176     char * currentDir = getcwd(buf, 2048);
177     std::string cwd(currentDir);
178     std::string libname(name);
179     std::string fileSeparator;
180     fileSeparator = ConfigurationFile::GetInstance().Get_file_separator();
181     // tooHigh : true is user supplies a library pathname with too many "../"
182     bool tooHigh = false;
183     
184 //std::cout << "------------------cwd ["  << cwd << "] name [" << name << "]" << std::endl;
185  
186     if ( name[0] == '/' ||  name[1] == ':' ) // Linux or Windows absolute name
187     {
188       return(libname);
189     }
190     else if  ( name =="." )
191     {
192       libname = cwd  + fileSeparator;
193       return(libname);
194     }
195     else if  (name[0] == '.' && (name[1] == '/' || name[1] == '\\') )
196     {
197       libname = cwd  + fileSeparator + name.substr(2, name.length());
198       return(libname);
199     }
200     else if ( name[0] == '.' &&  name[1] == '.' /*  && (name[2] == '/' || name[2] == '\\') */ ) 
201     {
202       if ( IsAtRoot(cwd) )  // hope it gets / (for Linux),  C: D: (for Windows)
203       {  
204      // if we are already at / or c: --> hopeless  
205          if (verbose)
206            std::cout << "   File path [" <<  name << "] doesn't exist" << std::endl;
207          tooHigh = true;
208       }
209       else
210       {
211          // iterate on ../ and go up from the current working dir!
212          std::string a(name); 
213          bool alreadyProcessRoot = false;
214
215           //if (a[a.size()-1] != fileSeparator[0])
216           //   a.append(fileSeparator);
217 //std::cout << "------------------a ["  << a << "]" << std::endl;
218
219          for(;;)  // wild loop !
220          {
221             std::string::size_type slash_position = cwd.find_last_of(fileSeparator);
222             if (slash_position != std::string::npos) {
223              if (slash_position == 0)
224                 slash_position = 1;
225               cwd = cwd.substr(0,slash_position/*+1*/);
226 //std::cout << "------------------cwd ["  << cwd << "]" << std::endl;
227             //  if (a == "..") {
228             //    a = "";
229             //    break;
230             //   }
231             //   else
232                  a = a.substr(3, /*name.length()*/ a.length());  // remove ../
233 //std::cout << "------------------a ["  << a << "]" << std::endl;  
234               if (a == "" || alreadyProcessRoot)
235               {
236                 if (verbose)
237                   std::cout << "   File path : [" <<  name << "] doesn't exist" << std::endl;
238                 tooHigh = true;
239                 break;
240               }
241              // std::string b = cwd + a;
242               libname =  cwd;
243               char c = cwd[cwd.size()-1];
244               if (c != '/' && c != '\\' )
245                 libname += fileSeparator;
246               libname += a;
247
248               if ( a[0] != '.' ) // if . (probabely ../), loop again
249                 break;
250
251               if (IsAtRoot(cwd))
252                 alreadyProcessRoot = true;
253             }
254          } // end iterating on ../
255       }
256 //std::cout << "------------------out of loop]" << std::endl;        
257       if (tooHigh)
258          libname="";
259       return (libname);
260
261     }  // -----   End of expanding path name   ( ./ ../ ../../ )
262
263     std::cout <<"* ERROR in ExpandLibName : should never get here!" << std::endl;
264     // To avoid warning
265     return(""); // Will never get here!
266   }
267
268 // ===================================================================================
269
270   static std::string MakeLibnameFromPath(std::string path, std::string pkgname)
271   {
272     std::string libname = path;
273     char c = path[path.size()-1];    
274 #if defined(__GNUC__)
275        if (c != '/')
276           libname += "/libbb";
277        else
278           libname += "libbb";
279        libname += pkgname;
280        libname += ".so";
281          
282 #elif defined(_WIN32)
283        if (c != '\\')
284           libname = path+"\\bb";
285        libname += pkgname;
286        libname += ".dll";
287 #endif
288     return libname;    
289   }
290
291 // ===================================================================================
292
293   static inline std::string MakePkgnameFromPath(std::string path, std::string pkgname, bool addExt)
294   {
295     std::string libname = path;
296     char c = path[path.size()-1];
297     if (c != '/' && c != '\\')
298     {
299        libname +=  ConfigurationFile::GetInstance().Get_file_separator ();
300     }
301     libname += pkgname;
302     if (addExt)
303     {
304        int l = libname.size();
305        if (l>4)
306        {
307           if (libname.substr(l-4, 4) != ".bbs")
308           {
309                libname = libname + ".bbs";
310           }
311        }
312     }
313     return libname;
314   }
315
316 // ===================================================================================
317
318  static inline  bool IsAtRoot(std::string cwd)
319  {
320     if ( cwd == "/"                             // hope it gets /     (for Linux)
321         || (cwd.size() <= 3 && cwd[1] == ':') ) // hope it gets C: D: (for Windows)
322       return (true);
323     else
324       return(false);
325  }
326
327 // ===================================================================================
328
329 static bool IsDirectory(std::string const &dirName)
330 {
331    struct stat fs;
332
333    if ( stat(dirName.c_str(), &fs) == 0 )
334    {
335 #if _WIN32
336       return ((fs.st_mode & _S_IFDIR) != 0);
337 #else
338       return S_ISDIR(fs.st_mode);
339 #endif
340    }
341    else
342    {
343       return false;
344    }
345 }
346
347 // ===================================================================================
348
349     static inline void SplitAroundFirstDot( const std::string& in,
350                                             std::string& left,
351                                             std::string& right)
352    {
353       std::string delimiter = ".";
354       std::string::size_type pos = in.find_first_of(delimiter);
355       if (std::string::npos != pos) 
356       {
357         left = in.substr(0,pos);
358         right = in.substr(pos+1,in.size());
359
360       }
361       else
362       {
363              // bbtkError(in<<" : expected 'a.b' format but no dot found");
364              left ="";
365              right = "";
366       }
367     }
368   //=======================================================================
369   static inline void SplitString ( const std::string& str, 
370                                    const std::string& delimiters, 
371                                    std::vector<std::string>& tokens)
372   {
373     // Skip delimiters at beginning.
374     std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
375     // Find first delimiter.
376     std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
377     
378     while (std::string::npos != pos || std::string::npos != lastPos)
379       {
380         // Found a token, add it to the vector.
381         tokens.push_back(str.substr(lastPos, pos - lastPos));
382         // Skip delimiters.  Note the "not_of"
383         lastPos = str.find_first_not_of(delimiters, pos);
384         // Find next delimiter
385         pos = str.find_first_of(delimiters, lastPos);
386       }
387     
388   }
389   //=======================================================================
390
391
392 // ===================================================================================
393
394     static inline std::string get_file_name(const std::string& s) 
395     { 
396       std::string::size_type slash_position = s.find_last_of("/\\");
397       if (slash_position != std::string::npos) 
398       {
399         return  s.substr(slash_position+1,std::string::npos);   
400       }
401       else 
402       {
403         return s;
404       }
405     }
406     
407 // ===================================================================================
408 /**
409  * \brief   Explore a directory with possibility of recursion
410  *          return number of files read
411  * @param  dirpath   directory to explore
412  * @param  recursive whether we want recursion or not
413  */
414 static int Explore(std::string const &dirpath, bool recursive, std::vector<std::string> &Filenames)
415 {
416    int numberOfFiles = 0;
417    std::string fileName;
418    
419    std::string dirName = dirpath;
420    
421 #ifdef _MSC_VER
422    WIN32_FIND_DATA fileData;
423    HANDLE hFile = FindFirstFile((dirName+"*").c_str(), &fileData);
424
425    for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
426        b = FindNextFile(hFile, &fileData))
427    {
428       fileName = fileData.cFileName;
429       if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
430       {
431          // Need to check for . and .. to avoid infinite loop
432          if ( fileName != "." && fileName != ".." && recursive )
433          {
434             numberOfFiles += Explore(dirName+ "\\"+fileName,recursive,Filenames);
435          }
436       }
437       else
438       {
439          Filenames.push_back(dirName+fileName);
440          numberOfFiles++;
441       }
442    }
443    DWORD dwError = GetLastError();
444    if (hFile != INVALID_HANDLE_VALUE) 
445       FindClose(hFile);
446    if (dwError != ERROR_NO_MORE_FILES) 
447    {
448       LPVOID lpMsgBuf;
449       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
450                     FORMAT_MESSAGE_FROM_SYSTEM|
451                     FORMAT_MESSAGE_IGNORE_INSERTS,
452                     NULL,GetLastError(),
453                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
454                     (LPTSTR) &lpMsgBuf,0,NULL);
455
456      // ErrorMacro("FindNextFile error. Error is " << (char *)lpMsgBuf
457      //             <<" for the directory : "<<dirName);
458       
459       return 0;
460    }
461
462 #else
463   // Real POSIX implementation: scandir is a BSD extension only, and doesn't 
464   // work on debian for example
465 //std::cout <<"in Explor dirname[" << dirName << "]" << std::endl; 
466    DIR* dir = opendir(dirName.c_str());
467    if (!dir)
468    {
469       return 0;
470    }
471 //std::cout <<"Open OK" << std::endl; 
472    // According to POSIX, the dirent structure contains a field char d_name[]
473    // of unspecified size, with at most NAME_MAX characters preceeding the
474    // terminating null character. Use of other fields will harm the  porta-
475    // bility of your programs.
476
477    struct stat buf;
478    dirent *d;
479    for (d = readdir(dir); d; d = readdir(dir))
480    {
481       fileName = dirName + "/" + d->d_name;
482 //std::cout <<"in Explor filename[" << fileName << "]" << std::endl;      
483       if( stat(fileName.c_str(), &buf) != 0 )
484       {
485          //ErrorMacro( strerror(errno) );
486       }
487       if ( S_ISREG(buf.st_mode) )    //is it a regular file?
488       {
489          Filenames.push_back( fileName );
490          numberOfFiles++;
491       }
492       else if ( S_ISDIR(buf.st_mode) ) //directory?
493       {
494          if ( d->d_name[0] != '.' && recursive ) //we also skip hidden files
495          {
496             numberOfFiles += Explore( fileName, recursive, Filenames);
497          }
498       }
499       else
500       {
501          //ErrorMacro( "Unexpected error" );
502          return -1;
503       }
504    }
505    if( closedir(dir) != 0 )
506    {
507      // ErrorMacro( strerror(errno) );
508    }
509 #endif
510
511   return numberOfFiles;
512
513 }
514
515   //========================================================================
516   // Usefull functions for html generation
517   //========================================================================
518
519     static inline void replace( std::string& str,
520                                 const std::string& what, 
521                                 const std::string& with )
522     {
523       std::string::size_type pos = str.find( what );
524           while ( pos != std::string::npos )
525       {
526         str.replace( pos, what.size(), with );
527         pos = str.find( what, pos+what.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