Revert "TextSearch: use BString-based searching instead of Grep-based."
This reverts commit 1e9f5f5be4c8419c2085f51c78c9ac02ef13377b. As per discussion on the ML.
This commit is contained in:
parent
251eb00d51
commit
f8f8d2bbec
@ -90,6 +90,7 @@ GrepWindow::GrepWindow(BMessage* message)
|
||||
fRecurseDirs(NULL),
|
||||
fSkipDotDirs(NULL),
|
||||
fCaseSensitive(NULL),
|
||||
fEscapeText(NULL),
|
||||
fTextOnly(NULL),
|
||||
fInvokePe(NULL),
|
||||
fHistoryMenu(NULL),
|
||||
@ -210,6 +211,10 @@ void GrepWindow::MessageReceived(BMessage* message)
|
||||
_OnCaseSensitive();
|
||||
break;
|
||||
|
||||
case MSG_ESCAPE_TEXT:
|
||||
_OnEscapeText();
|
||||
break;
|
||||
|
||||
case MSG_TEXT_ONLY:
|
||||
_OnTextOnly();
|
||||
break;
|
||||
@ -254,6 +259,10 @@ void GrepWindow::MessageReceived(BMessage* message)
|
||||
_OnReportResult(message);
|
||||
break;
|
||||
|
||||
case MSG_REPORT_ERROR:
|
||||
_OnReportError(message);
|
||||
break;
|
||||
|
||||
case MSG_SELECT_ALL:
|
||||
_OnSelectAll(message);
|
||||
break;
|
||||
@ -443,6 +452,9 @@ GrepWindow::_CreateMenus()
|
||||
fCaseSensitive = new BMenuItem(
|
||||
B_TRANSLATE("Case-sensitive"), new BMessage(MSG_CASE_SENSITIVE));
|
||||
|
||||
fEscapeText = new BMenuItem(
|
||||
B_TRANSLATE("Escape search text"), new BMessage(MSG_ESCAPE_TEXT));
|
||||
|
||||
fTextOnly = new BMenuItem(
|
||||
B_TRANSLATE("Text files only"), new BMessage(MSG_TEXT_ONLY));
|
||||
|
||||
@ -474,6 +486,7 @@ GrepWindow::_CreateMenus()
|
||||
fPreferencesMenu->AddItem(fRecurseDirs);
|
||||
fPreferencesMenu->AddItem(fSkipDotDirs);
|
||||
fPreferencesMenu->AddItem(fCaseSensitive);
|
||||
fPreferencesMenu->AddItem(fEscapeText);
|
||||
fPreferencesMenu->AddItem(fTextOnly);
|
||||
fPreferencesMenu->AddItem(fInvokePe);
|
||||
|
||||
@ -594,6 +607,7 @@ GrepWindow::_LoadPrefs()
|
||||
fRecurseLinks->SetMarked(fModel->fRecurseLinks);
|
||||
fSkipDotDirs->SetMarked(fModel->fSkipDotDirs);
|
||||
fCaseSensitive->SetMarked(fModel->fCaseSensitive);
|
||||
fEscapeText->SetMarked(fModel->fEscapeText);
|
||||
fTextOnly->SetMarked(fModel->fTextOnly);
|
||||
fInvokePe->SetMarked(fModel->fInvokePe);
|
||||
|
||||
@ -1005,6 +1019,15 @@ GrepWindow::_OnReportResult(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepWindow::_OnReportError(BMessage* message)
|
||||
{
|
||||
const char* buf;
|
||||
if (message->FindString("error", &buf) == B_OK)
|
||||
fSearchResults->AddItem(new BStringItem(buf));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepWindow::_OnRecurseLinks()
|
||||
{
|
||||
@ -1032,6 +1055,15 @@ GrepWindow::_OnSkipDotDirs()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepWindow::_OnEscapeText()
|
||||
{
|
||||
fModel->fEscapeText = !fModel->fEscapeText;
|
||||
fEscapeText->SetMarked(fModel->fEscapeText);
|
||||
_ModelChanged();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GrepWindow::_OnCaseSensitive()
|
||||
{
|
||||
|
@ -50,9 +50,11 @@ private:
|
||||
void _OnNodeMonitorPulse();
|
||||
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();
|
||||
@ -101,6 +103,7 @@ private:
|
||||
BMenuItem* fRecurseDirs;
|
||||
BMenuItem* fSkipDotDirs;
|
||||
BMenuItem* fCaseSensitive;
|
||||
BMenuItem* fEscapeText;
|
||||
BMenuItem* fTextOnly;
|
||||
BMenuItem* fInvokePe;
|
||||
BMenu* fHistoryMenu;
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <Locale.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <UTF8.h>
|
||||
|
||||
#include "FileIterator.h"
|
||||
@ -60,10 +59,33 @@ strdup_to_utf8(uint32 encode, const char* src, int32 length)
|
||||
}
|
||||
|
||||
|
||||
Grepper::Grepper(BString pattern, const Model* model,
|
||||
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(%" B_PRId32 ", %" B_PRId32
|
||||
") dst allocate smalled(%" B_PRId32 ")\n", encode, length, dstLen);
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
|
||||
Grepper::Grepper(const char* pattern, const Model* model,
|
||||
const BHandler* target, FileIterator* iterator)
|
||||
: fPattern(pattern),
|
||||
: fPattern(NULL),
|
||||
fTarget(target),
|
||||
fEscapeText(model->fEscapeText),
|
||||
fCaseSensitive(model->fCaseSensitive),
|
||||
fEncoding(model->fEncoding),
|
||||
|
||||
@ -71,12 +93,19 @@ Grepper::Grepper(BString pattern, const Model* model,
|
||||
fThreadId(-1),
|
||||
fMustQuit(false)
|
||||
{
|
||||
if (fEncoding > 0) {
|
||||
char* src = strdup_from_utf8(fEncoding, pattern, strlen(pattern));
|
||||
_SetPattern(src);
|
||||
free(src);
|
||||
} else
|
||||
_SetPattern(pattern);
|
||||
}
|
||||
|
||||
|
||||
Grepper::~Grepper()
|
||||
{
|
||||
Cancel();
|
||||
free(fPattern);
|
||||
delete fIterator;
|
||||
}
|
||||
|
||||
@ -131,9 +160,17 @@ 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, "/tmp/SearchText%" B_PRId32, fThreadId);
|
||||
tempFile.SetTo(fileName);
|
||||
|
||||
while (!fMustQuit && fIterator->GetNextName(fileName)) {
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_FILE_NAME;
|
||||
message.AddString("filename", fileName);
|
||||
@ -154,44 +191,58 @@ Grepper::_GrepperThread()
|
||||
continue;
|
||||
}
|
||||
|
||||
BString contents;
|
||||
if (!_EscapeSpecialChars(fileName, B_PATH_NAME_LENGTH)) {
|
||||
sprintf(tempString, B_TRANSLATE("%s: Not enough room to escape "
|
||||
"the filename."), fileName);
|
||||
|
||||
BFile file(&ref, B_READ_WRITE);
|
||||
off_t size;
|
||||
file.GetSize(&size);
|
||||
file.Seek(0, SEEK_SET);
|
||||
char* buffer = new char[size];
|
||||
file.Read(buffer, size);
|
||||
if (fEncoding > 0) {
|
||||
char* temp = strdup_to_utf8(fEncoding, buffer, size);
|
||||
contents.SetTo(temp, size);
|
||||
free(temp);
|
||||
} else
|
||||
contents.SetTo(buffer, size);
|
||||
delete[] buffer;
|
||||
|
||||
int32 index = 0, lines = 1; // First line is 1 not 0
|
||||
while (true) {
|
||||
int32 newPos;
|
||||
if (fCaseSensitive)
|
||||
newPos = contents.FindFirst(fPattern, index);
|
||||
else
|
||||
newPos = contents.IFindFirst(fPattern, index);
|
||||
if (newPos == B_ERROR)
|
||||
break;
|
||||
|
||||
lines += _CountLines(contents, index, newPos);
|
||||
BString linenoAndLine;
|
||||
linenoAndLine.SetToFormat("%" B_PRId32 ":%s", lines, _GetLine(contents, newPos).String());
|
||||
message.AddString("text", linenoAndLine);
|
||||
|
||||
index = newPos + 1;
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_ERROR;
|
||||
message.AddString("error", tempString);
|
||||
fTarget.SendMessage(&message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.HasString("text") || fIterator->NotifyNegatives())
|
||||
fTarget.SendMessage(&message);
|
||||
sprintf(command, "grep -hn %s %s \"%s\" > \"%s\"",
|
||||
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 (fEncoding > 0) {
|
||||
char* tempdup = strdup_to_utf8(fEncoding, tempString,
|
||||
strlen(tempString));
|
||||
message.AddString("text", tempdup);
|
||||
free(tempdup);
|
||||
} else
|
||||
message.AddString("text", tempString);
|
||||
}
|
||||
|
||||
if (message.HasString("text") || fIterator->NotifyNegatives())
|
||||
fTarget.SendMessage(&message);
|
||||
|
||||
fclose(results);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(tempString, B_TRANSLATE("%s: There was a problem running grep."), fileName);
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_REPORT_ERROR;
|
||||
message.AddString("error", tempString);
|
||||
fTarget.SendMessage(&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 /tmp/ might be open.
|
||||
|
||||
remove(tempFile.Path());
|
||||
|
||||
message.MakeEmpty();
|
||||
message.what = MSG_SEARCH_FINISHED;
|
||||
fTarget.SendMessage(&message);
|
||||
@ -200,36 +251,79 @@ Grepper::_GrepperThread()
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Grepper::_CountLines(BString& str, int32 startPos, int32 endPos)
|
||||
void
|
||||
Grepper::_SetPattern(const char* src)
|
||||
{
|
||||
int32 ret = 0;
|
||||
for (int32 i = startPos; i < endPos; i++) {
|
||||
if (str[i] == '\n')
|
||||
ret++;
|
||||
if (src == NULL)
|
||||
return;
|
||||
|
||||
if (!fEscapeText) {
|
||||
fPattern = strdup(src);
|
||||
return;
|
||||
}
|
||||
return ret;
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
Grepper::_GetLine(BString& str, int32 pos)
|
||||
bool
|
||||
Grepper::_EscapeSpecialChars(char* buffer, ssize_t bufferSize)
|
||||
{
|
||||
int32 startPos = 0;
|
||||
int32 endPos = str.Length();
|
||||
for (int32 i = pos; i > 0; i--) {
|
||||
if (str[i] == '\n') {
|
||||
startPos = i + 1;
|
||||
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];
|
||||
}
|
||||
for (int32 i = pos; i < endPos; i++) {
|
||||
if (str[i] == '\n') {
|
||||
endPos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BString ret;
|
||||
return str.CopyInto(ret, startPos, endPos - startPos);
|
||||
*buffer = '\0';
|
||||
free(copy);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define GREPPER_H
|
||||
|
||||
#include <Messenger.h>
|
||||
#include <String.h>
|
||||
|
||||
class FileIterator;
|
||||
class Model;
|
||||
@ -14,7 +13,7 @@ class Model;
|
||||
// Executes "grep" in a background thread.
|
||||
class Grepper {
|
||||
public:
|
||||
Grepper(BString pattern, const Model* model,
|
||||
Grepper(const char* pattern, const Model* model,
|
||||
const BHandler* target,
|
||||
FileIterator* iterator);
|
||||
virtual ~Grepper();
|
||||
@ -31,14 +30,16 @@ private:
|
||||
// The thread function that does the actual grepping.
|
||||
int32 _GrepperThread();
|
||||
|
||||
// Counts the number of linebreaks from startPos to endPos.
|
||||
int32 _CountLines(BString& str, int32 startPos,
|
||||
int32 endPos);
|
||||
// Gets the complete line that "pos" is on.
|
||||
BString _GetLine(BString& str, int32 pos);
|
||||
// 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);
|
||||
private:
|
||||
// The search pattern.
|
||||
BString fPattern;
|
||||
// The (escaped) search pattern.
|
||||
char* fPattern;
|
||||
|
||||
// The settings from the model.
|
||||
BMessenger fTarget;
|
||||
|
@ -35,6 +35,7 @@ Model::Model()
|
||||
fRecurseLinks(false),
|
||||
fSkipDotDirs(true),
|
||||
fCaseSensitive(false),
|
||||
fEscapeText(true),
|
||||
fTextOnly(true),
|
||||
fInvokePe(false),
|
||||
|
||||
@ -90,6 +91,9 @@ Model::LoadPrefs()
|
||||
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);
|
||||
|
||||
@ -143,6 +147,9 @@ Model::SavePrefs()
|
||||
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));
|
||||
|
||||
|
@ -23,6 +23,7 @@ enum {
|
||||
MSG_RECURSE_DIRS,
|
||||
MSG_SKIP_DOT_DIRS,
|
||||
MSG_CASE_SENSITIVE,
|
||||
MSG_ESCAPE_TEXT,
|
||||
MSG_TEXT_ONLY,
|
||||
MSG_INVOKE_PE,
|
||||
MSG_CHECKBOX_SHOW_LINES,
|
||||
@ -34,6 +35,7 @@ enum {
|
||||
|
||||
MSG_REPORT_FILE_NAME,
|
||||
MSG_REPORT_RESULT,
|
||||
MSG_REPORT_ERROR,
|
||||
MSG_SEARCH_FINISHED,
|
||||
|
||||
MSG_NEW_WINDOW,
|
||||
@ -85,6 +87,9 @@ public:
|
||||
// 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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user