inlib
1.2.0
|
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