diff --git a/Foundation/CMakeLists.txt b/Foundation/CMakeLists.txt index 5acc97e9b..77b060bdf 100644 --- a/Foundation/CMakeLists.txt +++ b/Foundation/CMakeLists.txt @@ -52,6 +52,7 @@ set( BASE_SRCS src/DigestEngine.cpp src/DigestStream.cpp src/DirectoryIterator.cpp + src/RecursiveDirectoryIteratorStrategies.cpp src/DirectoryWatcher.cpp src/Environment.cpp src/Error.cpp @@ -124,6 +125,7 @@ set( BASE_SRCS src/SharedMemory.cpp src/SignalHandler.cpp src/SimpleFileChannel.cpp + src/SortedDirectoryIterator.cpp src/SplitterChannel.cpp src/Stopwatch.cpp src/StreamChannel.cpp diff --git a/Foundation/Makefile b/Foundation/Makefile index 8e48ebdda..85043471b 100644 --- a/Foundation/Makefile +++ b/Foundation/Makefile @@ -22,10 +22,10 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel \ NotificationQueue PriorityNotificationQueue TimedNotificationQueue \ NullStream NumberFormatter NumberParser NumericString AbstractObserver \ Path PatternFormatter Process PurgeStrategy RWLock Random RandomStream \ - RegularExpression RefCountedObject Runnable RotateStrategy Condition \ + RecursiveDirectoryIteratorStrategies RegularExpression RefCountedObject Runnable RotateStrategy Condition \ SHA1Engine Semaphore SharedLibrary SimpleFileChannel \ - SignalHandler SplitterChannel Stopwatch StreamChannel StreamConverter StreamCopier \ - StreamTokenizer String StringTokenizer SynchronizedObject \ + SignalHandler SplitterChannel SortedDirectoryIterator Stopwatch StreamChannel \ + StreamConverter StreamCopier StreamTokenizer String StringTokenizer SynchronizedObject \ Task TaskManager TaskNotification TeeStream Hash HashStatistic \ TemporaryFile TextConverter TextEncoding TextIterator TextBufferIterator Thread ThreadLocal \ ThreadPool ThreadTarget ActiveDispatcher Timer Timespan Timestamp Timezone Token URI \ diff --git a/Foundation/include/Poco/DirectoryIterator.h b/Foundation/include/Poco/DirectoryIterator.h index ece8102fb..9c6747568 100644 --- a/Foundation/include/Poco/DirectoryIterator.h +++ b/Foundation/include/Poco/DirectoryIterator.h @@ -81,7 +81,7 @@ public: DirectoryIterator(const Path& path); /// Creates a directory iterator for the given path. - ~DirectoryIterator(); + virtual ~DirectoryIterator(); /// Destroys the DirectoryIterator. const std::string& name() const; @@ -95,7 +95,7 @@ public: DirectoryIterator& operator = (const Path& path); DirectoryIterator& operator = (const std::string& path); - DirectoryIterator& operator ++ (); // prefix + virtual DirectoryIterator& operator ++ (); // prefix //@ deprecated DirectoryIterator operator ++ (int); // postfix @@ -109,9 +109,11 @@ public: bool operator == (const DirectoryIterator& iterator) const; bool operator != (const DirectoryIterator& iterator) const; -private: +protected: Path _path; File _file; + +private: DirectoryIteratorImpl* _pImpl; }; diff --git a/Foundation/include/Poco/RecursiveDirectoryIterator.h b/Foundation/include/Poco/RecursiveDirectoryIterator.h new file mode 100644 index 000000000..43b6b2ef9 --- /dev/null +++ b/Foundation/include/Poco/RecursiveDirectoryIterator.h @@ -0,0 +1,281 @@ +// +// RecursiveDirectoryIterator.h +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: RecursiveDirectoryIterator +// +// Definition of the RecursiveDirectoryIterator class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_RecursiveDirectoryIterator_INCLUDE +#define Foundation_RecursiveDirectoryIterator_INCLUDE + +#include "Poco/Foundation.h" +#include "Poco/File.h" +#include "Poco/Path.h" +#include "Poco/RecursiveDirectoryIteratorImpl.h" +#include "Poco/RecursiveDirectoryIteratorStrategies.h" + + +namespace Poco +{ + +class DirectoryIterator; + +template +class RecursiveDirectoryIteratorImpl; + +template +class RecursiveDirectoryIterator + /// The RecursiveDirectoryIterator class is used to enumerate + /// all files in a directory and its subdirectories. + /// + /// RecursiveDirectoryIterator has some limitations: + /// * only forward iteration (++) is supported + /// * an iterator copied from another one will always + /// point to the same file as the original iterator, + /// even is the original iterator has been advanced + /// (all copies of an iterator share their state with + /// the original iterator) + /// + /// The class can follow different traversal strategies: + /// * depth-first strategy; + /// * siblings-first strategy. + /// The stategies are set by template parameter. + /// There are two corresponding typedefs: + /// * SimpleRecursiveDirectoryIterator; + /// * SiblingsFirstRecursiveDirectoryIterator. + /// + /// The depth of traversal can be limited by constructor + /// parameter maxDepth (which sets the infinite depth by default). +{ +public: + typedef RecursiveDirectoryIterator MyType; + + enum + { + D_INFINITE = 0 + }; + /// Constant for infinite traverse depth. + + RecursiveDirectoryIterator() + /// Creates the end iterator. + : _pImpl(0) + { + } + + RecursiveDirectoryIterator(const std::string& path, UInt16 maxDepth = D_INFINITE); + /// Creates a recursive directory iterator for the given path. + + RecursiveDirectoryIterator(const MyType& iterator) + /// Creates a copy of another recursive directory iterator. + : _pImpl(iterator._pImpl), _path(iterator._path), _file(iterator._file) + { + } + + RecursiveDirectoryIterator(const DirectoryIterator& iterator, UInt16 maxDepth = D_INFINITE) + /// Creates a recursive directory iterator for the path of + /// non-recursive directory iterator. + : _pImpl(new ImplType(iterator->path(), maxDepth)), _path(Path(_pImpl->get())), _file(_path) + { + } + + RecursiveDirectoryIterator(const File& file, UInt16 maxDepth = D_INFINITE) + /// Creates a recursive directory iterator for the given path. + : _pImpl(new ImplType(file.path(), maxDepth)), _path(Path(_pImpl->get())), _file(_path) + { + } + + RecursiveDirectoryIterator(const Path& path, UInt16 maxDepth = D_INFINITE) + /// Creates a recursive directory iterator for the given path. + : _pImpl(new ImplType(path.toString(), maxDepth)), _path(Path(_pImpl->get())), _file(_path) + { + } + + + ~RecursiveDirectoryIterator() + /// Destroys the DirectoryIterator. + { + if (_pImpl) + _pImpl->release(); + } + + const std::string& name() const + /// Returns the current filename. + { + return _path.getFileName(); + } + + const Poco::Path& path() const + /// Returns the current path. + { + return _path; + } + + UInt16 depth() const + /// Depth of recursion (counting from 1). + { + return _pImpl->depth(); + } + + UInt16 maxDepth() const + /// Max depth of recursion (counting from 1). + { + return _pImpl->maxDepth(); + } + + + MyType& operator =(const MyType& it) + { + if (_pImpl) + _pImpl->release(); + _pImpl = it._pImpl; + if (_pImpl) + { + _pImpl->duplicate(); + _path = it._path; + _file = _path; + } + return *this; + } + + MyType& operator =(const File& file) + { + if (_pImpl) + _pImpl->release(); + _pImpl = new ImplType(file.path()); + _path = Path(_pImpl->get()); + _file = _path; + return *this; + } + + + MyType& operator =(const Path& path) + { + if (_pImpl) + _pImpl->release(); + _pImpl = new ImplType(path.toString()); + _path = Path(_pImpl->get()); + _file = _path; + return *this; + } + + MyType& operator =(const std::string& path) + { + if (_pImpl) + _pImpl->release(); + _pImpl = new ImplType(path); + _path = Path(_pImpl->get()); + _file = _path; + return *this; + } + + MyType& operator ++() + { + if (_pImpl) + { + _path = Path(_pImpl->next()); + _file = _path; + } + return *this; + } + + const File& operator *() const + { + return _file; + } + + File& operator *() + { + return _file; + } + + const File* operator ->() const + { + return &_file; + } + + File* operator ->() + { + return &_file; + } + + + template + friend inline bool operator ==(const RecursiveDirectoryIterator& a, const RecursiveDirectoryIterator& b); + template + friend inline bool operator !=(const RecursiveDirectoryIterator& a, const RecursiveDirectoryIterator& b); + +private: + typedef RecursiveDirectoryIteratorImpl ImplType; + + ImplType* _pImpl; + Path _path; + File _file; +}; + + +// +// friend comparsion operators +// +template +inline bool operator ==(const RecursiveDirectoryIterator& a, const RecursiveDirectoryIterator& b) +{ + return a.path().toString() == b.path().toString();; +} + +template +inline bool operator !=(const RecursiveDirectoryIterator& a, const RecursiveDirectoryIterator& b) +{ + return a.path().toString() != b.path().toString();; +} + + +// +// exported instances +// +template class Foundation_API +RecursiveDirectoryIterator ; +template class Foundation_API +RecursiveDirectoryIterator ; + + +// +// typedefs +// +typedef RecursiveDirectoryIterator SimpleRecursiveDirectoryIterator; +typedef RecursiveDirectoryIterator SiblingsFirstRecursiveDirectoryIterator; + + +} // namespace Poco + +#endif // Foundation_RecursiveDirectoryIterator_INCLUDE diff --git a/Foundation/include/Poco/RecursiveDirectoryIteratorImpl.h b/Foundation/include/Poco/RecursiveDirectoryIteratorImpl.h new file mode 100644 index 000000000..fa4d7193b --- /dev/null +++ b/Foundation/include/Poco/RecursiveDirectoryIteratorImpl.h @@ -0,0 +1,131 @@ +// +// RecursiveDirectoryIteratorImpl.h +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: RecursiveDirectoryIterator +// +// Definition of the RecursiveDirectoryIteratorImpl class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_RecursiveDirectoryIteratorImpl_INCLUDE +#define Foundation_RecursiveDirectoryIteratorImpl_INCLUDE + +#include "Poco/Foundation.h" +#include "Poco/RecursiveDirectoryIteratorStrategies.h" +#include +#include + + +namespace Poco +{ + +class ChildrenFirstTraverse; +class SiblingsFirstTraverse; + +template +class RecursiveDirectoryIteratorImpl +{ +public: + enum + { + D_INFINITE = 0 + }; + /// Constant for infinite traverse depth. + + RecursiveDirectoryIteratorImpl(const std::string& path, UInt16 maxDepth = D_INFINITE) + : _maxDepth(maxDepth), _traverseStrategy(std::ptr_fun(depthFun), _maxDepth), _isFinished(false), _rc(1) + { + _itStack.push(DirectoryIterator(path)); + _current = _itStack.top()->path(); + } + + ~RecursiveDirectoryIteratorImpl() + { + } + + inline void duplicate() + { + ++_rc; + } + + inline void release() + { + if (--_rc == 0) + delete this; + } + + inline UInt16 depth() const + { + return depthFun(_itStack); + } + + inline UInt16 maxDepth() const + { + return _maxDepth; + } + + inline const std::string& get() const + { + return _current; + } + const std::string& next() + { + if (_isFinished) + return _current; + + _current = _traverseStrategy.next(&_itStack, &_isFinished); + + return _current; + } + +private: + typedef std::stack Stack; + + static UInt16 depthFun(const Stack& stack) + /// Function which implements the logic of determining + /// recursion depth. + { + return stack.size(); + } + + UInt16 _maxDepth; + TTraverseStrategy _traverseStrategy; + bool _isFinished; + Stack _itStack; + std::string _current; + int _rc; +}; + + +} // namespace Poco + +#endif // Foundation_RecursiveDirectoryIteratorImpl_INCLUDE diff --git a/Foundation/include/Poco/RecursiveDirectoryIteratorStrategies.h b/Foundation/include/Poco/RecursiveDirectoryIteratorStrategies.h new file mode 100644 index 000000000..7142ee9e5 --- /dev/null +++ b/Foundation/include/Poco/RecursiveDirectoryIteratorStrategies.h @@ -0,0 +1,112 @@ +// +// RecursiveDirectoryIteratorStategies.h +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: RecursiveDirectoryIterator +// +// Definitions of the RecursiveDirectoryIterator stategy classes. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_RecursiveDirectoryIteratorStategies_INCLUDE +#define Foundation_RecursiveDirectoryIteratorStategies_INCLUDE + +#include "Poco/Foundation.h" +#include "Poco/DirectoryIterator.h" +#include +#include +#include + + +namespace Poco +{ + +class TraverseBase +{ +public: + typedef std::stack Stack; + typedef std::pointer_to_unary_function DepthFunPtr; + + enum + { + D_INFINITE = 0 + }; + /// Constant for infinite traverse depth. + + TraverseBase(DepthFunPtr depthDeterminer, UInt16 maxDepth = D_INFINITE); + +protected: + bool isFiniteDepth(); + + DepthFunPtr _depthDeterminer; + UInt16 _maxDepth; + DirectoryIterator _itEnd; + +private: + TraverseBase(); + TraverseBase(const TraverseBase&); + TraverseBase& operator=(const TraverseBase&); +}; + + +class ChildrenFirstTraverse: public TraverseBase +{ +public: + ChildrenFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth = D_INFINITE); + + const std::string next(Stack* itStack, bool* isFinished); + +private: + ChildrenFirstTraverse(); + ChildrenFirstTraverse(const ChildrenFirstTraverse&); + ChildrenFirstTraverse& operator=(const ChildrenFirstTraverse&); +}; + + +class SiblingsFirstTraverse: public TraverseBase +{ +public: + SiblingsFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth = D_INFINITE); + + const std::string next(Stack* itStack, bool* isFinished); + +private: + SiblingsFirstTraverse(); + SiblingsFirstTraverse(const SiblingsFirstTraverse&); + SiblingsFirstTraverse& operator=(const SiblingsFirstTraverse&); + + std::stack > _dirsStack; +}; + + +} // namespace Poco + +#endif // Foundation_RecursiveDirectoryIteratorStategies_INCLUDE diff --git a/Foundation/include/Poco/SortedDirectoryIterator.h b/Foundation/include/Poco/SortedDirectoryIterator.h new file mode 100644 index 000000000..4b6684d21 --- /dev/null +++ b/Foundation/include/Poco/SortedDirectoryIterator.h @@ -0,0 +1,92 @@ +// +// SortedDirectoryIterator.h +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: DirectoryIterator +// +// Definition of the SortedDirectoryIterator class. +// +// Copyright (c) 2004-2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_SortedDirectoryIterator_INCLUDED +#define Foundation_SortedDirectoryIterator_INCLUDED + +#include "Poco/Foundation.h" +#include "Poco/File.h" +#include "Poco/Path.h" +#include "Poco/DirectoryIterator.h" +#include + + +namespace Poco +{ + +class Foundation_API SortedDirectoryIterator: public DirectoryIterator + /// The SortedDirectoryIterator class is similar to + /// DirectoryIterator class, but places directories before files + /// and sorts content alphabetically. +{ +public: + SortedDirectoryIterator(); + /// Creates the end iterator. + + SortedDirectoryIterator(const std::string& path); + /// Creates a directory iterator for the given path. + + SortedDirectoryIterator(const DirectoryIterator& iterator); + /// Creates a directory iterator for the given path. + + SortedDirectoryIterator(const File& file); + /// Creates a directory iterator for the given file. + + SortedDirectoryIterator(const Path& path); + /// Creates a directory iterator for the given path. + + virtual ~SortedDirectoryIterator(); + /// Destroys the DirsFirstDirectoryIterator. + + virtual SortedDirectoryIterator& operator ++(); // prefix + +private: + bool _is_finished; + std::deque _directories; + std::deque _files; + + void next(); + /// Take next item + void scan(); + /// Scan directory to collect its children directories and files +}; + + +} // namespace Poco + +#endif //Foundation_SortedDirectoryIterator_INCLUDED diff --git a/Foundation/src/RecursiveDirectoryIteratorStrategies.cpp b/Foundation/src/RecursiveDirectoryIteratorStrategies.cpp new file mode 100644 index 000000000..c5093ef16 --- /dev/null +++ b/Foundation/src/RecursiveDirectoryIteratorStrategies.cpp @@ -0,0 +1,179 @@ +// +// RecursiveDirectoryIteratorStategies.cpp +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: RecursiveDirectoryIterator +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/RecursiveDirectoryIteratorStrategies.h" + + +namespace Poco +{ + +using namespace std; + +// +// TraverseBase +// +TraverseBase::TraverseBase(DepthFunPtr depthDeterminer, UInt16 maxDepth) + : _depthDeterminer(depthDeterminer), _maxDepth(maxDepth) +{ +} + + +inline bool TraverseBase::isFiniteDepth() +{ + return _maxDepth != D_INFINITE; +} + + +// +// ChildrenFirstTraverse +// +ChildrenFirstTraverse::ChildrenFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth) + : TraverseBase(depthDeterminer, maxDepth) +{ +} + + +const string ChildrenFirstTraverse::next(Stack* itStack, bool* isFinished) +{ + // pointer mustn't point to NULL and iteration mustn't be finished + poco_check_ptr(isFinished); + poco_assert(!(*isFinished)); + + stack it; + + //_depthDeterminer(it); + + // go deeper into not empty directory + // (if depth limit allows) + bool isDepthLimitReached = isFiniteDepth() && _depthDeterminer(*itStack) >= _maxDepth; + if (!isDepthLimitReached && itStack->top()->isDirectory()) + { + DirectoryIterator child_it(itStack->top().path()); + // check if directory is empty + if (child_it != _itEnd) + { + itStack->push(child_it); + return child_it->path(); + } + } + + ++(itStack->top()); + + poco_assert(!itStack->empty()); + // return up until there isn't right sibling + while (itStack->top() == _itEnd) + { + itStack->pop(); + + // detect end of traversal + if (itStack->empty()) + { + *isFinished = true; + return _itEnd->path(); + } + else + { + ++(itStack->top()); + } + } + + return itStack->top()->path(); +} + + +// +// SiblingsFirstTraverse +// +SiblingsFirstTraverse::SiblingsFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth) + : TraverseBase(depthDeterminer, maxDepth) +{ + _dirsStack.push(queue()); +} + + +const string SiblingsFirstTraverse::next(Stack* itStack, bool* isFinished) +{ + // pointer mustn't point to NULL and iteration mustn't be finished + poco_check_ptr(isFinished); + poco_assert(!(*isFinished)); + + // add dirs to queue (if depth limit allows) + bool isDepthLimitReached = isFiniteDepth() && _depthDeterminer(*itStack) >= _maxDepth; + if (!isDepthLimitReached && itStack->top()->isDirectory()) + { + const string& p = itStack->top()->path(); + _dirsStack.top().push(p); + } + + ++(itStack->top()); + + poco_assert(!itStack->empty()); + // return up until there isn't right sibling + while (itStack->top() == _itEnd) + { + // try to find first not empty directory and go deeper + while (!_dirsStack.top().empty()) + { + string dir = _dirsStack.top().front(); + _dirsStack.top().pop(); + DirectoryIterator child_it(dir); + + // check if directory is empty + if (child_it != _itEnd) + { + itStack->push(child_it); + _dirsStack.push(queue()); + return child_it->path(); + } + } + + // if fail go upper + itStack->pop(); + _dirsStack.pop(); + + // detect end of traversal + if (itStack->empty()) + { + *isFinished = true; + return _itEnd->path(); + } + } + + return itStack->top()->path(); +} + + +} // namespace Poco diff --git a/Foundation/src/SortedDirectoryIterator.cpp b/Foundation/src/SortedDirectoryIterator.cpp new file mode 100644 index 000000000..73131d2cd --- /dev/null +++ b/Foundation/src/SortedDirectoryIterator.cpp @@ -0,0 +1,137 @@ +// +// SortedDirectoryIterator.cpp +// +// $Id$ +// +// Library: Foundation +// Package: Filesystem +// Module: DirectoryIterator +// +// Copyright (c) 2004-2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +#include "Poco/SortedDirectoryIterator.h" +#include + + +namespace Poco +{ + +SortedDirectoryIterator::SortedDirectoryIterator() + : DirectoryIterator(), _is_finished(true) +{ +} + + +SortedDirectoryIterator::SortedDirectoryIterator(const std::string& path) + : DirectoryIterator(path), _is_finished(false) +{ + scan(); + next(); +} + + +SortedDirectoryIterator::SortedDirectoryIterator(const DirectoryIterator& iterator) + : DirectoryIterator(iterator), _is_finished(false) +{ + scan(); + next(); +} + + +SortedDirectoryIterator::SortedDirectoryIterator(const File& file) + : DirectoryIterator(file), _is_finished(false) +{ + scan(); + next(); +} + + +SortedDirectoryIterator::SortedDirectoryIterator(const Path& path) + : DirectoryIterator(path), _is_finished(false) +{ + scan(); + next(); +} + + +SortedDirectoryIterator::~SortedDirectoryIterator() +{ +} + +SortedDirectoryIterator& SortedDirectoryIterator::operator ++() +{ + if (!_is_finished) + { + next(); + } + return *this; +} + + +void SortedDirectoryIterator::scan() +{ + DirectoryIterator end_it; + while (*this != end_it) + { + if ((*this)->isDirectory()) + _directories.push_back(_path.toString()); + else + _files.push_back(_path.toString()); + + DirectoryIterator::operator++(); + } + + std::sort(_directories.begin(), _directories.end()); + std::sort(_files.begin(), _files.end()); +} + + +void SortedDirectoryIterator::next() +{ + DirectoryIterator end_it; + if (!_directories.empty()) + { + _path.assign(_directories.front()); + _directories.pop_front(); + _file = _path; + } + else if (!_files.empty()) + { + _path.assign(_files.front()); + _files.pop_front(); + _file = _path; + } + else + { + _is_finished = true; + _path = end_it.path(); + _file = _path; + } +} + + +} // namespace Poco diff --git a/Foundation/testsuite/CMakeLists.txt b/Foundation/testsuite/CMakeLists.txt index 8e40c6e6e..3385d124a 100644 --- a/Foundation/testsuite/CMakeLists.txt +++ b/Foundation/testsuite/CMakeLists.txt @@ -24,6 +24,7 @@ src/DateTimeParserTest.cpp src/DateTimeTest.cpp src/DateTimeTestSuite.cpp src/DigestStreamTest.cpp +src/DirectoryIteratorsTest.cpp src/DirectoryWatcherTest.cpp src/Driver.cpp src/DummyDelegate.cpp diff --git a/Foundation/testsuite/Makefile-Driver b/Foundation/testsuite/Makefile-Driver index 8f0a5626e..f0bb73c44 100644 --- a/Foundation/testsuite/Makefile-Driver +++ b/Foundation/testsuite/Makefile-Driver @@ -39,7 +39,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \ HashSetTest HashMapTest SharedMemoryTest \ UniqueExpireCacheTest UniqueExpireLRUCacheTest UnicodeConverterTest \ TuplesTest NamedTuplesTest TypeListTest VarTest DynamicTestSuite FileStreamTest \ - MemoryStreamTest ObjectPoolTest DirectoryWatcherTest + MemoryStreamTest ObjectPoolTest DirectoryWatcherTest DirectoryIteratorsTest target = testrunner target_version = 1 diff --git a/Foundation/testsuite/src/DirectoryIteratorsTest.cpp b/Foundation/testsuite/src/DirectoryIteratorsTest.cpp new file mode 100644 index 000000000..f62914964 --- /dev/null +++ b/Foundation/testsuite/src/DirectoryIteratorsTest.cpp @@ -0,0 +1,233 @@ +// +// DirectoryIteratorsTest.cpp +// +// $Id: //poco/1.4/Foundation/testsuite/src/DirectoryIteratorsTest.cpp#1 $ +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "DirectoryIteratorsTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/DirectoryIterator.h" +#include "Poco/SortedDirectoryIterator.h" +#include "Poco/RecursiveDirectoryIterator.h" +#include "Poco/FileStream.h" + +#include + +using namespace Poco; + + +DirectoryIteratorsTest::DirectoryIteratorsTest(const std::string& name): + CppUnit::TestCase(name) +{ +} + + +DirectoryIteratorsTest::~DirectoryIteratorsTest() +{ +} + + +void DirectoryIteratorsTest::testDirectoryIterator() +{ + Path p = path(); + DirectoryIterator dirIterator(p); + DirectoryIterator end; + std::vector result; + std::string file; + + while (dirIterator != end) + { + file = dirIterator->path(); + ++dirIterator; + result.push_back(file); + } + + assertEquals(7, result.size()); +} + + +void DirectoryIteratorsTest::testSortedDirectoryIterator() +{ + Path p = path(); + SortedDirectoryIterator dirIterator(p); + SortedDirectoryIterator end; + std::vector result; + std::string file; + + while (dirIterator != end) + { + file = Path(dirIterator->path()).getFileName(); + ++dirIterator; + result.push_back(file); + } + + assertEquals(7, result.size()); + assertEquals("first", result[0]); + assertEquals("1", result[1]); + assertEquals("2", result[2]); + assertEquals("A", result[3]); + assertEquals("B", result[4]); + assertEquals("a", result[5]); + assertEquals("b", result[6]); +} + + +void DirectoryIteratorsTest::testSimpleRecursiveDirectoryIterator() +{ + Path p = path(); + SimpleRecursiveDirectoryIterator dirIterator(p); + SimpleRecursiveDirectoryIterator end; + std::vector result; + std::string file; + + while (dirIterator != end) + { + file = dirIterator->path(); + ++dirIterator; + result.push_back(file); + } + + assertEquals(20, result.size()); +} + + +void DirectoryIteratorsTest::testSiblingsFirstRecursiveDirectoryIterator() +{ + Path p = path(); + SiblingsFirstRecursiveDirectoryIterator dirIterator(p); + SiblingsFirstRecursiveDirectoryIterator end; + std::vector result; + std::string file; + + while (dirIterator != end) + { + file = dirIterator->path(); + ++dirIterator; + result.push_back(file); + } + + assertEquals(20, result.size()); +} + + +void DirectoryIteratorsTest::setUp() +{ + try + { + File d(path()); + d.remove(true); + } + catch (...) + { + } + + /* + Build Directory Tree like this: + + DirectoryIteratorsTest + |-- 1 + |-- 2 + |-- A + |-- B + |-- a + |-- b + `-- first + |-- 1 + |-- 2 + |-- A + |-- B + |-- a + |-- b + `-- second + |-- 1 + |-- 2 + |-- A + |-- B + |-- a + `-- b + + 2 directories, 18 files + */ + Path p = path(); + createSubdir(p); + + p.pushDirectory("first"); + createSubdir(p); + + p.pushDirectory("second"); + createSubdir(p); +} + + +void DirectoryIteratorsTest::createSubdir(Path& p) +{ + File d(p); + d.createDirectories(); + FileStream f1(p.toString() + "b"); + FileStream f2(p.toString() + "1"); + FileStream f3(p.toString() + "A"); + FileStream f4(p.toString() + "2"); + FileStream f5(p.toString() + "B"); + FileStream f6(p.toString() + "a"); +} + + +void DirectoryIteratorsTest::tearDown() +{ + try + { + File d(path()); + d.remove(true); + } + catch (...) + { + } +} + + +Poco::Path DirectoryIteratorsTest::path() const +{ + Path p(Path::current()); + p.pushDirectory("DirectoryIteratorsTest"); + return p; +} + + +CppUnit::Test* DirectoryIteratorsTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DirectoryIteratorsTest"); + + CppUnit_addTest(pSuite, DirectoryIteratorsTest, testDirectoryIterator); + CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSortedDirectoryIterator); + CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSimpleRecursiveDirectoryIterator); + CppUnit_addTest(pSuite, DirectoryIteratorsTest, testSiblingsFirstRecursiveDirectoryIterator); + + return pSuite; +} diff --git a/Foundation/testsuite/src/DirectoryIteratorsTest.h b/Foundation/testsuite/src/DirectoryIteratorsTest.h new file mode 100644 index 000000000..f919e89ce --- /dev/null +++ b/Foundation/testsuite/src/DirectoryIteratorsTest.h @@ -0,0 +1,68 @@ +// +// DirectoryIteratorsTest.h +// +// $Id: //poco/1.4/Foundation/testsuite/src/DirectoryIteratorsTest.h#1 $ +// +// Definition of the DirectoryIteratorsTest class. +// +// Copyright (c) 2012, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef DirectoryIteratorsTest_INCLUDED +#define DirectoryIteratorsTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Path.h" +#include "CppUnit/TestCase.h" + + +class DirectoryIteratorsTest: public CppUnit::TestCase +{ +public: + DirectoryIteratorsTest(const std::string& name); + ~DirectoryIteratorsTest(); + + void testDirectoryIterator(); + void testSortedDirectoryIterator(); + void testSimpleRecursiveDirectoryIterator(); + void testSiblingsFirstRecursiveDirectoryIterator(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +protected: + Poco::Path path() const; + void createSubdir(Poco::Path& p); + +private: +}; + + +#endif // DirectoryIteratorsTest_INCLUDED diff --git a/Foundation/testsuite/src/FilesystemTestSuite.cpp b/Foundation/testsuite/src/FilesystemTestSuite.cpp index a46e0d685..492868c01 100644 --- a/Foundation/testsuite/src/FilesystemTestSuite.cpp +++ b/Foundation/testsuite/src/FilesystemTestSuite.cpp @@ -35,6 +35,7 @@ #include "FileTest.h" #include "GlobTest.h" #include "DirectoryWatcherTest.h" +#include "DirectoryIteratorsTest.h" CppUnit::Test* FilesystemTestSuite::suite() @@ -45,6 +46,7 @@ CppUnit::Test* FilesystemTestSuite::suite() pSuite->addTest(FileTest::suite()); pSuite->addTest(GlobTest::suite()); pSuite->addTest(DirectoryWatcherTest::suite()); + pSuite->addTest(DirectoryIteratorsTest::suite()); return pSuite; }