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 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 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 55 InitialIterator::IsValid() const 56 { 57 return fCurrentDir != NULL; 58 } 59 60 61 bool 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 96 InitialIterator::NotifyNegatives() const 97 { 98 return false; 99 } 100 101 102 bool 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 131 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 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 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 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