1*1fffad3fSStephan Aßmus /* 2*1fffad3fSStephan Aßmus * Copyright (c) 2008 Stephan Aßmus <superstippi@gmx.de> 3*1fffad3fSStephan Aßmus * Copyright (c) 1998-2007 Matthijs Hollemans 4*1fffad3fSStephan Aßmus * 5*1fffad3fSStephan Aßmus * Permission is hereby granted, free of charge, to any person obtaining a 6*1fffad3fSStephan Aßmus * copy of this software and associated documentation files (the "Software"), 7*1fffad3fSStephan Aßmus * to deal in the Software without restriction, including without limitation 8*1fffad3fSStephan Aßmus * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9*1fffad3fSStephan Aßmus * and/or sell copies of the Software, and to permit persons to whom the 10*1fffad3fSStephan Aßmus * Software is furnished to do so, subject to the following conditions: 11*1fffad3fSStephan Aßmus * 12*1fffad3fSStephan Aßmus * The above copyright notice and this permission notice shall be included in 13*1fffad3fSStephan Aßmus * all copies or substantial portions of the Software. 14*1fffad3fSStephan Aßmus * 15*1fffad3fSStephan Aßmus * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*1fffad3fSStephan Aßmus * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*1fffad3fSStephan Aßmus * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18*1fffad3fSStephan Aßmus * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*1fffad3fSStephan Aßmus * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20*1fffad3fSStephan Aßmus * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21*1fffad3fSStephan Aßmus * DEALINGS IN THE SOFTWARE. 22*1fffad3fSStephan Aßmus */ 23*1fffad3fSStephan Aßmus 24*1fffad3fSStephan Aßmus #include "FileIterator.h" 25*1fffad3fSStephan Aßmus 26*1fffad3fSStephan Aßmus #include <new> 27*1fffad3fSStephan Aßmus #include <stdio.h> 28*1fffad3fSStephan Aßmus #include <stdlib.h> 29*1fffad3fSStephan Aßmus #include <string.h> 30*1fffad3fSStephan Aßmus 31*1fffad3fSStephan Aßmus #include <Directory.h> 32*1fffad3fSStephan Aßmus #include <NodeInfo.h> 33*1fffad3fSStephan Aßmus #include <Path.h> 34*1fffad3fSStephan Aßmus 35*1fffad3fSStephan Aßmus #include "Model.h" 36*1fffad3fSStephan Aßmus 37*1fffad3fSStephan Aßmus using std::nothrow; 38*1fffad3fSStephan Aßmus 39*1fffad3fSStephan Aßmus // TODO: stippi: Check if this is a the best place to maintain a global 40*1fffad3fSStephan Aßmus // list of files and folders for node monitoring. It should probably monitor 41*1fffad3fSStephan Aßmus // every file that was grepped, as well as every visited (sub) folder. 42*1fffad3fSStephan Aßmus // For the moment I don't know the life cycle of the FileIterator object. 43*1fffad3fSStephan Aßmus 44*1fffad3fSStephan Aßmus 45*1fffad3fSStephan Aßmus FileIterator::FileIterator(Model* model) 46*1fffad3fSStephan Aßmus : fDirectories(10), 47*1fffad3fSStephan Aßmus fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)), 48*1fffad3fSStephan Aßmus fCurrentRef(0), 49*1fffad3fSStephan Aßmus fModel(model) 50*1fffad3fSStephan Aßmus { 51*1fffad3fSStephan Aßmus if (!fCurrentDir || !fDirectories.AddItem(fCurrentDir)) { 52*1fffad3fSStephan Aßmus // init error 53*1fffad3fSStephan Aßmus delete fCurrentDir; 54*1fffad3fSStephan Aßmus fCurrentDir = NULL; 55*1fffad3fSStephan Aßmus } 56*1fffad3fSStephan Aßmus } 57*1fffad3fSStephan Aßmus 58*1fffad3fSStephan Aßmus 59*1fffad3fSStephan Aßmus FileIterator::~FileIterator() 60*1fffad3fSStephan Aßmus { 61*1fffad3fSStephan Aßmus for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--) 62*1fffad3fSStephan Aßmus delete (BDirectory*)fDirectories.ItemAt(i); 63*1fffad3fSStephan Aßmus } 64*1fffad3fSStephan Aßmus 65*1fffad3fSStephan Aßmus 66*1fffad3fSStephan Aßmus bool 67*1fffad3fSStephan Aßmus FileIterator::IsValid() const 68*1fffad3fSStephan Aßmus { 69*1fffad3fSStephan Aßmus return fCurrentDir != NULL; 70*1fffad3fSStephan Aßmus } 71*1fffad3fSStephan Aßmus 72*1fffad3fSStephan Aßmus 73*1fffad3fSStephan Aßmus bool 74*1fffad3fSStephan Aßmus FileIterator::GetNextName(char* buffer) 75*1fffad3fSStephan Aßmus { 76*1fffad3fSStephan Aßmus BEntry entry; 77*1fffad3fSStephan Aßmus struct stat fileStat; 78*1fffad3fSStephan Aßmus 79*1fffad3fSStephan Aßmus while (true) { 80*1fffad3fSStephan Aßmus // Traverse the directory to get a new BEntry. 81*1fffad3fSStephan Aßmus // _GetNextEntry returns false if there are no 82*1fffad3fSStephan Aßmus // more entries, and we exit the loop. 83*1fffad3fSStephan Aßmus 84*1fffad3fSStephan Aßmus if (!_GetNextEntry(entry)) 85*1fffad3fSStephan Aßmus return false; 86*1fffad3fSStephan Aßmus 87*1fffad3fSStephan Aßmus // If the entry is a subdir, then add it to the 88*1fffad3fSStephan Aßmus // list of directories and continue the loop. 89*1fffad3fSStephan Aßmus // If the entry is a file and we can grep it 90*1fffad3fSStephan Aßmus // (i.e. it is a text file), then we're done 91*1fffad3fSStephan Aßmus // here. Otherwise, continue with the next entry. 92*1fffad3fSStephan Aßmus 93*1fffad3fSStephan Aßmus if (entry.GetStat(&fileStat) == B_OK) { 94*1fffad3fSStephan Aßmus if (S_ISDIR(fileStat.st_mode)) { 95*1fffad3fSStephan Aßmus // subdir 96*1fffad3fSStephan Aßmus _ExamineSubdir(entry); 97*1fffad3fSStephan Aßmus } else { 98*1fffad3fSStephan Aßmus // file or a (non-traversed) symbolic link 99*1fffad3fSStephan Aßmus if (_ExamineFile(entry, buffer)) 100*1fffad3fSStephan Aßmus return true; 101*1fffad3fSStephan Aßmus } 102*1fffad3fSStephan Aßmus } 103*1fffad3fSStephan Aßmus } 104*1fffad3fSStephan Aßmus } 105*1fffad3fSStephan Aßmus 106*1fffad3fSStephan Aßmus 107*1fffad3fSStephan Aßmus // #pragma mark - private 108*1fffad3fSStephan Aßmus 109*1fffad3fSStephan Aßmus 110*1fffad3fSStephan Aßmus bool 111*1fffad3fSStephan Aßmus FileIterator::_GetNextEntry(BEntry& entry) 112*1fffad3fSStephan Aßmus { 113*1fffad3fSStephan Aßmus if (fDirectories.CountItems() == 1) 114*1fffad3fSStephan Aßmus return _GetTopEntry(entry); 115*1fffad3fSStephan Aßmus else 116*1fffad3fSStephan Aßmus return _GetSubEntry(entry); 117*1fffad3fSStephan Aßmus } 118*1fffad3fSStephan Aßmus 119*1fffad3fSStephan Aßmus 120*1fffad3fSStephan Aßmus bool 121*1fffad3fSStephan Aßmus FileIterator::_GetTopEntry(BEntry& entry) 122*1fffad3fSStephan Aßmus { 123*1fffad3fSStephan Aßmus // If the user selected one or more files, we must look 124*1fffad3fSStephan Aßmus // at the "refs" inside the message that was passed into 125*1fffad3fSStephan Aßmus // our add-on's process_refs(). If the user didn't select 126*1fffad3fSStephan Aßmus // any files, we will simply read all the entries from the 127*1fffad3fSStephan Aßmus // current working directory. 128*1fffad3fSStephan Aßmus 129*1fffad3fSStephan Aßmus entry_ref fileRef; 130*1fffad3fSStephan Aßmus 131*1fffad3fSStephan Aßmus if (fModel->fSelectedFiles.FindRef("refs", fCurrentRef, &fileRef) == B_OK) { 132*1fffad3fSStephan Aßmus entry.SetTo(&fileRef, fModel->fRecurseLinks); 133*1fffad3fSStephan Aßmus ++fCurrentRef; 134*1fffad3fSStephan Aßmus return true; 135*1fffad3fSStephan Aßmus } else if (fCurrentRef > 0) { 136*1fffad3fSStephan Aßmus // when we get here, we have processed 137*1fffad3fSStephan Aßmus // all the refs from the message 138*1fffad3fSStephan Aßmus return false; 139*1fffad3fSStephan Aßmus } else if (fCurrentDir != NULL) { 140*1fffad3fSStephan Aßmus // examine the whole directory 141*1fffad3fSStephan Aßmus return fCurrentDir->GetNextEntry(&entry, 142*1fffad3fSStephan Aßmus fModel->fRecurseLinks) == B_OK; 143*1fffad3fSStephan Aßmus } 144*1fffad3fSStephan Aßmus 145*1fffad3fSStephan Aßmus return false; 146*1fffad3fSStephan Aßmus } 147*1fffad3fSStephan Aßmus 148*1fffad3fSStephan Aßmus 149*1fffad3fSStephan Aßmus bool 150*1fffad3fSStephan Aßmus FileIterator::_GetSubEntry(BEntry& entry) 151*1fffad3fSStephan Aßmus { 152*1fffad3fSStephan Aßmus if (!fCurrentDir) 153*1fffad3fSStephan Aßmus return false; 154*1fffad3fSStephan Aßmus 155*1fffad3fSStephan Aßmus if (fCurrentDir->GetNextEntry(&entry, fModel->fRecurseLinks) == B_OK) 156*1fffad3fSStephan Aßmus return true; 157*1fffad3fSStephan Aßmus 158*1fffad3fSStephan Aßmus // If we get here, there are no more entries in 159*1fffad3fSStephan Aßmus // this subdir, so return to the parent directory. 160*1fffad3fSStephan Aßmus 161*1fffad3fSStephan Aßmus fDirectories.RemoveItem(fCurrentDir); 162*1fffad3fSStephan Aßmus delete fCurrentDir; 163*1fffad3fSStephan Aßmus fCurrentDir = (BDirectory*)fDirectories.LastItem(); 164*1fffad3fSStephan Aßmus 165*1fffad3fSStephan Aßmus return _GetNextEntry(entry); 166*1fffad3fSStephan Aßmus } 167*1fffad3fSStephan Aßmus 168*1fffad3fSStephan Aßmus 169*1fffad3fSStephan Aßmus void 170*1fffad3fSStephan Aßmus FileIterator::_ExamineSubdir(BEntry& entry) 171*1fffad3fSStephan Aßmus { 172*1fffad3fSStephan Aßmus if (!fModel->fRecurseDirs) 173*1fffad3fSStephan Aßmus return; 174*1fffad3fSStephan Aßmus 175*1fffad3fSStephan Aßmus if (fModel->fSkipDotDirs) { 176*1fffad3fSStephan Aßmus char nameBuf[B_FILE_NAME_LENGTH]; 177*1fffad3fSStephan Aßmus if (entry.GetName(nameBuf) == B_OK) { 178*1fffad3fSStephan Aßmus if (*nameBuf == '.') 179*1fffad3fSStephan Aßmus return; 180*1fffad3fSStephan Aßmus } 181*1fffad3fSStephan Aßmus } 182*1fffad3fSStephan Aßmus 183*1fffad3fSStephan Aßmus BDirectory* dir = new (nothrow) BDirectory(&entry); 184*1fffad3fSStephan Aßmus if (dir == NULL || dir->InitCheck() != B_OK 185*1fffad3fSStephan Aßmus || !fDirectories.AddItem(dir)) { 186*1fffad3fSStephan Aßmus // clean up 187*1fffad3fSStephan Aßmus delete dir; 188*1fffad3fSStephan Aßmus return; 189*1fffad3fSStephan Aßmus } 190*1fffad3fSStephan Aßmus 191*1fffad3fSStephan Aßmus fCurrentDir = dir; 192*1fffad3fSStephan Aßmus } 193*1fffad3fSStephan Aßmus 194*1fffad3fSStephan Aßmus 195*1fffad3fSStephan Aßmus bool 196*1fffad3fSStephan Aßmus FileIterator::_ExamineFile(BEntry& entry, char* buffer) 197*1fffad3fSStephan Aßmus { 198*1fffad3fSStephan Aßmus BPath path; 199*1fffad3fSStephan Aßmus if (entry.GetPath(&path) != B_OK) 200*1fffad3fSStephan Aßmus return false; 201*1fffad3fSStephan Aßmus 202*1fffad3fSStephan Aßmus strcpy(buffer, path.Path()); 203*1fffad3fSStephan Aßmus 204*1fffad3fSStephan Aßmus if (!fModel->fTextOnly) 205*1fffad3fSStephan Aßmus return true; 206*1fffad3fSStephan Aßmus 207*1fffad3fSStephan Aßmus BNode node(&entry); 208*1fffad3fSStephan Aßmus BNodeInfo nodeInfo(&node); 209*1fffad3fSStephan Aßmus char mimeTypeString[B_MIME_TYPE_LENGTH]; 210*1fffad3fSStephan Aßmus 211*1fffad3fSStephan Aßmus if (nodeInfo.GetType(mimeTypeString) == B_OK) { 212*1fffad3fSStephan Aßmus BMimeType mimeType(mimeTypeString); 213*1fffad3fSStephan Aßmus BMimeType superType; 214*1fffad3fSStephan Aßmus 215*1fffad3fSStephan Aßmus if (mimeType.GetSupertype(&superType) == B_OK) { 216*1fffad3fSStephan Aßmus if (strcmp("text", superType.Type()) == 0 217*1fffad3fSStephan Aßmus || strcmp("message", superType.Type()) == 0) { 218*1fffad3fSStephan Aßmus return true; 219*1fffad3fSStephan Aßmus } 220*1fffad3fSStephan Aßmus } 221*1fffad3fSStephan Aßmus } 222*1fffad3fSStephan Aßmus 223*1fffad3fSStephan Aßmus return false; 224*1fffad3fSStephan Aßmus } 225*1fffad3fSStephan Aßmus 226