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