inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/sys/dir
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_sys_dir
00005 #define inlib_sys_dir
00006 
00007 #include <string>
00008 #include <vector>
00009 #include <cstdlib> //getenv
00010 #include <cstdio> //::remove
00011 
00012 #ifdef WIN32
00013 #include <windows.h>
00014 #include <direct.h>
00015 #else //UNIX
00016 #include <dirent.h>
00017 #include <unistd.h>
00018 #endif
00019 
00020 #include <sys/stat.h>
00021 
00022 namespace inlib {
00023 namespace dir {
00024 
00025 inline bool pwd(std::string& a_pwd) {
00026   // Return current directory.
00027   unsigned int mx_path_len = 1024;
00028   char* cwd = new char[mx_path_len];
00029 #ifdef WIN32
00030   //  driveletter = 0 means return the working directory for the default drive.
00031   if(::_getdcwd(0,cwd,mx_path_len)==NULL) {
00032     delete [] cwd;
00033     a_pwd.clear();
00034     return false;
00035   }
00036 #else
00037   if(::getcwd(cwd,mx_path_len)==NULL) {
00038     delete [] cwd;
00039     a_pwd.clear();
00040     return false;
00041   }
00042 #endif
00043   a_pwd = cwd;
00044   delete [] cwd;
00045   return true;
00046 }
00047 
00048 inline bool cd(const std::string& a_path){
00049   if(::chdir(a_path.c_str())!=0) return false;
00050   return true;
00051 }
00052 
00053 inline bool create(const std::string& a_name){
00054   // a_name should be a single directory name, and not a file system path.
00055   // Then it must not contain : ., .., /, \ etc...
00056 #ifdef WIN32
00057   return (::mkdir(a_name.c_str())==0 ? true : false); 
00058 #else
00059   return (::mkdir(a_name.c_str(), 0755)==0 ? true : false); 
00060 #endif
00061 }
00062 
00063 inline std::string home() {
00064 #ifdef WIN32
00065   const char* env = ::getenv("HOMEDRIVE");
00066   std::string drive = env ? env : std::string("C:");
00067  {const char* env = ::getenv("HOMEPATH");
00068   if(!env) return drive+"\\";
00069   return drive+std::string(env);}
00070 #else
00071   const char* env = ::getenv("HOME");
00072   return (env?env:"");
00073 #endif
00074 }
00075 
00076 inline bool cd_home() {
00077   std::string s = home();
00078   if(s.empty()) return false;
00079   return cd(s);
00080 }
00081 
00082 //NOTE : SWIG : exists is also a method in file
00083 //       (can be fix with a %rename(directory_exists))
00084 inline bool in_fs(const std::string& a_path){
00085   struct stat finfo;
00086   if (::stat(a_path.c_str(),&finfo) < 0) return false;
00087   return true;
00088 }
00089 
00090 //NOTE : SWIG : "is" is a Python keyword.
00091 inline bool is_a(const std::string& a_path,bool& a_value) {
00092   a_value = false;
00093   struct stat finfo;
00094   if (::stat(a_path.c_str(),&finfo) < 0) return false;
00095   a_value = ( ((finfo.st_mode & S_IFMT) == S_IFDIR) ? true : false);
00096   return true;
00097 }
00098 
00099 inline bool is_dot(const std::string& a_path) {
00100 #ifdef WIN32
00101   char sep = '\\';
00102 #else
00103   char sep = '/';
00104 #endif
00105   unsigned int l = a_path.size();
00106   if((l==1) && (a_path[0]=='.') ) return true;
00107   if((l==2) && (a_path[0]=='.') && (a_path[l]=='.') ) return true;
00108   if((l>=2) && (a_path[l-1]=='.') && (a_path[l-2]==sep) ) return true;
00109   if((l>=3) && (a_path[l-1]=='.') && (a_path[l-2]=='.') && (a_path[l-3]==sep) )
00110     return true;
00111   return false;
00112 }
00113 
00114 inline bool mkcd(const std::string& a_name) {
00115   // a_name should be a single directory name, and not a file system path.
00116   // Then it must not contain : ., .., /, \ etc...
00117   bool is;
00118   if(!is_a(a_name,is)) { //a_name does not exist as a file or dir.
00119     if(!create(a_name)) return false;
00120   } else {
00121     if(!is) return false; //a_name exists but is not a directory.
00122   }
00123   return cd(a_name);
00124 }
00125 
00126 inline bool is_empty(const std::string& a_path,bool& a_is_empty){
00127   a_is_empty = true;
00128   struct stat finfo;
00129   if (::stat(a_path.c_str(),&finfo) < 0)  return false;
00130 #ifdef WIN32
00131   if (!(finfo.st_mode & S_IFDIR)) return false;
00132   std::string entry = a_path;
00133   if (!(entry[entry.size()] == '/' || entry[entry.size()] == '\\' ))
00134     entry += "\\";
00135   entry += "*";
00136   WIN32_FIND_DATA findFileData;
00137   HANDLE dir = ::FindFirstFile(entry.c_str(),&findFileData);
00138   if(dir == INVALID_HANDLE_VALUE) return false;
00139   for (;;) {
00140     if(!::FindNextFile(dir,&findFileData)) break;
00141     std::string name = (const char*)findFileData.cFileName;
00142     if(name==".") continue;
00143     if(name=="..") continue;
00144     a_is_empty = false;
00145     ::FindClose(dir);
00146     return true;  
00147   }
00148   ::FindClose(dir);
00149 #else
00150   if (!S_ISDIR(finfo.st_mode)) return false;
00151   DIR* dir = ::opendir(a_path.c_str());
00152   if(!dir) return false;
00153   for (;;) {
00154     struct dirent* dp = ::readdir(dir);
00155     //struct direct* dp;
00156     if (dp==NULL) break;
00157 #if defined(_POSIX_SOURCE)
00158     if(true) {
00159 #else
00160     if(dp->d_ino!=0) {
00161 #endif
00162       std::string name = dp->d_name;
00163       if(name==".") continue;
00164       if(name=="..") continue;
00165       a_is_empty = false;
00166       ::closedir(dir);
00167       return true;  
00168     }
00169   }
00170   ::closedir(dir);
00171 #endif
00172   return true;
00173 }
00174 
00175 inline bool entries(const std::string& a_path,std::vector<std::string>& a_list,bool a_full_path = true){
00176   a_list.clear();
00177   struct stat finfo;
00178   if (::stat(a_path.c_str(),&finfo) < 0)  return false;
00179 #ifdef WIN32
00180   if (!(finfo.st_mode & S_IFDIR)) return false;
00181   std::string entry = a_path;
00182   if (!(entry[entry.size()] == '/' || entry[entry.size()] == '\\' ))
00183     entry += "\\";
00184   entry += "*";
00185   WIN32_FIND_DATA findFileData;
00186   HANDLE dir = ::FindFirstFile(entry.c_str(),&findFileData);
00187   if(dir == INVALID_HANDLE_VALUE) return false;
00188   // Get file names :
00189   for (;;) {
00190     if(!::FindNextFile(dir,&findFileData)) break;
00191     std::string name = (const char*)findFileData.cFileName;
00192     // Be sure we can work on the file :
00193     std::string fname = a_path+"\\"+name;
00194     if (::stat(fname.c_str(),&finfo) < 0)  continue;
00195     if(a_full_path)
00196       a_list.push_back(fname);
00197     else
00198       a_list.push_back(name);
00199   }
00200   ::FindClose(dir);
00201 #else
00202   if (!S_ISDIR(finfo.st_mode)) return false;
00203   DIR* dir = ::opendir(a_path.c_str());
00204   if(!dir) return false;
00205   // Get file names :
00206   for (;;) {
00207     struct dirent* dp = ::readdir(dir);
00208     //struct direct* dp;
00209     if (dp==NULL) break;
00210 #if defined(_POSIX_SOURCE)
00211     if(true) {
00212 #else
00213     if(dp->d_ino!=0) {
00214 #endif
00215       std::string name = dp->d_name;
00216       // Be sure we can work on the file :
00217       std::string fname = a_path+"/"+name;
00218       if (::stat(fname.c_str(),&finfo) < 0)  continue;
00219       if(a_full_path)
00220         a_list.push_back(fname);
00221       else
00222         a_list.push_back(name);
00223     }
00224   }
00225   ::closedir(dir);
00226 #endif
00227   return true;
00228 }
00229 
00230 inline bool is_an_entry(const std::string& a_path,const std::string& a_name,bool& a_found){
00231   a_found = false;
00232   struct stat finfo;
00233   if (::stat(a_path.c_str(),&finfo) < 0)  return false;
00234 #ifdef WIN32
00235   if (!(finfo.st_mode & S_IFDIR)) return false;
00236   std::string entry = a_path;
00237   if (!(entry[entry.size()] == '/' || entry[entry.size()] == '\\' ))
00238     entry += "\\";
00239   entry += "*";
00240   WIN32_FIND_DATA findFileData;
00241   HANDLE dir = ::FindFirstFile(entry.c_str(),&findFileData);
00242   if(dir == INVALID_HANDLE_VALUE) return false;
00243   // Get file names :
00244   for (;;) {
00245     if(!::FindNextFile(dir,&findFileData)) break;
00246     std::string name = (const char*)findFileData.cFileName;
00247     if(name==a_name) {
00248       a_found = true;
00249       ::FindClose(dir);
00250       return true;
00251     }
00252   }
00253   ::FindClose(dir);
00254 #else
00255   if (!S_ISDIR(finfo.st_mode)) return false;
00256   DIR* dir = ::opendir(a_path.c_str());
00257   if(!dir) return false;
00258   // Get file names :
00259   for (;;) {
00260     struct dirent* dp = ::readdir(dir);
00261     //struct direct* dp;
00262     if (dp==NULL) break;
00263 #if defined(_POSIX_SOURCE)
00264     if(true) {
00265 #else
00266     if(dp->d_ino!=0) {
00267 #endif
00268       std::string name = dp->d_name;
00269       if(name==a_name) {
00270         a_found = true;
00271         ::closedir(dir);
00272         return true;
00273       }
00274     }
00275   }
00276   ::closedir(dir);
00277 #endif
00278   return true;
00279 }
00280 
00281 //duplicate from smanip to avoid including smanip :
00282 //NOTE : SWIG : have to change the name.
00283 inline std::string path_base_name(const std::string& a_path) {
00284   std::string::size_type pos_slash = a_path.rfind('/');
00285   std::string::size_type pos_bslash = a_path.rfind('\\');
00286   std::string::size_type pos = 0;
00287   if(pos_slash==std::string::npos) {
00288     if(pos_bslash==std::string::npos) {
00289       pos = std::string::npos;
00290     } else {
00291       pos = pos_bslash;
00292     }
00293   } else {
00294     if(pos_bslash==std::string::npos) {
00295       pos = pos_slash;
00296     } else {
00297       if(pos_slash<=pos_bslash) {
00298         pos = pos_bslash;
00299       } else {
00300         pos = pos_slash;
00301       }
00302     }
00303   }
00304   if(pos==std::string::npos) return a_path;
00305   pos++;
00306   return a_path.substr(pos,a_path.size()-pos);
00307 }
00308 
00309 //NOTE : SWIG : "remove" exists in smanip. Have to change the name.
00310 inline bool rmdir(const std::string& a_path){
00311   struct stat finfo;
00312   if(::stat(a_path.c_str(),&finfo) < 0) return true;
00313 #ifdef WIN32
00314   if(!(finfo.st_mode & S_IFDIR)) return false;
00315 #else
00316   if(!S_ISDIR(finfo.st_mode)) return false;
00317 #endif
00318   // Empty the directory :
00319   std::vector<std::string> files;
00320   entries(a_path,files);
00321   unsigned int filen = files.size();
00322   for(unsigned int count=0;count<filen;count++) {
00323     const std::string& entry = files[count];     
00324 
00325    {std::string name = path_base_name(entry);
00326     if((name==".")||(name=="..")) continue;}
00327 
00328     bool is_dir;
00329     if(!is_a(entry,is_dir)) return false;
00330     if(is_dir) {
00331       if(!dir::rmdir(entry)) {
00332         //::printf("debug : rm dir %s failed.\n",entry.c_str());
00333         return false;
00334       }
00335       //::printf("debug : rm dir %s.\n",entry.c_str());
00336     } else {
00337       if(::remove(entry.c_str())!=0) {
00338         //::printf("debug : rm file %s failed.\n",entry.c_str());
00339         return false;
00340       }
00341       //::printf("debug : rm file %s.\n",entry.c_str());
00342     }
00343   }
00344   // Remove the directory :
00345   return (::rmdir(a_path.c_str())==0?true:false);
00346 }
00347 
00348 }}
00349 
00350 #include <ostream>
00351 
00352 namespace inlib {
00353 namespace dir {
00354 
00355 // two classes to build applications working
00356 // on a hierarchy of files.
00357 
00358 class visitor {
00359 public:
00360   virtual ~visitor() {}
00361 public:
00362   virtual bool directory(const std::string&,bool&) = 0;
00363   virtual bool file(const std::string&) = 0;
00364 };
00365 
00366 class tree {
00367 public:
00368   typedef bool(*match_func)(const std::string&,const std::string&);
00369 public:
00370   tree(std::ostream& a_out):m_out(a_out),m_match_func(0){}
00371   virtual ~tree() {
00372    {std::vector<tree*>::iterator it;
00373     for(it=m_dirs.begin();it!=m_dirs.end();++it) delete *it;
00374     m_dirs.clear();}
00375   }
00376 public:
00377   tree(const tree& a_from):m_out(a_from.m_out) {    
00378     m_path = a_from.m_path;
00379     m_files = a_from.m_files;
00380    {std::vector<tree*>::const_iterator it;
00381     for(it=a_from.m_dirs.begin();it!=a_from.m_dirs.end();++it) {
00382       m_dirs.push_back(new tree(*(*it)));
00383     }}
00384   }
00385   tree& operator=(const tree& a_from) {    
00386     m_path = a_from.m_path;
00387     m_files = a_from.m_files;
00388 
00389    {std::vector<tree*>::iterator it;
00390     for(it=m_dirs.begin();it!=m_dirs.end();++it) delete *it;
00391     m_dirs.clear();}
00392     
00393    {std::vector<tree*>::const_iterator it;
00394     for(it=a_from.m_dirs.begin();it!=a_from.m_dirs.end();++it) {
00395       m_dirs.push_back(new tree(*(*it)));
00396     }}
00397 
00398     return *this;
00399   }
00400 public:
00401   void set_path(const std::string& a_path) {m_path = a_path;}
00402   void set_match_func(match_func a_func) {m_match_func = a_func;}
00403 
00404   bool build(const std::string& a_pattern = "") {
00405     if(m_path.empty()) {
00406       m_out << "tree::build :"
00407             << " empty path."
00408             << std::endl;
00409       return false;
00410     }
00411     std::vector<std::string> files;
00412     if(!entries(m_path,files)) {
00413       m_out << "tree::build :"
00414             << " dir::entries failed for \"" << m_path << "\"."
00415             << std::endl;
00416       return false;
00417     }
00418     //printf("debug : build : \"%s\" %d files.\n",
00419     //       aTree.path().c_str(),(int)files.size());
00420     std::vector<std::string>::iterator it;
00421     for(it=files.begin();it!=files.end();++it) {
00422       const std::string& name = *it;
00423       bool is;
00424       if(!is_a(name,is)) {
00425         m_out << "tree::build :"
00426               << " is_a failed for \"" << name << "\"."
00427               << std::endl;
00428         return false;
00429       }
00430       if(is) {
00431         if(is_dot(name)) {
00432           //bypass dot directories.
00433         } else {
00434           tree* dir = new tree(m_out);
00435           m_dirs.push_back(dir);
00436           dir->set_path(name);
00437           dir->set_match_func(m_match_func);
00438           if(!dir->build(a_pattern)) return false;
00439         }
00440       } else {
00441         if( (a_pattern.empty()) || (a_pattern=="*") ) {
00442           m_files.push_back(name);
00443         } else {
00444           if(!m_match_func) {
00445             m_out << "tree::build :"
00446                   << " pattern given but no match function given."
00447                   << std::endl;
00448             return false;
00449           }
00450           bool ok = m_match_func(name,a_pattern);
00451           //printf("debug : build : \"%s\" match \"%s\" ? %d\n",
00452           //       name.c_str(),a_pattern.c_str(),ok);
00453           if(ok) m_files.push_back(name);
00454         }
00455       }
00456     }
00457     return true;
00458   }
00459 
00460   bool visit(visitor& a_visitor) {
00461     if(m_path.empty()) return true;
00462     bool process;
00463     if(!a_visitor.directory(m_path,process)) return false;
00464     if(!process) return true;
00465    {std::vector<std::string>::iterator it;
00466     for(it=m_files.begin();it!=m_files.end();++it) {
00467       if(!a_visitor.file(*it)) return false;
00468     }}
00469    {std::vector<tree*>::iterator it;
00470     for(it=m_dirs.begin();it!=m_dirs.end();++it) {
00471       if(!(*it)->visit(a_visitor)) return false;
00472     }}
00473     return true;
00474   }
00475 protected:
00476   std::ostream& m_out;
00477   std::string m_path;
00478   std::vector<tree*> m_dirs;
00479   std::vector<std::string> m_files;
00480   match_func m_match_func;
00481 };
00482 
00483 }}
00484 
00485 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines