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 18using 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 26InitialIterator::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 47InitialIterator::~InitialIterator() 48{ 49 for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--) 50 delete (BDirectory*)fDirectories.ItemAt(i); 51} 52 53 54bool 55InitialIterator::IsValid() const 56{ 57 return fCurrentDir != NULL; 58} 59 60 61bool 62InitialIterator::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 95bool 96InitialIterator::NotifyNegatives() const 97{ 98 return false; 99} 100 101 102bool 103InitialIterator::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 130bool 131InitialIterator::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 151bool 152InitialIterator::_GetNextEntry(BEntry& entry) 153{ 154 if (fDirectories.CountItems() == 1) 155 return GetTopEntry(entry); 156 else 157 return _GetSubEntry(entry); 158} 159 160 161bool 162InitialIterator::_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 181void 182InitialIterator::_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