1 /*
2 * Copyright (c) 2008 Stephan Aßmus <superstippi@gmx.de>
3 * Copyright (c) 1998-2007 Matthijs Hollemans
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7 #include "InitialIterator.h"
8
9 #include <new>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <Directory.h>
15
16 #include "Model.h"
17
18 using std::nothrow;
19
20 // TODO: stippi: Check if this is a the best place to maintain a global
21 // list of files and folders for node monitoring. It should probably monitor
22 // every file that was grepped, as well as every visited (sub) folder.
23 // For the moment I don't know the life cycle of the InitialIterator object.
24
25
InitialIterator(const Model * model)26 InitialIterator::InitialIterator(const Model* model)
27 : FileIterator(),
28 fDirectories(32),
29 fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)),
30 fCurrentRef(0),
31
32 fSelectedFiles(model->fSelectedFiles),
33
34 fRecurseDirs(model->fRecurseDirs),
35 fRecurseLinks(model->fRecurseLinks),
36 fSkipDotDirs(model->fSkipDotDirs),
37 fTextOnly(model->fTextOnly)
38 {
39 if (!fCurrentDir || !fDirectories.AddItem(fCurrentDir)) {
40 // init error
41 delete fCurrentDir;
42 fCurrentDir = NULL;
43 }
44 }
45
46
~InitialIterator()47 InitialIterator::~InitialIterator()
48 {
49 for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--)
50 delete (BDirectory*)fDirectories.ItemAt(i);
51 }
52
53
54 bool
IsValid() const55 InitialIterator::IsValid() const
56 {
57 return fCurrentDir != NULL;
58 }
59
60
61 bool
GetNextName(char * buffer)62 InitialIterator::GetNextName(char* buffer)
63 {
64 BEntry entry;
65 struct stat fileStat;
66
67 while (true) {
68 // Traverse the directory to get a new BEntry.
69 // _GetNextEntry returns false if there are no
70 // more entries, and we exit the loop.
71
72 if (!_GetNextEntry(entry))
73 return false;
74
75 // If the entry is a subdir, then add it to the
76 // list of directories and continue the loop.
77 // If the entry is a file and we can grep it
78 // (i.e. it is a text file), then we're done
79 // here. Otherwise, continue with the next entry.
80
81 if (entry.GetStat(&fileStat) == B_OK) {
82 if (S_ISDIR(fileStat.st_mode)) {
83 // subdir
84 _ExamineSubdir(entry);
85 } else {
86 // file or a (non-traversed) symbolic link
87 if (_ExamineFile(entry, buffer, fTextOnly))
88 return true;
89 }
90 }
91 }
92 }
93
94
95 bool
NotifyNegatives() const96 InitialIterator::NotifyNegatives() const
97 {
98 return false;
99 }
100
101
102 bool
GetTopEntry(BEntry & entry)103 InitialIterator::GetTopEntry(BEntry& entry)
104 {
105 // If the user selected one or more files, we must look
106 // at the "refs" inside the message that was passed into
107 // our add-on's process_refs(). If the user didn't select
108 // any files, we will simply read all the entries from the
109 // current working directory.
110
111 entry_ref fileRef;
112
113 if (fSelectedFiles.FindRef("refs", fCurrentRef, &fileRef) == B_OK) {
114 entry.SetTo(&fileRef, fRecurseLinks);
115 ++fCurrentRef;
116 return true;
117 } else if (fCurrentRef > 0) {
118 // when we get here, we have processed
119 // all the refs from the message
120 return false;
121 } else if (fCurrentDir != NULL) {
122 // examine the whole directory
123 return fCurrentDir->GetNextEntry(&entry, fRecurseLinks) == B_OK;
124 }
125
126 return false;
127 }
128
129
130 bool
FollowSubdir(BEntry & entry) const131 InitialIterator::FollowSubdir(BEntry& entry) const
132 {
133 if (!fRecurseDirs)
134 return false;
135
136 if (fSkipDotDirs) {
137 char nameBuf[B_FILE_NAME_LENGTH];
138 if (entry.GetName(nameBuf) == B_OK) {
139 if (*nameBuf == '.')
140 return false;
141 }
142 }
143
144 return true;
145 }
146
147
148 // #pragma mark - private
149
150
151 bool
_GetNextEntry(BEntry & entry)152 InitialIterator::_GetNextEntry(BEntry& entry)
153 {
154 if (fDirectories.CountItems() == 1)
155 return GetTopEntry(entry);
156 else
157 return _GetSubEntry(entry);
158 }
159
160
161 bool
_GetSubEntry(BEntry & entry)162 InitialIterator::_GetSubEntry(BEntry& entry)
163 {
164 if (!fCurrentDir)
165 return false;
166
167 if (fCurrentDir->GetNextEntry(&entry, fRecurseLinks) == B_OK)
168 return true;
169
170 // If we get here, there are no more entries in
171 // this subdir, so return to the parent directory.
172
173 fDirectories.RemoveItem(fCurrentDir);
174 delete fCurrentDir;
175 fCurrentDir = (BDirectory*)fDirectories.LastItem();
176
177 return _GetNextEntry(entry);
178 }
179
180
181 void
_ExamineSubdir(BEntry & entry)182 InitialIterator::_ExamineSubdir(BEntry& entry)
183 {
184 if (!FollowSubdir(entry))
185 return;
186
187 BDirectory* dir = new (nothrow) BDirectory(&entry);
188 if (dir == NULL || dir->InitCheck() != B_OK || !fDirectories.AddItem(dir)) {
189 // clean up
190 delete dir;
191 return;
192 }
193
194 fCurrentDir = dir;
195 }
196