1//
2// RecursiveDirectoryIteratorStategies.cpp
3//
4// Library: Foundation
5// Package: Filesystem
6// Module: RecursiveDirectoryIterator
7//
8// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/DirectoryIteratorStrategy.h"
16
17
18namespace Poco {
19
20
21//
22// TraverseBase
23//
24TraverseBase::TraverseBase(DepthFunPtr depthDeterminer, UInt16 maxDepth)
25 : _depthDeterminer(depthDeterminer), _maxDepth(maxDepth)
26{
27}
28
29
30inline bool TraverseBase::isFiniteDepth()
31{
32 return _maxDepth != D_INFINITE;
33}
34
35
36bool TraverseBase::isDirectory(Poco::File& file)
37{
38 try
39 {
40 return file.isDirectory();
41 }
42 catch (...)
43 {
44 return false;
45 }
46}
47
48
49//
50// ChildrenFirstTraverse
51//
52ChildrenFirstTraverse::ChildrenFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth)
53 : TraverseBase(depthDeterminer, maxDepth)
54{
55}
56
57
58const std::string ChildrenFirstTraverse::next(Stack* itStack, bool* isFinished)
59{
60 // pointer mustn't point to NULL and iteration mustn't be finished
61 poco_check_ptr(isFinished);
62 poco_assert(!(*isFinished));
63
64 std::stack<DirectoryIterator> it;
65
66 //_depthDeterminer(it);
67
68 // go deeper into not empty directory
69 // (if depth limit allows)
70 bool isDepthLimitReached = isFiniteDepth() && _depthDeterminer(*itStack) >= _maxDepth;
71 if (!isDepthLimitReached && isDirectory(*itStack->top()))
72 {
73 // check the dir is iterable
74 try
75 {
76 DirectoryIterator child_it(itStack->top().path());
77 // check if directory is empty
78 if (child_it != _itEnd)
79 {
80 itStack->push(child_it);
81 return child_it->path();
82 }
83 }
84 catch (...)
85 {
86 }
87 }
88
89 ++(itStack->top());
90
91 poco_assert(!itStack->empty());
92 // return up until there isn't right sibling
93 while (itStack->top() == _itEnd)
94 {
95 itStack->pop();
96
97 // detect end of traversal
98 if (itStack->empty())
99 {
100 *isFinished = true;
101 return _itEnd->path();
102 }
103 else
104 {
105 ++(itStack->top());
106 }
107 }
108
109 return itStack->top()->path();
110}
111
112
113//
114// SiblingsFirstTraverse
115//
116SiblingsFirstTraverse::SiblingsFirstTraverse(DepthFunPtr depthDeterminer, UInt16 maxDepth)
117 : TraverseBase(depthDeterminer, maxDepth)
118{
119 _dirsStack.push(std::queue<std::string>());
120}
121
122
123const std::string SiblingsFirstTraverse::next(Stack* itStack, bool* isFinished)
124{
125 // pointer mustn't point to NULL and iteration mustn't be finished
126 poco_check_ptr(isFinished);
127 poco_assert(!(*isFinished));
128
129 // add dirs to queue (if depth limit allows)
130 bool isDepthLimitReached = isFiniteDepth() && _depthDeterminer(*itStack) >= _maxDepth;
131 if (!isDepthLimitReached && isDirectory(*itStack->top()))
132 {
133 const std::string& p = itStack->top()->path();
134 _dirsStack.top().push(p);
135 }
136
137 ++(itStack->top());
138
139 poco_assert(!itStack->empty());
140 // return up until there isn't right sibling
141 while (itStack->top() == _itEnd)
142 {
143 // try to find first not empty directory and go deeper
144 while (!_dirsStack.top().empty())
145 {
146 std::string dir = _dirsStack.top().front();
147 _dirsStack.top().pop();
148 DirectoryIterator child_it;
149
150 // check the dir is iterable
151 try
152 {
153 child_it = dir;
154 }
155 catch (...)
156 {
157 continue;
158 }
159
160 // check if directory is empty
161 if (child_it != _itEnd)
162 {
163 itStack->push(child_it);
164 _dirsStack.push(std::queue<std::string>());
165 return child_it->path();
166 }
167 }
168
169 // if fail go upper
170 itStack->pop();
171 _dirsStack.pop();
172
173 // detect end of traversal
174 if (itStack->empty())
175 {
176 *isFinished = true;
177 return _itEnd->path();
178 }
179 }
180
181 return itStack->top()->path();
182}
183
184
185} // namespace Poco
186