* Imported Tracker Grep 5.1 source code
* Renamed it to TextSearch * Cleaned up the code to match our coding style (already was almost compliant and the code is very clean and well designed, a pleasure to work with!) * Fixed memory leaks and potential memory leaks in error codepaths * Checked the success of most allocations (GrepWindow is missing) and implemented error code paths * Simplified the code in a few places * Fixed bugs in code that iterated over the selected list items and assumed it found a top level item already while it may not have git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26737 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Binary file not shown.
@@ -3,4 +3,5 @@ SubDir HAIKU_TOP src add-ons tracker ;
|
||||
SubInclude HAIKU_TOP src add-ons tracker zipomatic ;
|
||||
SubInclude HAIKU_TOP src add-ons tracker filetype ;
|
||||
SubInclude HAIKU_TOP src add-ons tracker mark_as ;
|
||||
SubInclude HAIKU_TOP src add-ons tracker text_search ;
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Stephan Aßmus <[email protected]>
|
||||
* All rights reserved. Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef GLOBAL_DEFS_H
|
||||
#define GLOBAL_DEFS_H
|
||||
|
||||
#define APP_SIGNATURE "application/x-vnd.mahlzeit.trackergrep"
|
||||
#define APP_NAME "TextSearch"
|
||||
|
||||
#endif // GLOBAL_DEFS_H
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 "GrepApp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Entry.h>
|
||||
|
||||
#include "GlobalDefs.h"
|
||||
#include "GrepWindow.h"
|
||||
#include "Model.h"
|
||||
|
||||
|
||||
GrepApp::GrepApp()
|
||||
: BApplication(APP_SIGNATURE),
|
||||
fGotArgvOnStartup(false),
|
||||
fGotRefsOnStartup(false),
|
||||
fQuitter(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
GrepApp::~GrepApp()
|
||||
{
|
||||
delete fQuitter;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::ArgvReceived(int32 argc, char** argv)
|
||||
{
|
||||
fGotArgvOnStartup = true;
|
||||
|
||||
BMessage message(B_REFS_RECEIVED);
|
||||
int32 refCount = 0;
|
||||
|
||||
for (int32 i = 1; i < argc; i++) {
|
||||
BEntry entry(argv[i]);
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
|
||||
if (entry.Exists()) {
|
||||
message.AddRef("refs", &ref);
|
||||
refCount += 1;
|
||||
} else
|
||||
printf("%s: File not found: %s\n", argv[0], argv[i]);
|
||||
}
|
||||
|
||||
if (refCount > 0)
|
||||
RefsReceived(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::RefsReceived(BMessage* message)
|
||||
{
|
||||
if (IsLaunching())
|
||||
fGotRefsOnStartup = true;
|
||||
|
||||
new GrepWindow(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::ReadyToRun()
|
||||
{
|
||||
if (!fGotArgvOnStartup && !fGotRefsOnStartup)
|
||||
_NewUnfocusedGrepWindow();
|
||||
|
||||
// TODO: stippi: I don't understand what this is supposed to do:
|
||||
if (fGotArgvOnStartup && !fGotRefsOnStartup)
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case B_SILENT_RELAUNCH:
|
||||
_NewUnfocusedGrepWindow();
|
||||
break;
|
||||
|
||||
case MSG_TRY_QUIT:
|
||||
_TryQuit();
|
||||
break;
|
||||
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::_TryQuit()
|
||||
{
|
||||
if (CountWindows() == 0)
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
|
||||
if (CountWindows() == 1 && fQuitter == NULL) {
|
||||
fQuitter = new BMessageRunner(be_app_messenger,
|
||||
new BMessage(MSG_TRY_QUIT), 200000, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepApp::_NewUnfocusedGrepWindow()
|
||||
{
|
||||
BMessage emptyMessage;
|
||||
new GrepWindow(&emptyMessage);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 <Application.h>
|
||||
#include <MessageRunner.h>
|
||||
|
||||
#ifndef GREP_APP_H
|
||||
#define GREP_APP_H
|
||||
|
||||
class GrepApp : public BApplication {
|
||||
public:
|
||||
GrepApp();
|
||||
virtual ~GrepApp();
|
||||
|
||||
virtual void ArgvReceived(int32 argc, char** argv);
|
||||
virtual void RefsReceived(BMessage* message);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void ReadyToRun();
|
||||
|
||||
private:
|
||||
void _TryQuit();
|
||||
void _NewUnfocusedGrepWindow();
|
||||
|
||||
bool fGotArgvOnStartup;
|
||||
bool fGotRefsOnStartup;
|
||||
|
||||
BMessageRunner* fQuitter;
|
||||
};
|
||||
|
||||
#endif // GREP_APP_H
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 "GrepListView.h"
|
||||
|
||||
#include <Path.h>
|
||||
|
||||
ResultItem::ResultItem(const entry_ref& ref)
|
||||
: BStringItem("", 0, false),
|
||||
ref(ref)
|
||||
{
|
||||
BEntry entry(&ref);
|
||||
BPath path(&entry);
|
||||
SetText(path.Path());
|
||||
}
|
||||
|
||||
|
||||
GrepListView::GrepListView()
|
||||
: BOutlineListView(BRect(0, 0, 40, 80), "SearchResults",
|
||||
B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES,
|
||||
B_WILL_DRAW | B_NAVIGABLE)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 GREP_LIST_VIEW_H
|
||||
#define GREP_LIST_VIEW_H
|
||||
|
||||
#include <Entry.h>
|
||||
#include <OutlineListView.h>
|
||||
#include <StringItem.h>
|
||||
|
||||
|
||||
class ResultItem : public BStringItem {
|
||||
public:
|
||||
ResultItem(const entry_ref& ref);
|
||||
|
||||
entry_ref ref;
|
||||
};
|
||||
|
||||
|
||||
class GrepListView : public BOutlineListView {
|
||||
public:
|
||||
GrepListView();
|
||||
};
|
||||
|
||||
#endif // GREP_LIST_VIEW_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 GREP_WINDOW_H
|
||||
#define GREP_WINDOW_H
|
||||
|
||||
#include <InterfaceKit.h>
|
||||
#include <FilePanel.h>
|
||||
|
||||
#include "Model.h"
|
||||
#include "GrepListView.h"
|
||||
|
||||
class Grepper;
|
||||
|
||||
class GrepWindow : public BWindow {
|
||||
public:
|
||||
GrepWindow(BMessage* message);
|
||||
virtual ~GrepWindow();
|
||||
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void FrameMoved(BPoint origin);
|
||||
virtual void MenusBeginning();
|
||||
virtual void MenusEnded();
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void Quit();
|
||||
|
||||
private:
|
||||
void _InitRefsReceived(entry_ref* directory,
|
||||
BMessage* message);
|
||||
void _SetWindowTitle();
|
||||
void _CreateMenus();
|
||||
void _CreateViews();
|
||||
void _LayoutViews();
|
||||
void _TileIfMultipleWindows();
|
||||
|
||||
void _LoadPrefs();
|
||||
void _SavePrefs();
|
||||
|
||||
void _OnStartCancel();
|
||||
void _OnSearchFinished();
|
||||
void _OnReportFileName(BMessage* message);
|
||||
void _OnReportResult(BMessage* message);
|
||||
void _OnReportError(BMessage* message);
|
||||
void _OnRecurseLinks();
|
||||
void _OnRecurseDirs();
|
||||
void _OnSkipDotDirs();
|
||||
void _OnEscapeText();
|
||||
void _OnCaseSensitive();
|
||||
void _OnTextOnly();
|
||||
void _OnInvokePe();
|
||||
void _OnCheckboxShowLines();
|
||||
void _OnMenuShowLines();
|
||||
void _OnInvokeItem();
|
||||
void _OnSearchText();
|
||||
void _OnHistoryItem(BMessage* message);
|
||||
void _OnTrimSelection();
|
||||
void _OnCopyText();
|
||||
void _OnSelectInTracker();
|
||||
void _OnQuitNow();
|
||||
void _OnAboutRequested();
|
||||
void _OnFileDrop(BMessage* message);
|
||||
void _OnRefsReceived(BMessage* message);
|
||||
void _OnOpenPanel();
|
||||
void _OnOpenPanelCancel();
|
||||
void _OnSelectAll(BMessage* message);
|
||||
void _OnNewWindow();
|
||||
|
||||
bool _OpenInPe(const entry_ref& ref, int32 lineNum);
|
||||
void _RemoveFolderListDuplicates(BList* folderList);
|
||||
status_t _OpenFoldersInTracker(BList* folderList);
|
||||
bool _AreAllFoldersOpenInTracker(BList* folderList);
|
||||
status_t _SelectFilesInTracker(BList* folderList,
|
||||
BMessage* refsMessage);
|
||||
|
||||
private:
|
||||
BTextControl* fSearchText;
|
||||
GrepListView* fSearchResults;
|
||||
|
||||
BMenuBar* fMenuBar;
|
||||
BMenu* fFileMenu;
|
||||
BMenuItem* fNew;
|
||||
BMenuItem* fOpen;
|
||||
BMenuItem* fClose;
|
||||
BMenuItem* fAbout;
|
||||
BMenuItem* fQuit;
|
||||
BMenu* fActionMenu;
|
||||
BMenuItem* fSelectAll;
|
||||
BMenuItem* fSearch;
|
||||
BMenuItem* fTrimSelection;
|
||||
BMenuItem* fCopyText;
|
||||
BMenuItem* fSelectInTracker;
|
||||
BMenuItem* fOpenSelection;
|
||||
BMenu* fPreferencesMenu;
|
||||
BMenuItem* fRecurseLinks;
|
||||
BMenuItem* fRecurseDirs;
|
||||
BMenuItem* fSkipDotDirs;
|
||||
BMenuItem* fCaseSensitive;
|
||||
BMenuItem* fEscapeText;
|
||||
BMenuItem* fTextOnly;
|
||||
BMenuItem* fInvokePe;
|
||||
BMenuItem* fShowLinesMenuitem;
|
||||
BMenu* fHistoryMenu;
|
||||
BMenu* fEncodingMenu;
|
||||
BMenuItem* fUTF8;
|
||||
BMenuItem* fShiftJIS;
|
||||
BMenuItem* fEUC;
|
||||
BMenuItem* fJIS;
|
||||
|
||||
BCheckBox* fShowLinesCheckbox;
|
||||
BButton* fButton;
|
||||
|
||||
Grepper* fGrepper;
|
||||
BString fOldPattern;
|
||||
|
||||
Model* fModel;
|
||||
|
||||
BFilePanel* fFilePanel;
|
||||
};
|
||||
|
||||
#endif // GREP_WINDOW_H
|
||||
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* 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 "Grepper.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <List.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <UTF8.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 Grepper object.
|
||||
|
||||
|
||||
char*
|
||||
strdup_to_utf8(uint32 encode, const char* src, int32 length)
|
||||
{
|
||||
int32 srcLen = length;
|
||||
int32 dstLen = 2 * srcLen;
|
||||
// TODO: stippi: Why the duplicate copy? Why not just return
|
||||
// dst (and allocate with malloc() instead of new)? Is 2 * srcLen
|
||||
// enough space? Check return value of convert_to_utf8 and keep
|
||||
// converting if it didn't fit?
|
||||
char* dst = new (nothrow) char[dstLen + 1];
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
int32 cookie = 0;
|
||||
convert_to_utf8(encode, src, &srcLen, dst, &dstLen, &cookie);
|
||||
dst[dstLen] = '\0';
|
||||
char* dup = strdup(dst);
|
||||
delete[] dst;
|
||||
if (srcLen != length) {
|
||||
fprintf(stderr, "strdup_to_utf8(%ld, %ld) dst allocate smalled(%ld)\n",
|
||||
encode, length, dstLen);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
strdup_from_utf8(uint32 encode, const char* src, int32 length)
|
||||
{
|
||||
int32 srcLen = length;
|
||||
int32 dstLen = srcLen;
|
||||
char* dst = new (nothrow) char[dstLen + 1];
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
int32 cookie = 0;
|
||||
convert_from_utf8(encode, src, &srcLen, dst, &dstLen, &cookie);
|
||||
// TODO: See above.
|
||||
dst[dstLen] = '\0';
|
||||
char* dup = strdup(dst);
|
||||
delete[] dst;
|
||||
if (srcLen != length) {
|
||||
fprintf(stderr, "strdup_from_utf8(%ld, %ld) dst allocate "
|
||||
"smalled(%ld)\n", encode, length, dstLen);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
|
||||
Grepper::Grepper(const char* pattern, Model* model)
|
||||
: fDirectories(new (nothrow) BList(10)),
|
||||
fCurrentDir(new (nothrow) BDirectory(&model->fDirectory)),
|
||||
fCurrentRef(0),
|
||||
fPattern(NULL),
|
||||
fModel(model),
|
||||
fThreadId(-1),
|
||||
fMustQuit(false)
|
||||
{
|
||||
if (!fCurrentDir || !fDirectories || !fDirectories->AddItem(fCurrentDir)) {
|
||||
// init error
|
||||
delete fCurrentDir;
|
||||
fCurrentDir = NULL;
|
||||
delete fDirectories;
|
||||
fDirectories = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fModel->fEncoding) {
|
||||
char *src = strdup_from_utf8(fModel->fEncoding, pattern,
|
||||
strlen(pattern));
|
||||
_SetPattern(src);
|
||||
free(src);
|
||||
} else
|
||||
_SetPattern(pattern);
|
||||
}
|
||||
|
||||
|
||||
Grepper::~Grepper()
|
||||
{
|
||||
Cancel();
|
||||
|
||||
free(fPattern);
|
||||
|
||||
// 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
|
||||
Grepper::IsValid() const
|
||||
{
|
||||
return fPattern != NULL && fDirectories != NULL && fCurrentDir != NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Grepper::Start()
|
||||
{
|
||||
Cancel();
|
||||
|
||||
fMustQuit = false;
|
||||
fThreadId = spawn_thread(
|
||||
_SpawnThread, "_GrepperThread", B_NORMAL_PRIORITY, this);
|
||||
|
||||
resume_thread(fThreadId);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Grepper::Cancel()
|
||||
{
|
||||
if (fThreadId < 0)
|
||||
return;
|
||||
|
||||
fMustQuit = true;
|
||||
int32 exitValue;
|
||||
wait_for_thread(fThreadId, &exitValue);
|
||||
fThreadId = -1;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - private
|
||||
|
||||
|
||||
int32
|
||||
Grepper::_SpawnThread(void* cookie)
|
||||
{
|
||||
Grepper* self = static_cast<Grepper*>(cookie);
|
||||
return self->_GrepperThread();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Grepper::_GrepperThread()
|
||||
{
|
||||
BMessage message;
|
||||
|
||||
char fileName[B_PATH_NAME_LENGTH];
|
||||
char tempString[B_PATH_NAME_LENGTH];
|
||||
char command[B_PATH_NAME_LENGTH + 32];
|
||||
|
||||
BPath tempFile;
|
||||
sprintf(fileName, "/boot/var/tmp/SearchText%ld", fThreadId);
|
||||
tempFile.SetTo(fileName);
|
||||
|
||||
while (!fMustQuit && _GetNextName(fileName)) {
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_FILE_NAME;
|
||||
message.AddString("filename", fileName);
|
||||
fModel->fTarget->PostMessage(&message);
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_RESULT;
|
||||
message.AddString("filename", fileName);
|
||||
|
||||
BEntry entry(fileName);
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
message.AddRef("ref", &ref);
|
||||
|
||||
if (!_EscapeSpecialChars(fileName, B_PATH_NAME_LENGTH)) {
|
||||
sprintf(tempString, "%s: Not enough room to escape the filename.",
|
||||
fileName);
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_ERROR;
|
||||
message.AddString("error", tempString);
|
||||
fModel->fTarget->PostMessage(&message);
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(command, "grep -hn %s %s \"%s\" > \"%s\"",
|
||||
fModel->fCaseSensitive ? "" : "-i", fPattern, fileName,
|
||||
tempFile.Path());
|
||||
|
||||
int res = system(command);
|
||||
|
||||
if (res == 0 || res == 1) {
|
||||
FILE *results = fopen(tempFile.Path(), "r");
|
||||
|
||||
if (results != NULL) {
|
||||
while (fgets(tempString, B_PATH_NAME_LENGTH, results) != 0) {
|
||||
if (fModel->fEncoding) {
|
||||
char *tempdup = strdup_to_utf8(fModel->fEncoding,
|
||||
tempString, strlen(tempString));
|
||||
message.AddString("text", tempdup);
|
||||
free(tempdup);
|
||||
} else
|
||||
message.AddString("text", tempString);
|
||||
}
|
||||
|
||||
if (message.HasString("text"))
|
||||
fModel->fTarget->PostMessage(&message);
|
||||
|
||||
fclose(results);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(tempString, "%s: There was a problem running grep.", fileName);
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_ERROR;
|
||||
message.AddString("error", tempString);
|
||||
fModel->fTarget->PostMessage(&message);
|
||||
}
|
||||
|
||||
// We wait with removing the temporary file until after the
|
||||
// entire search has finished, to prevent a lot of flickering
|
||||
// if the Tracker window for /boot/var/tmp/ might be open.
|
||||
|
||||
remove(tempFile.Path());
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_SEARCH_FINISHED;
|
||||
fModel->fTarget->PostMessage(&message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Grepper::_SetPattern(const char* src)
|
||||
{
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
if (!fModel->fEscapeText) {
|
||||
fPattern = strdup(src);
|
||||
return;
|
||||
}
|
||||
|
||||
// We will simply guess the size of the memory buffer
|
||||
// that we need. This should always be large enough.
|
||||
fPattern = (char*)malloc((strlen(src) + 1) * 3 * sizeof(char));
|
||||
if (fPattern == NULL)
|
||||
return;
|
||||
|
||||
const char* srcPtr = src;
|
||||
char* dstPtr = fPattern;
|
||||
|
||||
// Put double quotes around the pattern, so separate
|
||||
// words are considered to be part of a single string.
|
||||
*dstPtr++ = '"';
|
||||
|
||||
while (*srcPtr != '\0') {
|
||||
char c = *srcPtr++;
|
||||
|
||||
// Put a backslash in front of characters
|
||||
// that should be escaped.
|
||||
if ((c == '.') || (c == ',')
|
||||
|| (c == '[') || (c == ']')
|
||||
|| (c == '?') || (c == '*')
|
||||
|| (c == '+') || (c == '-')
|
||||
|| (c == ':') || (c == '^')
|
||||
|| (c == '\'') || (c == '"')) {
|
||||
*dstPtr++ = '\\';
|
||||
} else if ((c == '\\') || (c == '$')) {
|
||||
// Some characters need to be escaped
|
||||
// with *three* backslashes in a row.
|
||||
*dstPtr++ = '\\';
|
||||
*dstPtr++ = '\\';
|
||||
*dstPtr++ = '\\';
|
||||
}
|
||||
|
||||
// Note: we do not have to escape the
|
||||
// { } ( ) < > and | characters.
|
||||
|
||||
*dstPtr++ = c;
|
||||
}
|
||||
|
||||
*dstPtr++ = '"';
|
||||
*dstPtr = '\0';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Grepper::_EscapeSpecialChars(char* buffer, ssize_t bufferSize)
|
||||
{
|
||||
char* copy = strdup(buffer);
|
||||
char* start = buffer;
|
||||
uint32 len = strlen(copy);
|
||||
bool result = true;
|
||||
for (uint32 count = 0; count < len; ++count) {
|
||||
if (copy[count] == '"' || copy[count] == '$')
|
||||
*buffer++ = '\\';
|
||||
if (buffer - start == bufferSize - 1) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
*buffer++ = copy[count];
|
||||
}
|
||||
*buffer = '\0';
|
||||
free(copy);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 GREPPER_H
|
||||
#define GREPPER_H
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
// Executes "grep" in a background thread.
|
||||
class Grepper {
|
||||
public:
|
||||
Grepper(const char* pattern, Model* model);
|
||||
virtual ~Grepper();
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
void Start();
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
// Spawns the real grepper thread.
|
||||
static int32 _SpawnThread(void* cookie);
|
||||
|
||||
// The thread function that does the actual grepping.
|
||||
int32 _GrepperThread();
|
||||
|
||||
// Remembers, and possibly escapes, the search pattern.
|
||||
void _SetPattern(const char* source);
|
||||
|
||||
// Prepends all quotes, dollars and backslashes with at backslash
|
||||
// to prevent the shell from misinterpreting them.
|
||||
bool _EscapeSpecialChars(char* buffer,
|
||||
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:
|
||||
// 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.
|
||||
char* fPattern;
|
||||
|
||||
// The directory or files to grep on.
|
||||
Model* fModel;
|
||||
|
||||
// Our thread's ID.
|
||||
thread_id fThreadId;
|
||||
|
||||
// Whether our thread must quit.
|
||||
volatile bool fMustQuit;
|
||||
};
|
||||
|
||||
#endif // GREPPER_H
|
||||
@@ -0,0 +1,18 @@
|
||||
SubDir HAIKU_TOP src add-ons tracker text_search ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
# TODO: does not seem to work:
|
||||
AddResources FileType-F : FileType.rdef ;
|
||||
|
||||
Application TextSearch-G :
|
||||
GrepApp.cpp
|
||||
GrepListView.cpp
|
||||
Grepper.cpp
|
||||
GrepWindow.cpp
|
||||
Model.cpp
|
||||
TextSearch.cpp
|
||||
|
||||
: be tracker textencoding
|
||||
: TextSearch.rdef
|
||||
;
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* 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 "Model.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <List.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Path.h>
|
||||
|
||||
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
Model::Model()
|
||||
: fDirectory(),
|
||||
fSelectedFiles(0UL),
|
||||
|
||||
fRecurseDirs(true),
|
||||
fRecurseLinks(false),
|
||||
fSkipDotDirs(true),
|
||||
fCaseSensitive(false),
|
||||
fEscapeText(true),
|
||||
fTextOnly(true),
|
||||
fInvokePe(false),
|
||||
fShowContents(false),
|
||||
|
||||
fFrame(100, 100, 500, 400),
|
||||
|
||||
fTarget(NULL),
|
||||
fState(STATE_IDLE),
|
||||
|
||||
fFilePanelPath(""),
|
||||
|
||||
fEncoding(0)
|
||||
{
|
||||
BPath path;
|
||||
status_t status = find_directory(B_USER_DIRECTORY, &path);
|
||||
if (status == B_OK)
|
||||
fFilePanelPath = path.Path();
|
||||
else
|
||||
fFilePanelPath = "/boot/home";
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Model::LoadPrefs()
|
||||
{
|
||||
BFile file;
|
||||
status_t status = _OpenFile(&file, PREFS_FILE, B_READ_ONLY,
|
||||
B_USER_SETTINGS_DIRECTORY, NULL);
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = file.Lock();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
int32 value;
|
||||
|
||||
if (file.ReadAttr("RecurseDirs", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fRecurseDirs = (value != 0);
|
||||
|
||||
if (file.ReadAttr("RecurseLinks", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fRecurseLinks = (value != 0);
|
||||
|
||||
if (file.ReadAttr("SkipDotDirs", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fSkipDotDirs = (value != 0);
|
||||
|
||||
if (file.ReadAttr("CaseSensitive", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fCaseSensitive = (value != 0);
|
||||
|
||||
if (file.ReadAttr("EscapeText", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fEscapeText = (value != 0);
|
||||
|
||||
if (file.ReadAttr("TextOnly", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fTextOnly = (value != 0);
|
||||
|
||||
if (file.ReadAttr("InvokePe", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fInvokePe = (value != 0);
|
||||
|
||||
if (file.ReadAttr("ShowContents", B_INT32_TYPE, 0, &value,
|
||||
sizeof(int32)) > 0)
|
||||
fShowContents = (value != 0);
|
||||
|
||||
char buffer [B_PATH_NAME_LENGTH+1];
|
||||
int32 length = file.ReadAttr("FilePanelPath", B_STRING_TYPE, 0, &buffer,
|
||||
sizeof(buffer));
|
||||
if (length > 0) {
|
||||
buffer[length] = '\0';
|
||||
fFilePanelPath = buffer;
|
||||
}
|
||||
|
||||
file.ReadAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
|
||||
|
||||
if (file.ReadAttr("Encoding", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
|
||||
fEncoding = value;
|
||||
|
||||
file.Unlock();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Model::SavePrefs()
|
||||
{
|
||||
BFile file;
|
||||
status_t status = _OpenFile(&file, PREFS_FILE,
|
||||
B_CREATE_FILE | B_WRITE_ONLY, B_USER_SETTINGS_DIRECTORY, NULL);
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = file.Lock();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
int32 value = 2;
|
||||
file.WriteAttr("Version", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fRecurseDirs ? 1 : 0;
|
||||
file.WriteAttr("RecurseDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fRecurseLinks ? 1 : 0;
|
||||
file.WriteAttr("RecurseLinks", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fSkipDotDirs ? 1 : 0;
|
||||
file.WriteAttr("SkipDotDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fCaseSensitive ? 1 : 0;
|
||||
file.WriteAttr("CaseSensitive", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fEscapeText ? 1 : 0;
|
||||
file.WriteAttr("EscapeText", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fTextOnly ? 1 : 0;
|
||||
file.WriteAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fInvokePe ? 1 : 0;
|
||||
file.WriteAttr("InvokePe", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
value = fShowContents ? 1 : 0;
|
||||
file.WriteAttr("ShowContents", B_INT32_TYPE, 0, &value, sizeof(int32));
|
||||
|
||||
file.WriteAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
|
||||
|
||||
file.WriteAttr("FilePanelPath", B_STRING_TYPE, 0, fFilePanelPath.String(),
|
||||
fFilePanelPath.Length() + 1);
|
||||
|
||||
file.WriteAttr("Encoding", B_INT32_TYPE, 0, &fEncoding, sizeof(int32));
|
||||
|
||||
file.Sync();
|
||||
file.Unlock();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::AddToHistory(const char* text)
|
||||
{
|
||||
BList* items = _LoadHistory();
|
||||
if (items == NULL)
|
||||
return;
|
||||
|
||||
BString* string = new (nothrow) BString(text);
|
||||
if (string == NULL || !items->AddItem(string)) {
|
||||
delete string;
|
||||
return;
|
||||
}
|
||||
|
||||
int32 count = items->CountItems() - 1;
|
||||
// don't check last item, since that's the one we just added
|
||||
for (int32 t = 0; t < count; ++t) {
|
||||
// If the same text is already in the list,
|
||||
// then remove it first. Case-sensitive.
|
||||
BString* string = static_cast<BString*>(items->ItemAt(t));
|
||||
if (*string == text) {
|
||||
delete static_cast<BString*>(items->RemoveItem(t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (items->CountItems() == HISTORY_LIMIT)
|
||||
delete static_cast<BString*>(items->RemoveItem(0L));
|
||||
|
||||
_SaveHistory(items);
|
||||
_FreeHistory(items);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::FillHistoryMenu(BMenu* menu)
|
||||
{
|
||||
BList* items = _LoadHistory();
|
||||
if (items == NULL)
|
||||
return;
|
||||
|
||||
for (int32 t = items->CountItems() - 1; t >= 0; --t) {
|
||||
BString* item = static_cast<BString*>(items->ItemAt(t));
|
||||
BMessage* message = new BMessage(MSG_SELECT_HISTORY);
|
||||
message->AddString("text", item->String());
|
||||
menu->AddItem(new BMenuItem(item->String(), message));
|
||||
}
|
||||
|
||||
_FreeHistory(items);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - private
|
||||
|
||||
|
||||
BList*
|
||||
Model::_LoadHistory()
|
||||
{
|
||||
BList* items = new (nothrow) BList();
|
||||
if (items == NULL)
|
||||
return NULL;
|
||||
|
||||
BFile file;
|
||||
status_t status = _OpenFile(&file, PREFS_FILE, B_READ_ONLY,
|
||||
B_USER_SETTINGS_DIRECTORY, NULL);
|
||||
|
||||
if (status != B_OK)
|
||||
return items;
|
||||
|
||||
status = file.Lock();
|
||||
if (status != B_OK)
|
||||
return items;
|
||||
|
||||
BMessage message;
|
||||
status = message.Unflatten(&file);
|
||||
if (status != B_OK)
|
||||
return items;
|
||||
|
||||
file.Unlock();
|
||||
|
||||
BString string;
|
||||
for (int32 x = 0; message.FindString("string", x, &string) == B_OK; x++) {
|
||||
BString* copy = new (nothrow) BString(string);
|
||||
if (copy == NULL || !items->AddItem(copy)) {
|
||||
delete copy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Model::_SaveHistory(BList* items)
|
||||
{
|
||||
BFile file;
|
||||
status_t status = _OpenFile(&file, PREFS_FILE,
|
||||
B_CREATE_FILE | B_WRITE_ONLY,
|
||||
B_USER_SETTINGS_DIRECTORY, NULL);
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = file.Lock();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
BMessage message;
|
||||
for (int32 x = 0; ; x++) {
|
||||
BString* string = static_cast<BString*>(items->ItemAt(x));
|
||||
if (string == NULL)
|
||||
break;
|
||||
|
||||
if (message.AddString("string", string->String()) != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
status = message.Flatten(&file);
|
||||
file.SetSize(message.FlattenedSize());
|
||||
file.Sync();
|
||||
file.Unlock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Model::_FreeHistory(BList* items)
|
||||
{
|
||||
for (int32 t = items->CountItems() - 1; t >= 0; --t)
|
||||
delete static_cast<BString*>((items->RemoveItem(t)));
|
||||
|
||||
delete items;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Model::_OpenFile(BFile* file, const char* name, uint32 openMode = B_READ_ONLY,
|
||||
directory_which which = B_USER_SETTINGS_DIRECTORY, BVolume* volume = NULL)
|
||||
{
|
||||
if (file == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
BPath path;
|
||||
status_t status = find_directory(which, &path, true, volume);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = path.Append(PREFS_FILE);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = file->SetTo(path.Path(), openMode);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = file->InitCheck();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include <Entry.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <List.h>
|
||||
#include <Looper.h>
|
||||
#include <Menu.h>
|
||||
#include <Message.h>
|
||||
#include <Rect.h>
|
||||
#include <String.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 {
|
||||
MSG_START_CANCEL = 1000,
|
||||
MSG_RECURSE_LINKS,
|
||||
MSG_RECURSE_DIRS,
|
||||
MSG_SKIP_DOT_DIRS,
|
||||
MSG_CASE_SENSITIVE,
|
||||
MSG_ESCAPE_TEXT,
|
||||
MSG_TEXT_ONLY,
|
||||
MSG_INVOKE_PE,
|
||||
MSG_MENU_SHOW_LINES,
|
||||
MSG_CHECKBOX_SHOW_LINES,
|
||||
MSG_SEARCH_TEXT,
|
||||
MSG_INVOKE_ITEM,
|
||||
MSG_SELECT_HISTORY,
|
||||
|
||||
MSG_REPORT_FILE_NAME,
|
||||
MSG_REPORT_RESULT,
|
||||
MSG_REPORT_ERROR,
|
||||
MSG_SEARCH_FINISHED,
|
||||
|
||||
MSG_NEW_WINDOW,
|
||||
MSG_OPEN_PANEL,
|
||||
MSG_REFS_RECEIVED,
|
||||
MSG_TRY_QUIT,
|
||||
MSG_QUIT_NOW,
|
||||
|
||||
MSG_TRIM_SELECTION,
|
||||
MSG_COPY_TEXT,
|
||||
MSG_SELECT_IN_TRACKER,
|
||||
MSG_SELECT_ALL,
|
||||
MSG_OPEN_SELECTION
|
||||
};
|
||||
|
||||
enum state_t {
|
||||
STATE_IDLE = 0,
|
||||
STATE_SEARCH,
|
||||
STATE_CANCEL
|
||||
};
|
||||
|
||||
class Model {
|
||||
public:
|
||||
Model();
|
||||
|
||||
status_t LoadPrefs();
|
||||
status_t SavePrefs();
|
||||
|
||||
void AddToHistory(const char* text);
|
||||
void FillHistoryMenu(BMenu* menu);
|
||||
|
||||
// The directory we were invoked from.
|
||||
entry_ref fDirectory;
|
||||
|
||||
// The selected files we were invoked upon.
|
||||
BMessage fSelectedFiles;
|
||||
|
||||
// Whether we need to look into subdirectories.
|
||||
bool fRecurseDirs;
|
||||
|
||||
// Whether we need to follow symbolic links.
|
||||
bool fRecurseLinks;
|
||||
|
||||
// Whether we should skip subdirectories that start with a dot.
|
||||
bool fSkipDotDirs;
|
||||
|
||||
// Whether the search is case sensitive.
|
||||
bool fCaseSensitive;
|
||||
|
||||
// Whether the search pattern will be escaped.
|
||||
bool fEscapeText;
|
||||
|
||||
// Whether we look at text files only.
|
||||
bool fTextOnly;
|
||||
|
||||
// Whether we open the item in Pe and jump to the correct line.
|
||||
bool fInvokePe;
|
||||
|
||||
// Whether to show the contents of matching files.
|
||||
bool fShowContents;
|
||||
|
||||
// The dimensions of the window.
|
||||
BRect fFrame;
|
||||
|
||||
// The looper that will receive notifications.
|
||||
BLooper* fTarget;
|
||||
|
||||
// What are we doing.
|
||||
state_t fState;
|
||||
|
||||
// Current directory of the filepanel
|
||||
BString fFilePanelPath;
|
||||
|
||||
// Grep string encoding ?
|
||||
uint32 fEncoding;
|
||||
|
||||
private:
|
||||
BList* _LoadHistory();
|
||||
status_t _SaveHistory(BList* items);
|
||||
void _FreeHistory(BList* items);
|
||||
status_t _OpenFile(BFile* file, const char* name,
|
||||
uint32 openMode = B_READ_ONLY,
|
||||
directory_which which
|
||||
= B_USER_SETTINGS_DIRECTORY,
|
||||
BVolume* volume = NULL);
|
||||
};
|
||||
|
||||
#endif // MODEL_H
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 "GrepApp.h"
|
||||
|
||||
#include <AppFileInfo.h>
|
||||
#include <Entry.h>
|
||||
#include <Roster.h>
|
||||
#include <TrackerAddOn.h>
|
||||
|
||||
#include "GlobalDefs.h"
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
GrepApp app;
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
process_refs(entry_ref dirRef, BMessage *message, void* /*reserved*/)
|
||||
{
|
||||
// Tracker calls this function when the user invokes the add-on.
|
||||
// "dir_ref" contains the entry_ref of the current directory.
|
||||
// "message" is a standard B_REFS_RECEIVED BMessage whose "refs"
|
||||
// array contains the entry_refs of the selected files. The last
|
||||
// argument, "reserved", is currently unused.
|
||||
|
||||
// This version of TrackerGrep is a Tracker add-on, but primarily
|
||||
// it is a stand-alone application. The add-on launches the app
|
||||
// on the set of files you had selected in Tracker. That way you
|
||||
// get the benefits of the Tracker add-on with the benefits of the
|
||||
// stand-alone application.
|
||||
|
||||
message->AddRef("dir_ref", &dirRef);
|
||||
|
||||
// get the path of the Tracker add-on
|
||||
image_info image;
|
||||
int32 cookie = 0;
|
||||
status_t status = B_OK;
|
||||
|
||||
status = get_next_image_info(0, &cookie, &image);
|
||||
|
||||
while (status == B_OK) {
|
||||
if (((char*)process_refs >= (char*)image.text
|
||||
&& (char*)process_refs <= (char*)image.text + image.text_size)
|
||||
|| ((char*)process_refs >= (char*)image.data
|
||||
&& (char*)process_refs <= (char*)image.data + image.data_size))
|
||||
break;
|
||||
|
||||
status = get_next_image_info(0, &cookie, &image);
|
||||
}
|
||||
|
||||
entry_ref addonRef;
|
||||
|
||||
if (get_ref_for_path(image.name, &addonRef) == B_OK) {
|
||||
// It's better to launch the application by its entry
|
||||
// than by its application signature. There may be
|
||||
// multiple instances and we would not be certain
|
||||
// that the desired one is launched - the one which was
|
||||
// loaded into Tracker and whose process_refs() was called.
|
||||
be_roster->Launch(&addonRef, message);
|
||||
} else
|
||||
be_roster->Launch(APP_SIGNATURE, message);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* TextSearch.rdef
|
||||
*/
|
||||
|
||||
resource app_signature "application/x-vnd.mahlzeit.trackergrep";
|
||||
|
||||
resource app_version {
|
||||
major = 5,
|
||||
middle = 1,
|
||||
minor = 1,
|
||||
|
||||
variety = B_APPV_FINAL,
|
||||
internal = 0,
|
||||
|
||||
short_info = "Context search using Grep",
|
||||
long_info = "Context search in Tracker, a GUI wrapper of /bin/grep."
|
||||
};
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH;
|
||||
|
||||
resource file_types message {
|
||||
"types" = "text",
|
||||
"types" = "application/x-vnd.Be-directory",
|
||||
"types" = "application/x-vnd.Be-symlink"
|
||||
};
|
||||
|
||||
resource vector_icon {
|
||||
$"6E6369660A0200060338D2F73CD163BF82B23B84A94B88504870C900FFEFA5BD"
|
||||
$"FFFCC0FFFFF8900501020106023E49240000000000003CAAAA4940004A3000FF"
|
||||
$"FFFCC07CF1B706040192020016023A55A6BAC2293F0DA33E958646C2EB47A1D6"
|
||||
$"0001FF9E03010000020012023B98000000000000003C44004AD8004ADA000001"
|
||||
$"0FFF0180020106023C00000000000000003C00004A30004A500000DCF4FFFF60"
|
||||
$"94AA02001603360FF5B7B2B23AD6A4392A794ABC0B4AF035FF55C285005005FF"
|
||||
$"0E0606AE0BB40BBF4D33C3AFB75DC173BDEFC607C13EC804CA28BD82C118B920"
|
||||
$"C51BBB40BF07B8083AB6BC0605AE02B57D3EB9B9C3EFB7BB44BBB751BD75C936"
|
||||
$"CA8EC1B1402F0A093B593D5BBFCDC93E455BC516C5F160465B435D4544510A04"
|
||||
$"5A425E3F5A3D574008022E40BDB53308023142BE34BC0308023444C0E5BB5108"
|
||||
$"023746C0D8BD7508023A48C270BDB508023D4A4CBD820802404CC408BFE60605"
|
||||
$"7A024658565D5B5CCA15CB54CB0FCA5A584A540204423AC2BF3ABE583A384438"
|
||||
$"BF2438C38B424EBE584EC2BF4E4C444CC38B4CBF240606BA0A4C51565B585AC9"
|
||||
$"1CCA4EC983C9E959584F4E4B4D0E0A03020203000A0101011001178400040A02"
|
||||
$"0101000A0101001001178400040A000100000A04040604080A1815FF01178100"
|
||||
$"040A04040604080A18001501178200040A04030907051815FF01178100040A06"
|
||||
$"010B000A05010D1001178400040A08010D000A05010C1001178400040A07010C"
|
||||
$"000A09010C023C00000000000000003C000048B00048F000"
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Public domain, baby!
|
||||
*
|
||||
* Localization for Zeta users
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TRANSLATION_H
|
||||
#define TRANSLATION_H
|
||||
|
||||
#ifndef _T
|
||||
# define _T(x) x
|
||||
#endif
|
||||
|
||||
#endif // TRANSLATION_H
|
||||
Reference in New Issue
Block a user