From 7450c0f23b000f89fc44d85096c6955d99bfd2b2 Mon Sep 17 00:00:00 2001 From: kichik Date: Fri, 26 Nov 2004 15:37:31 +0000 Subject: [PATCH] new interface for reading directories which helps getting some preprocessor clutter outside of script.cpp git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3781 212acab6-be3b-0410-9dea-997c60f758d6 --- Source/dirreader.cpp | 225 +++++++++++++++++++++++++++++++++++++++++++ Source/dirreader.h | 40 ++++++++ Source/makenssi.dsp | 8 ++ 3 files changed, 273 insertions(+) create mode 100644 Source/dirreader.cpp create mode 100644 Source/dirreader.h diff --git a/Source/dirreader.cpp b/Source/dirreader.cpp new file mode 100644 index 00000000..149e56be --- /dev/null +++ b/Source/dirreader.cpp @@ -0,0 +1,225 @@ +#include "Platform.h" +#include "dirreader.h" +#include +#include + +#include // for tolower() + +using namespace std; + +dir_reader::dir_reader() { + exclude("."); + exclude(".."); +} + +const set& dir_reader::files() { + return m_files; +} + +const set& dir_reader::dirs() { + return m_dirs; +} + +void dir_reader::exclude(const string& spec) { + if (spec.find_first_of("?*") >= 0) { + m_wildcard_excluded.insert(spec); + } else { + m_excluded.insert(spec); + } +} + +void dir_reader::exclude(const set& specs) { + iterator i = specs.begin(); + iterator e = specs.end(); + + for (; i != e; i++) { + exclude(*i); + } +} + +bool dir_reader::matches(const string& name, const string& spec) { + string::const_iterator name_itr = name.begin(); + string::const_iterator name_end = name.end(); + + string::const_iterator spec_itr = spec.begin(); + string::const_iterator spec_end = spec.end(); + + string::const_iterator last_good_spec = NULL; + string::const_iterator last_good_name = NULL; + + while (name_itr != name_end && spec_itr != spec_end) { + switch (*spec_itr) { + case '?': + // question mark mathes one char + name_itr++; + spec_itr++; + break; + + case '*': + // double asterisk is the same as a simgle asterisk + while (*spec_itr == '*' && spec_itr != spec_end) + spec_itr++; + + // asterisk at the end of the spec matches the end of the name + if (spec_itr == spec_end) + return true; + + // remember last good name and spec for prematurely stopped asterisk + last_good_spec = spec_itr; + last_good_name = name_itr; + + break; + + default: + if (::tolower(*name_itr) != ::tolower(*spec_itr)) { + if (last_good_spec) { + // matched wrong part of the name, try again + spec_itr = last_good_spec; + name_itr = ++last_good_name; + } else { + // no match and no asterisk to use + return false; + } + } else { + // remember last good name for prematurely stopped asterisk + last_good_name = name_itr; + + spec_itr++; + name_itr++; + + if (spec_itr == spec_end && name_itr != name_end && last_good_spec) { + // asterisk hasn't matched enough, keep matching + spec_itr = last_good_spec; + } + } + break; + } + } + + // skip any redundant asterisks and periods at the end of the name + while (spec_itr != spec_end) { + if (*spec_itr != '.' && *spec_itr != '*') { + break; + } + spec_itr++; + } + + // return true only if managed to match everything + return name_itr == name_end && spec_itr == spec_end; +} + +void dir_reader::add_file(const string& file) { + if (!is_excluded(file)) { + m_files.insert(file); + } +} + +void dir_reader::add_dir(const std::string& dir) { + if (!is_excluded(dir)) { + m_dirs.insert(dir); + } +} + +bool dir_reader::is_excluded(const string& name) const { + iterator i = m_excluded.begin(); + iterator e = m_excluded.end(); + + for (; i != e; i++) { + if (name == *i) { + return true; + } + } + + i = m_wildcard_excluded.begin(); + e = m_wildcard_excluded.end(); + + for (; i != e; i++) { + if (matches(name, *i)) { + return true; + } + } + + return false; +} + +#ifdef _WIN32 + +class win32_dir_reader : public dir_reader { +public: + + virtual void read(const string& dir) { + WIN32_FIND_DATA fd; + + string spec = dir + PLATFORM_PATH_SEPARATOR_STR + "*.*"; + + HANDLE h = ::FindFirstFile(spec.c_str(), &fd); + if (h != INVALID_HANDLE_VALUE) { + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dir_reader::add_dir(fd.cFileName); + } else { + dir_reader::add_file(fd.cFileName); + } + } while (::FindNextFile(h, &fd)); + ::FindClose(h); + } + } + +}; + +#else + +#include +#include + +class posix_dir_reader : public dir_reader { +public: + + virtual void read(const string& dir) { + //string converted_dir = convert(dir); + + DIR *dip = ::diropen(dir.c_str()); + if (dip) { + dirent *dit; + while (dit = ::dirread(dip)) { + if (dit->d_type == DT_DIR) { + dir_reader::add_dir(dit->d_name); + } else { + dir_reader::add_file(dit->d_name); + } + } + ::closedir(dip); + } + } + +private: + + string& convert(string& path) { + string converted = path; + + string::size_type pos = converted.find('\\'); + while (pos != string::npos) { + converted[pos] = '/'; + pos = converted.find('\\'); + } + + /* Replace drive letter X: by /x */ + if (converted[1] == ':') { + converted[1] = ::tolower(converted[0]); + converted[0] = '/'; + } + + return converted; + } + +}; + +#endif + +dir_reader* new_dir_reader() { +#ifdef _WIN32 + return new win32_dir_reader(); +#else + return new posix_dir_reader(); +#endif +} diff --git a/Source/dirreader.h b/Source/dirreader.h new file mode 100644 index 00000000..a6bccd66 --- /dev/null +++ b/Source/dirreader.h @@ -0,0 +1,40 @@ +#include "Platform.h" +#include +#include + +class dir_reader { +public: + + typedef std::set::const_iterator iterator; + + dir_reader(); + virtual ~dir_reader() {} + + virtual void read(const std::string& dir) = 0; + + virtual const std::set& files(); + virtual const std::set& dirs(); + + virtual void exclude(const std::string& spec); + virtual void exclude(const std::set& specs); + + static bool matches(const std::string& name, const std::string& spec); + +protected: + + virtual void add_file(const std::string& file); + virtual void add_dir(const std::string& dir); + + virtual bool is_excluded(const std::string& name) const; + +private: + + std::set m_excluded; + std::set m_wildcard_excluded; + + std::set m_files; + std::set m_dirs; + +}; + +dir_reader* new_dir_reader(); diff --git a/Source/makenssi.dsp b/Source/makenssi.dsp index bcf0afab..508ae8f1 100644 --- a/Source/makenssi.dsp +++ b/Source/makenssi.dsp @@ -204,6 +204,10 @@ SOURCE=.\DialogTemplate.cpp # End Source File # Begin Source File +SOURCE=.\dirreader.cpp +# End Source File +# Begin Source File + SOURCE=.\exedata.cpp # ADD CPP /G6 # End Source File @@ -293,6 +297,10 @@ SOURCE=.\DialogTemplate.h # End Source File # Begin Source File +SOURCE=.\dirreader.h +# End Source File +# Begin Source File + SOURCE=.\exedata.h # End Source File # Begin Source File