00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef DIR_STREAM_H_INCLUDED
00036 #define DIR_STREAM_H_INCLUDED
00037 #include <cctype>
00038 #include <string>
00039 #if defined _MSC_VER && _MSC_VER <= 1300
00040 # define for if(0);else for
00041 # pragma warning(disable:4786)
00042 # define HAS_STD_ITERATOR
00043 namespace std {
00044 using ::tolower;
00045 using ::size_t;
00046 }
00047 #endif
00048
00049 #include <stack>
00050 #include <iterator>
00051 #include <algorithm>
00052 #include <cassert>
00053 #include <stdexcept>
00054 #include <memory>
00055 #include <utility>
00056
00057 #include "filter_base.h"
00058 #include "detail/filter_asserter.h"
00060
00062 #ifdef _WIN32
00063 #include "dirstreamw32.h"
00064 #else
00065
00066 #include <dirent.h>
00067 #include <sys/types.h>
00068 #include <sys/stat.h>
00069 namespace dirstr
00070 {
00071 const char PATH_SEPERATOR = '/';
00072 }
00073 #endif
00075 namespace dirstr
00076 {
00077
00082 enum entry_type{
00083 dirs = 1,
00084 dirs_not_dot_or_dot_dot = 2,
00085 files = 4,
00086 files_and_dirs = dirs | files,
00087 files_and_dirs_not_dot_or_dot_dot = dirs_not_dot_or_dot_dot | files
00088 };
00089
00094 enum recurse_mode {
00095 recursive_yes,
00096 recursive_no
00097 };
00098
00104 class open_error : public std::runtime_error
00105 {
00106 public:
00107 open_error(const char* dir)
00108 : std::runtime_error(dir)
00109 {}
00110 };
00111
00116 struct no_f : public filter_base
00117 {
00118 public:
00119 bool operator()(const std::string&) const {return true;}
00120 filter_base* clone() const {return new no_f();}
00121 };
00122
00123 template <class F> struct expr;
00125
00127
00154 class dirstream
00155 {
00156 typedef filter_base* (std::auto_ptr<filter_base>::*unspecified_bool_type)() const;
00157 public:
00178 dirstream (const char* dirName, const filter_base& entryFilter = no_f(),
00179 recurse_mode recMode = recursive_no, const filter_base& subDirFilter = no_f());
00180
00187 ~dirstream ();
00188
00194 operator unspecified_bool_type() const
00195 {
00196 return m_DirHandle ? &std::auto_ptr<filter_base>::get : 0;
00197 }
00198
00214 dirstream& operator>>(std::string& name);
00215
00228 std::streamsize readsome(std::string* r, std::streamsize n);
00229
00235 bool open(const char* dirName, const filter_base& entryFilter,
00236 recurse_mode recMode = recursive_no, const filter_base& subDirFilter = no_f());
00237
00245 bool open(const char* dirName, recurse_mode recMode = recursive_no);
00246
00250 bool is_open () const;
00251
00260 void rewind ();
00261
00271 void close();
00272 private:
00273
00274
00275 dirstream(const dirstream&);
00276 dirstream& operator=(const dirstream&);
00277
00278 bool isDirectory(const char*) const;
00279 bool selectSubDir(const std::string& name) const;
00280 bool selectEntry(const std::string& name) const;
00281 void closeDir();
00282 void commonInit();
00283 bool dotOrDotDot(const std::string& name) const;
00284
00285 typedef std::auto_ptr<filter_base> Filter;
00286 Filter m_EntryFilter;
00287 Filter m_SubDirFilter;
00288 recurse_mode m_RecurseMode;
00289 std::stack<std::string> m_Dirs;
00290 std::string m_DirName;
00291 std::string m_CurrentPath;
00292 DIR* m_DirHandle;
00293 dirent* m_CurrentEntry;
00294 };
00295
00310 class dirstream_iterator
00311 #ifdef HAS_STD_ITERATOR
00312 : public std::iterator<std::input_iterator_tag, std::string>
00313 #endif
00314 {
00315 public:
00316
00317
00318 #ifndef HAS_STD_ITERATOR
00319 typedef std::input_iterator_tag iterator_category;
00320 typedef std::string value_type;
00321 typedef ptrdiff_t difference_type;
00322 typedef std::string* pointer;
00323 typedef std::string& reference;
00324 #endif
00325 public:
00326 typedef dirstream stream_type;
00330 dirstream_iterator()
00331 : dstr_(0)
00332 {}
00333
00341 explicit dirstream_iterator(dirstream& dstr)
00342 : dstr_(&dstr)
00343 {
00344 readOne();
00345 }
00346
00351 const std::string& operator*() const
00352 {
00353 return currVal_;
00354 }
00355
00360 const std::string* operator->() const
00361 {
00362 return &**this;
00363 }
00364
00371 dirstream_iterator& operator++()
00372 {
00373 readOne();
00374 return *this;
00375 }
00376
00381 dirstream_iterator operator++(int)
00382 {
00383 dirstream_iterator t(*this);
00384 ++*this;
00385 return t;
00386 }
00387 friend bool operator==(const dirstream_iterator& lhs, const dirstream_iterator& rhs);
00388 friend bool operator!=(const dirstream_iterator& lhs, const dirstream_iterator& rhs);
00389 private:
00390 void readOne()
00391 {
00392 assert(dstr_);
00393 if ( !(*dstr_ >> currVal_) )
00394 dstr_ = 0;
00395 }
00396 dirstream* dstr_;
00397 std::string currVal_;
00398 };
00399
00404 inline bool operator==(const dirstream_iterator& lhs, const dirstream_iterator& rhs)
00405 {
00406 return lhs.dstr_ == rhs.dstr_;
00407 }
00408
00419 inline bool operator!=(const dirstream_iterator& lhs, const dirstream_iterator& rhs)
00420 {
00421 return !(lhs == rhs);
00422 }
00423
00424
00426
00428
00438 bool is_directory(const std::string& entry);
00439
00448 std::string full_path(const std::string& entry);
00449
00457 bool create_directory(const std::string& path);
00458
00466 bool directory_exists(const std::string& path);
00467
00469
00471
00519 #define ADD_CLONE_IMPL(Name) \
00520 filter_base* clone() const {return new Name(*this);}
00521
00522
00528 struct type_f : public filter_base {
00533 type_f(entry_type t)
00534 : t_(t)
00535 {}
00536
00540 bool operator()(const std::string& entryName) const
00541 {
00542 bool isDir = is_directory(entryName.c_str());
00543 if ((t_ & dirs) && isDir)
00544 return true;
00545 if (!isDir && (t_ & files))
00546 return true;
00547 if (isDir && (t_ & dirs_not_dot_or_dot_dot))
00548 {
00549 std::string::size_type pathEnd = entryName.rfind(PATH_SEPERATOR);
00550 if (pathEnd == std::string::npos)
00551 pathEnd = 0;
00552 else
00553 ++pathEnd;
00554 return entryName.compare(pathEnd, std::string::npos, ".") != 0 &&
00555 entryName.compare(pathEnd, std::string::npos, "..") != 0;
00556 }
00557 return false;
00558 }
00559 ADD_CLONE_IMPL(type_f);
00560 private:
00561 entry_type t_;
00562 };
00563
00564
00611 struct pattern_f : public filter_base
00612 {
00617 class invalid_pattern : public std::logic_error
00618 {
00619 public:
00620 invalid_pattern(const char* msg) : std::logic_error(msg)
00621 {}
00622 };
00623
00640 explicit pattern_f(const char* pattern,
00641 entry_type types = files_and_dirs_not_dot_or_dot_dot,
00642 bool checkPath = false,
00643 bool ignoreCase = false
00644 )
00645 : pattern_(simplify(pattern))
00646 , filter_(types)
00647 , ignoreCase_(ignoreCase)
00648 , checkPath_(checkPath)
00649 {}
00650
00655 bool operator()(const std::string& entryName) const
00656 {
00657 const char* fname = getName(entryName);
00658 if (!filter_(entryName)) return false;
00659 if (entryName.empty()) return pattern_ == "*" || pattern_.empty();
00660 return match(fname, pattern_.c_str());
00661 }
00662 ADD_CLONE_IMPL(pattern_f);
00663 private:
00664
00665 bool match(const char* str, const char* pattern) const
00666 {
00667 const char* strRun = 0;
00668 const char* patternRun = 0;
00669 bool starSeen = false;
00670 bool end = false;
00671 do {
00672 for (strRun = str, patternRun = pattern; !(end = *strRun == 0); ++strRun, ++patternRun)
00673 {
00674 if (*patternRun == '*')
00675 {
00676
00677
00678 starSeen = true;
00679 str = strRun;
00680 pattern = patternRun;
00681
00682
00683 if (!*++pattern) return true;
00684 break;
00685 }
00686 else if (*patternRun == '[')
00687 {
00688 ++patternRun;
00689 bool first = true;
00690 bool found = false;
00691 while (*patternRun != ']' || first)
00692 {
00693 if (!found && *patternRun == *strRun)
00694 found = true;
00695 first = false;
00696 ++patternRun;
00697 }
00698 if (!found)
00699 {
00700 if (!starSeen) return false;
00701 ++str;
00702 break;
00703 }
00704 }
00705 else if (!equal(*patternRun, *strRun) && *patternRun != '?')
00706 {
00707 if (!starSeen) return false;
00708
00709
00710
00711 ++str;
00712 break;
00713 }
00714 }
00715 if (end)
00716 {
00717 if (*patternRun == '*') ++patternRun;
00718 return (!*patternRun);
00719 }
00720 } while(!end);
00721 return false;
00722 }
00723 bool equal(char c1, char c2) const
00724 {
00725 return ignoreCase_ ?
00726 std::tolower(static_cast<unsigned char>(c1)) == std::tolower(static_cast<unsigned char>(c2))
00727 : c1 == c2;
00728 }
00729
00730
00731
00732
00733 std::string simplify(const char* pattern)
00734 {
00735 if (!pattern || !*pattern) return "";
00736 checkPattern(pattern);
00737 const char* cur = pattern;
00738 const char* next = cur + 1;
00739 bool starPending = false;
00740 std::string ret;
00741 ret.reserve(16);
00742 while (*cur)
00743 {
00744 if (*cur == '*' || starPending)
00745 {
00746 while (*next == '*') ++next;
00747 if (*next == '?')
00748 {
00749 ++cur;
00750 ++next;
00751 ret += '?';
00752 starPending = true;
00753 }
00754 else
00755 {
00756 ret += starPending ? '*' : *cur;
00757 starPending = false;
00758 cur = next++;
00759 }
00760 }
00761 else
00762 {
00763 ret += *cur;
00764 cur = next++;
00765 }
00766 }
00767 return ret;
00768 }
00769
00770 void checkPattern(const char* pattern) const
00771 {
00772 for(;*pattern;++pattern)
00773 {
00774 if (*pattern == '[')
00775 {
00776 pattern += 2;
00777 while (*pattern && *pattern != ']')
00778 ++pattern;
00779 if (!*pattern)
00780 throw invalid_pattern("missing ']'");
00781 }
00782 }
00783 }
00784 const char* getName(const std::string& entryName) const
00785 {
00786 if (checkPath_)
00787 return entryName.c_str();
00788 std::string::size_type p = entryName.rfind(PATH_SEPERATOR);
00789 if (p == std::string::npos)
00790 return entryName.c_str();
00791 else
00792 return entryName.c_str() + p + 1;
00793 }
00794 std::string pattern_;
00795 type_f filter_;
00796 bool ignoreCase_;
00797 bool checkPath_;
00798 };
00799
00801
00803
00816 template <class F>
00817 struct adapter_f_t : public filter_base, private detail::assert_is_filter<F>
00818 {
00819 public:
00823 adapter_f_t(const F& t)
00824 : f_(t)
00825 {}
00826
00831 bool operator()(const std::string& e) const
00832 {
00833 return f_(e) != 0;
00834 }
00835 filter_base* clone() const
00836 {
00837 return new adapter_f_t<F>(f_);
00838 }
00839 private:
00840 F f_;
00841 };
00842
00855 template <class R>
00856 adapter_f_t<R (*)(const std::string&)> ptr_fun_f(R (*ptr_fun)(const std::string&))
00857 {
00858 return adapter_f_t< R (*)(const std::string&) >(ptr_fun);
00859 }
00860
00873 template <class T>
00874 adapter_f_t<T> pred_f(const T& f)
00875 {
00876 return adapter_f_t<T>(f);
00877 }
00878
00902 template <class T, class MemFun>
00903 struct mem_fun_f_t : public filter_base
00904 {
00905 public:
00906 mem_fun_f_t(T obj, MemFun memFun)
00907 : obj_(obj)
00908 , memFun_(memFun)
00909 {}
00914 bool operator()(const std::string& entryName) const
00915 {return (obj_->*memFun_)(entryName);}
00916 filter_base* clone() const
00917 {
00918 return new mem_fun_f_t<T, MemFun>(obj_, memFun_);
00919 }
00920 private:
00921 T obj_;
00922 MemFun memFun_;
00923 };
00924
00943 template <class PtrT, class M>
00944 mem_fun_f_t<PtrT, M> mem_fun_f(PtrT o, M memFun)
00945 {
00946 return mem_fun_f_t<PtrT, M>(o, memFun);
00947 }
00948
00949
00950 }
00951
00952 #undef ADD_CLONE_IMPL
00953 #endif