Refactored a new class FileIterator from Grepper that will make adding
node monitoring easier. Also, FileIterator will be split to make the code cleaner with regards to folder or selection mode. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26752 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Stephan Aßmus <[email protected]>
|
||||||
|
* Copyright (c) 1998-2007 Matthijs Hollemans
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FileIterator.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <NodeInfo.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
|
#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 FileIterator object.
|
||||||
|
|
||||||
|
|
||||||
|
FileIterator::FileIterator(Model* model)
|
||||||
|
: fDirectories(10),
|
||||||
|
fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)),
|
||||||
|
fCurrentRef(0),
|
||||||
|
fModel(model)
|
||||||
|
{
|
||||||
|
if (!fCurrentDir || !fDirectories.AddItem(fCurrentDir)) {
|
||||||
|
// init error
|
||||||
|
delete fCurrentDir;
|
||||||
|
fCurrentDir = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileIterator::~FileIterator()
|
||||||
|
{
|
||||||
|
for (int32 i = fDirectories.CountItems() - 1; i >= 0; i--)
|
||||||
|
delete (BDirectory*)fDirectories.ItemAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::IsValid() const
|
||||||
|
{
|
||||||
|
return fCurrentDir != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::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))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::_GetNextEntry(BEntry& entry)
|
||||||
|
{
|
||||||
|
if (fDirectories.CountItems() == 1)
|
||||||
|
return _GetTopEntry(entry);
|
||||||
|
else
|
||||||
|
return _GetSubEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::_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 (fModel->fSelectedFiles.FindRef("refs", fCurrentRef, &fileRef) == B_OK) {
|
||||||
|
entry.SetTo(&fileRef, fModel->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,
|
||||||
|
fModel->fRecurseLinks) == B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::_GetSubEntry(BEntry& entry)
|
||||||
|
{
|
||||||
|
if (!fCurrentDir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fCurrentDir->GetNextEntry(&entry, fModel->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
|
||||||
|
FileIterator::_ExamineSubdir(BEntry& entry)
|
||||||
|
{
|
||||||
|
if (!fModel->fRecurseDirs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fModel->fSkipDotDirs) {
|
||||||
|
char nameBuf[B_FILE_NAME_LENGTH];
|
||||||
|
if (entry.GetName(nameBuf) == B_OK) {
|
||||||
|
if (*nameBuf == '.')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BDirectory* dir = new (nothrow) BDirectory(&entry);
|
||||||
|
if (dir == NULL || dir->InitCheck() != B_OK
|
||||||
|
|| !fDirectories.AddItem(dir)) {
|
||||||
|
// clean up
|
||||||
|
delete dir;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentDir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FileIterator::_ExamineFile(BEntry& entry, char* buffer)
|
||||||
|
{
|
||||||
|
BPath path;
|
||||||
|
if (entry.GetPath(&path) != B_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
strcpy(buffer, path.Path());
|
||||||
|
|
||||||
|
if (!fModel->fTextOnly)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
BNode node(&entry);
|
||||||
|
BNodeInfo nodeInfo(&node);
|
||||||
|
char mimeTypeString[B_MIME_TYPE_LENGTH];
|
||||||
|
|
||||||
|
if (nodeInfo.GetType(mimeTypeString) == B_OK) {
|
||||||
|
BMimeType mimeType(mimeTypeString);
|
||||||
|
BMimeType superType;
|
||||||
|
|
||||||
|
if (mimeType.GetSupertype(&superType) == B_OK) {
|
||||||
|
if (strcmp("text", superType.Type()) == 0
|
||||||
|
|| strcmp("message", superType.Type()) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Stephan Aßmus <[email protected]>
|
||||||
|
* Copyright (c) 1998-2007 Matthijs Hollemans
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef FILE_ITERATOR_H
|
||||||
|
#define FILE_ITERATOR_H
|
||||||
|
|
||||||
|
#include <List.h>
|
||||||
|
|
||||||
|
class BEntry;
|
||||||
|
class BDirectory;
|
||||||
|
class Model;
|
||||||
|
|
||||||
|
// TODO: split into Folder and MessageFileIterator (_GetTopEntry)
|
||||||
|
|
||||||
|
// Provides an interface to retrieve the next file that should be grepped
|
||||||
|
// for the search string.
|
||||||
|
class FileIterator {
|
||||||
|
public:
|
||||||
|
FileIterator(Model* model);
|
||||||
|
virtual ~FileIterator();
|
||||||
|
|
||||||
|
virtual bool IsValid() const;
|
||||||
|
|
||||||
|
// Returns the full path name of the next file.
|
||||||
|
virtual bool GetNextName(char* buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Looks for the next entry.
|
||||||
|
bool _GetNextEntry(BEntry& entry);
|
||||||
|
|
||||||
|
// Looks for the next entry in the top-level dir.
|
||||||
|
bool _GetTopEntry(BEntry& entry);
|
||||||
|
|
||||||
|
// Looks for the next entry in a subdir.
|
||||||
|
bool _GetSubEntry(BEntry& entry);
|
||||||
|
|
||||||
|
// Determines whether we can add a subdir.
|
||||||
|
void _ExamineSubdir(BEntry& entry);
|
||||||
|
|
||||||
|
// Determines whether we can grep a file.
|
||||||
|
bool _ExamineFile(BEntry& entry, char* buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Contains pointers to BDirectory objects.
|
||||||
|
BList fDirectories;
|
||||||
|
|
||||||
|
// The directory we are currently looking at.
|
||||||
|
BDirectory* fCurrentDir;
|
||||||
|
|
||||||
|
// The ref number we are currently looking at.
|
||||||
|
int32 fCurrentRef;
|
||||||
|
|
||||||
|
// The directory or files to grep on.
|
||||||
|
Model* fModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILE_ITERATOR_H
|
||||||
@@ -5,7 +5,15 @@
|
|||||||
#ifndef GLOBAL_DEFS_H
|
#ifndef GLOBAL_DEFS_H
|
||||||
#define GLOBAL_DEFS_H
|
#define GLOBAL_DEFS_H
|
||||||
|
|
||||||
|
|
||||||
#define APP_SIGNATURE "application/x-vnd.mahlzeit.trackergrep"
|
#define APP_SIGNATURE "application/x-vnd.mahlzeit.trackergrep"
|
||||||
#define APP_NAME "TextSearch"
|
#define APP_NAME "TextSearch"
|
||||||
|
|
||||||
|
#define PREFS_FILE "TextSearchSettings"
|
||||||
|
#define HISTORY_LIMIT 20
|
||||||
|
|
||||||
|
#define TRACKER_SIGNATURE "application/x-vnd.Be-TRAK"
|
||||||
|
#define PE_SIGNATURE "application/x-vnd.beunited.pe"
|
||||||
|
|
||||||
|
|
||||||
#endif // GLOBAL_DEFS_H
|
#endif // GLOBAL_DEFS_H
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <UTF8.h>
|
#include <UTF8.h>
|
||||||
|
|
||||||
|
#include "FileIterator.h"
|
||||||
#include "GlobalDefs.h"
|
#include "GlobalDefs.h"
|
||||||
#include "Grepper.h"
|
#include "Grepper.h"
|
||||||
#include "Translation.h"
|
#include "Translation.h"
|
||||||
@@ -112,10 +113,7 @@ GrepWindow::GrepWindow(BMessage* message)
|
|||||||
|
|
||||||
GrepWindow::~GrepWindow()
|
GrepWindow::~GrepWindow()
|
||||||
{
|
{
|
||||||
if (fModel->fState == STATE_SEARCH) {
|
delete fGrepper;
|
||||||
fGrepper->Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete fModel;
|
delete fModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,8 +706,21 @@ GrepWindow::_OnStartCancel()
|
|||||||
|
|
||||||
fOldPattern = fSearchText->Text();
|
fOldPattern = fSearchText->Text();
|
||||||
|
|
||||||
fGrepper = new Grepper(fOldPattern.String(), fModel);
|
FileIterator* iterator = new (nothrow) FileIterator(fModel);
|
||||||
|
fGrepper = new (nothrow) Grepper(fOldPattern.String(), fModel,
|
||||||
|
iterator);
|
||||||
|
if (fGrepper != NULL && fGrepper->IsValid())
|
||||||
fGrepper->Start();
|
fGrepper->Start();
|
||||||
|
else {
|
||||||
|
// roll back in case of problems
|
||||||
|
if (fGrepper == NULL)
|
||||||
|
delete iterator;
|
||||||
|
delete fGrepper;
|
||||||
|
fGrepper = NULL;
|
||||||
|
fModel->fState = STATE_CANCEL;
|
||||||
|
// TODO: better notification to user
|
||||||
|
fprintf(stderr, "Out of memory.\n");
|
||||||
|
}
|
||||||
} else if (fModel->fState == STATE_SEARCH) {
|
} else if (fModel->fState == STATE_SEARCH) {
|
||||||
fModel->fState = STATE_CANCEL;
|
fModel->fState = STATE_CANCEL;
|
||||||
fGrepper->Cancel();
|
fGrepper->Cancel();
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <UTF8.h>
|
#include <UTF8.h>
|
||||||
|
|
||||||
|
#include "FileIterator.h"
|
||||||
|
|
||||||
using std::nothrow;
|
using std::nothrow;
|
||||||
|
|
||||||
// TODO: stippi: Check if this is a the best place to maintain a global
|
// TODO: stippi: Check if this is a the best place to maintain a global
|
||||||
@@ -88,24 +90,13 @@ strdup_from_utf8(uint32 encode, const char* src, int32 length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Grepper::Grepper(const char* pattern, Model* model)
|
Grepper::Grepper(const char* pattern, Model* model, FileIterator* iterator)
|
||||||
: fDirectories(new (nothrow) BList(10)),
|
: fPattern(NULL),
|
||||||
fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)),
|
|
||||||
fCurrentRef(0),
|
|
||||||
fPattern(NULL),
|
|
||||||
fModel(model),
|
fModel(model),
|
||||||
|
fIterator(iterator),
|
||||||
fThreadId(-1),
|
fThreadId(-1),
|
||||||
fMustQuit(false)
|
fMustQuit(false)
|
||||||
{
|
{
|
||||||
if (!fCurrentDir || !fDirectories || !fDirectories->AddItem(fCurrentDir)) {
|
|
||||||
// init error
|
|
||||||
delete fCurrentDir;
|
|
||||||
fCurrentDir = NULL;
|
|
||||||
delete fDirectories;
|
|
||||||
fDirectories = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fModel->fEncoding) {
|
if (fModel->fEncoding) {
|
||||||
char *src = strdup_from_utf8(fModel->fEncoding, pattern,
|
char *src = strdup_from_utf8(fModel->fEncoding, pattern,
|
||||||
strlen(pattern));
|
strlen(pattern));
|
||||||
@@ -119,26 +110,17 @@ Grepper::Grepper(const char* pattern, Model* model)
|
|||||||
Grepper::~Grepper()
|
Grepper::~Grepper()
|
||||||
{
|
{
|
||||||
Cancel();
|
Cancel();
|
||||||
|
|
||||||
free(fPattern);
|
free(fPattern);
|
||||||
|
delete fIterator;
|
||||||
// If the thread terminated normally, then there is only
|
|
||||||
// one object in the list: the initial directory. But if
|
|
||||||
// the user aborted the search, there may be more.
|
|
||||||
|
|
||||||
if (fDirectories) {
|
|
||||||
for (int32 i = fDirectories->CountItems() - 1; i >= 0; i--)
|
|
||||||
delete static_cast<BDirectory*>(fDirectories->ItemAt(i));
|
|
||||||
|
|
||||||
delete fDirectories;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Grepper::IsValid() const
|
Grepper::IsValid() const
|
||||||
{
|
{
|
||||||
return fPattern != NULL && fDirectories != NULL && fCurrentDir != NULL;
|
if (fIterator == NULL || !fIterator->IsValid())
|
||||||
|
return false;
|
||||||
|
return fPattern != NULL && fModel != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -192,7 +174,7 @@ Grepper::_GrepperThread()
|
|||||||
sprintf(fileName, "/boot/var/tmp/SearchText%ld", fThreadId);
|
sprintf(fileName, "/boot/var/tmp/SearchText%ld", fThreadId);
|
||||||
tempFile.SetTo(fileName);
|
tempFile.SetTo(fileName);
|
||||||
|
|
||||||
while (!fMustQuit && _GetNextName(fileName)) {
|
while (!fMustQuit && fIterator->GetNextName(fileName)) {
|
||||||
message.MakeEmpty();
|
message.MakeEmpty();
|
||||||
message.what = MSG_REPORT_FILE_NAME;
|
message.what = MSG_REPORT_FILE_NAME;
|
||||||
message.AddString("filename", fileName);
|
message.AddString("filename", fileName);
|
||||||
@@ -344,153 +326,3 @@ Grepper::_EscapeSpecialChars(char* buffer, ssize_t bufferSize)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Grepper::_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))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Grepper::_GetNextEntry(BEntry& entry)
|
|
||||||
{
|
|
||||||
if (fDirectories->CountItems() == 1)
|
|
||||||
return _GetTopEntry(entry);
|
|
||||||
else
|
|
||||||
return _GetSubEntry(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Grepper::_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 (fModel->fSelectedFiles.FindRef("refs",
|
|
||||||
fCurrentRef, &fileRef) == B_OK) {
|
|
||||||
entry.SetTo(&fileRef, fModel->fRecurseLinks);
|
|
||||||
++fCurrentRef;
|
|
||||||
return true;
|
|
||||||
} else if (fCurrentRef > 0) {
|
|
||||||
// when we get here, we have processed
|
|
||||||
// all the refs from the message
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// examine the whole directory
|
|
||||||
return fCurrentDir->GetNextEntry(&entry,
|
|
||||||
fModel->fRecurseLinks) == B_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Grepper::_GetSubEntry(BEntry& entry)
|
|
||||||
{
|
|
||||||
if (!fCurrentDir)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (fCurrentDir->GetNextEntry(&entry, fModel->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
|
|
||||||
Grepper::_ExamineSubdir(BEntry& entry)
|
|
||||||
{
|
|
||||||
if (!fModel->fRecurseDirs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (fModel->fSkipDotDirs) {
|
|
||||||
char nameBuf[B_FILE_NAME_LENGTH];
|
|
||||||
if (entry.GetName(nameBuf) == B_OK) {
|
|
||||||
if (*nameBuf == '.')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BDirectory* dir = new (nothrow) BDirectory(&entry);
|
|
||||||
if (dir == NULL || dir->InitCheck() != B_OK
|
|
||||||
|| !fDirectories->AddItem(dir)) {
|
|
||||||
// clean up
|
|
||||||
delete dir;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fCurrentDir = dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Grepper::_ExamineFile(BEntry& entry, char* buffer)
|
|
||||||
{
|
|
||||||
BPath path;
|
|
||||||
if (entry.GetPath(&path) != B_OK)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
strcpy(buffer, path.Path());
|
|
||||||
|
|
||||||
if (!fModel->fTextOnly)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
BNode node(&entry);
|
|
||||||
BNodeInfo nodeInfo(&node);
|
|
||||||
char mimeTypeString[B_MIME_TYPE_LENGTH];
|
|
||||||
|
|
||||||
if (nodeInfo.GetType(mimeTypeString) == B_OK) {
|
|
||||||
BMimeType mimeType(mimeTypeString);
|
|
||||||
BMimeType superType;
|
|
||||||
|
|
||||||
if (mimeType.GetSupertype(&superType) == B_OK) {
|
|
||||||
if (strcmp("text", superType.Type()) == 0
|
|
||||||
|| strcmp("message", superType.Type()) == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,13 @@
|
|||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
|
||||||
|
class FileIterator;
|
||||||
|
|
||||||
// Executes "grep" in a background thread.
|
// Executes "grep" in a background thread.
|
||||||
class Grepper {
|
class Grepper {
|
||||||
public:
|
public:
|
||||||
Grepper(const char* pattern, Model* model);
|
Grepper(const char* pattern, Model* model,
|
||||||
|
FileIterator* iterator);
|
||||||
virtual ~Grepper();
|
virtual ~Grepper();
|
||||||
|
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
@@ -49,41 +52,16 @@ private:
|
|||||||
// to prevent the shell from misinterpreting them.
|
// to prevent the shell from misinterpreting them.
|
||||||
bool _EscapeSpecialChars(char* buffer,
|
bool _EscapeSpecialChars(char* buffer,
|
||||||
ssize_t bufferSize);
|
ssize_t bufferSize);
|
||||||
|
|
||||||
// Returns the full path name of the next file.
|
|
||||||
bool _GetNextName(char* buffer);
|
|
||||||
|
|
||||||
// Looks for the next entry.
|
|
||||||
bool _GetNextEntry(BEntry& entry);
|
|
||||||
|
|
||||||
// Looks for the next entry in the top-level dir.
|
|
||||||
bool _GetTopEntry(BEntry& entry);
|
|
||||||
|
|
||||||
// Looks for the next entry in a subdir.
|
|
||||||
bool _GetSubEntry(BEntry& entry);
|
|
||||||
|
|
||||||
// Determines whether we can add a subdir.
|
|
||||||
void _ExamineSubdir(BEntry& entry);
|
|
||||||
|
|
||||||
// Determines whether we can grep a file.
|
|
||||||
bool _ExamineFile(BEntry& entry, char* buffer);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Contains pointers to BDirectory objects.
|
|
||||||
BList* fDirectories;
|
|
||||||
|
|
||||||
// The directory we are currently looking at.
|
|
||||||
BDirectory* fCurrentDir;
|
|
||||||
|
|
||||||
// The ref number we are currently looking at.
|
|
||||||
int32 fCurrentRef;
|
|
||||||
|
|
||||||
// The (escaped) search pattern.
|
// The (escaped) search pattern.
|
||||||
char* fPattern;
|
char* fPattern;
|
||||||
|
|
||||||
// The directory or files to grep on.
|
// The directory or files to grep on.
|
||||||
Model* fModel;
|
Model* fModel;
|
||||||
|
|
||||||
|
// The supplier of files to grep
|
||||||
|
FileIterator* fIterator;
|
||||||
|
|
||||||
// Our thread's ID.
|
// Our thread's ID.
|
||||||
thread_id fThreadId;
|
thread_id fThreadId;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src apps text_search ;
|
|||||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
Application TextSearch :
|
Application TextSearch :
|
||||||
|
FileIterator.cpp
|
||||||
GrepApp.cpp
|
GrepApp.cpp
|
||||||
GrepListView.cpp
|
GrepListView.cpp
|
||||||
Grepper.cpp
|
Grepper.cpp
|
||||||
|
|||||||
@@ -32,12 +32,7 @@
|
|||||||
#include <Rect.h>
|
#include <Rect.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "GlobalDefs.h"
|
||||||
#define PREFS_FILE "TrackerGrepSettings"
|
|
||||||
#define HISTORY_LIMIT 20
|
|
||||||
|
|
||||||
#define TRACKER_SIGNATURE "application/x-vnd.Be-TRAK"
|
|
||||||
#define PE_SIGNATURE "application/x-vnd.beunited.pe"
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -89,6 +84,7 @@ public:
|
|||||||
void AddToHistory(const char* text);
|
void AddToHistory(const char* text);
|
||||||
void FillHistoryMenu(BMenu* menu);
|
void FillHistoryMenu(BMenu* menu);
|
||||||
|
|
||||||
|
public:
|
||||||
// The directory we were invoked from.
|
// The directory we were invoked from.
|
||||||
entry_ref fDirectory;
|
entry_ref fDirectory;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user