/* * Copyright (c) 2008 Stephan Aßmus * Copyright (c) 1998-2007 Matthijs Hollemans * All rights reserved. Distributed under the terms of the MIT License. */ #include "InitialIterator.h" #include #include #include #include #include #include "Model.h" using std::nothrow; // TODO: stippi: Check if this is a the best place to maintain a global // list of files and folders for node monitoring. It should probably monitor // every file that was grepped, as well as every visited (sub) folder. // For the moment I don't know the life cycle of the InitialIterator object. InitialIterator::InitialIterator(const Model* model) : FileIterator(), fDirectories(32), fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)), fCurrentRef(0), fSelectedFiles(model->fSelectedFiles), fRecurseDirs(model->fRecurseDirs), fRecurseLinks(model->fRecurseLinks), fSkipDotDirs(model->fSkipDotDirs), fTextOnly(model->fTextOnly) { if (!fCurrentDir || !fDirectories.AddItem(fCurrentDir)) { // init error delete fCurrentDir; fCurrentDir = NULL; } } InitialIterator::~InitialIterator() { for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--) delete (BDirectory*)fDirectories.ItemAt(i); } bool InitialIterator::IsValid() const { return fCurrentDir != NULL; } bool InitialIterator::GetNextName(char* buffer) { BEntry entry; struct stat fileStat; while (true) { // Traverse the directory to get a new BEntry. // _GetNextEntry returns false if there are no // more entries, and we exit the loop. if (!_GetNextEntry(entry)) return false; // If the entry is a subdir, then add it to the // list of directories and continue the loop. // If the entry is a file and we can grep it // (i.e. it is a text file), then we're done // here. Otherwise, continue with the next entry. if (entry.GetStat(&fileStat) == B_OK) { if (S_ISDIR(fileStat.st_mode)) { // subdir _ExamineSubdir(entry); } else { // file or a (non-traversed) symbolic link if (_ExamineFile(entry, buffer, fTextOnly)) return true; } } } } bool InitialIterator::NotifyNegatives() const { return false; } bool InitialIterator::GetTopEntry(BEntry& entry) { // If the user selected one or more files, we must look // at the "refs" inside the message that was passed into // our add-on's process_refs(). If the user didn't select // any files, we will simply read all the entries from the // current working directory. entry_ref fileRef; if (fSelectedFiles.FindRef("refs", fCurrentRef, &fileRef) == B_OK) { entry.SetTo(&fileRef, fRecurseLinks); ++fCurrentRef; return true; } else if (fCurrentRef > 0) { // when we get here, we have processed // all the refs from the message return false; } else if (fCurrentDir != NULL) { // examine the whole directory return fCurrentDir->GetNextEntry(&entry, fRecurseLinks) == B_OK; } return false; } bool InitialIterator::FollowSubdir(BEntry& entry) const { if (!fRecurseDirs) return false; if (fSkipDotDirs) { char nameBuf[B_FILE_NAME_LENGTH]; if (entry.GetName(nameBuf) == B_OK) { if (*nameBuf == '.') return false; } } return true; } // #pragma mark - private bool InitialIterator::_GetNextEntry(BEntry& entry) { if (fDirectories.CountItems() == 1) return GetTopEntry(entry); else return _GetSubEntry(entry); } bool InitialIterator::_GetSubEntry(BEntry& entry) { if (!fCurrentDir) return false; if (fCurrentDir->GetNextEntry(&entry, fRecurseLinks) == B_OK) return true; // If we get here, there are no more entries in // this subdir, so return to the parent directory. fDirectories.RemoveItem(fCurrentDir); delete fCurrentDir; fCurrentDir = (BDirectory*)fDirectories.LastItem(); return _GetNextEntry(entry); } void InitialIterator::_ExamineSubdir(BEntry& entry) { if (!FollowSubdir(entry)) return; BDirectory* dir = new (nothrow) BDirectory(&entry); if (dir == NULL || dir->InitCheck() != B_OK || !fDirectories.AddItem(dir)) { // clean up delete dir; return; } fCurrentDir = dir; }