diff --git a/src/apps/text_search/GrepWindow.cpp b/src/apps/text_search/GrepWindow.cpp index 5e2864e80a..ee660209c4 100644 --- a/src/apps/text_search/GrepWindow.cpp +++ b/src/apps/text_search/GrepWindow.cpp @@ -90,7 +90,6 @@ GrepWindow::GrepWindow(BMessage* message) fRecurseDirs(NULL), fSkipDotDirs(NULL), fCaseSensitive(NULL), - fEscapeText(NULL), fTextOnly(NULL), fInvokePe(NULL), fHistoryMenu(NULL), @@ -211,10 +210,6 @@ void GrepWindow::MessageReceived(BMessage* message) _OnCaseSensitive(); break; - case MSG_ESCAPE_TEXT: - _OnEscapeText(); - break; - case MSG_TEXT_ONLY: _OnTextOnly(); break; @@ -259,10 +254,6 @@ void GrepWindow::MessageReceived(BMessage* message) _OnReportResult(message); break; - case MSG_REPORT_ERROR: - _OnReportError(message); - break; - case MSG_SELECT_ALL: _OnSelectAll(message); break; @@ -452,9 +443,6 @@ 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)); @@ -486,7 +474,6 @@ GrepWindow::_CreateMenus() fPreferencesMenu->AddItem(fRecurseDirs); fPreferencesMenu->AddItem(fSkipDotDirs); fPreferencesMenu->AddItem(fCaseSensitive); - fPreferencesMenu->AddItem(fEscapeText); fPreferencesMenu->AddItem(fTextOnly); fPreferencesMenu->AddItem(fInvokePe); @@ -607,7 +594,6 @@ 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); @@ -1019,15 +1005,6 @@ 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() { @@ -1055,15 +1032,6 @@ GrepWindow::_OnSkipDotDirs() } -void -GrepWindow::_OnEscapeText() -{ - fModel->fEscapeText = !fModel->fEscapeText; - fEscapeText->SetMarked(fModel->fEscapeText); - _ModelChanged(); -} - - void GrepWindow::_OnCaseSensitive() { diff --git a/src/apps/text_search/GrepWindow.h b/src/apps/text_search/GrepWindow.h index e65f9a65e6..33a31c6be7 100644 --- a/src/apps/text_search/GrepWindow.h +++ b/src/apps/text_search/GrepWindow.h @@ -50,11 +50,9 @@ 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(); @@ -103,7 +101,6 @@ private: BMenuItem* fRecurseDirs; BMenuItem* fSkipDotDirs; BMenuItem* fCaseSensitive; - BMenuItem* fEscapeText; BMenuItem* fTextOnly; BMenuItem* fInvokePe; BMenu* fHistoryMenu; diff --git a/src/apps/text_search/Grepper.cpp b/src/apps/text_search/Grepper.cpp index 1a40decb9a..cf9a42f62a 100644 --- a/src/apps/text_search/Grepper.cpp +++ b/src/apps/text_search/Grepper.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "FileIterator.h" @@ -59,33 +60,10 @@ strdup_to_utf8(uint32 encode, const char* src, int32 length) } -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, +Grepper::Grepper(BString pattern, const Model* model, const BHandler* target, FileIterator* iterator) - : fPattern(NULL), + : fPattern(pattern), fTarget(target), - fEscapeText(model->fEscapeText), fCaseSensitive(model->fCaseSensitive), fEncoding(model->fEncoding), @@ -93,19 +71,12 @@ Grepper::Grepper(const char* 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; } @@ -160,17 +131,9 @@ 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); @@ -191,58 +154,44 @@ Grepper::_GrepperThread() continue; } - if (!_EscapeSpecialChars(fileName, B_PATH_NAME_LENGTH)) { - sprintf(tempString, B_TRANSLATE("%s: Not enough room to escape " - "the filename."), fileName); + BString contents; - message.MakeEmpty(); - message.what = MSG_REPORT_ERROR; - message.AddString("error", tempString); + 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; + } + + if (message.HasString("text") || fIterator->NotifyNegatives()) fTarget.SendMessage(&message); - continue; - } - - 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); @@ -251,79 +200,36 @@ Grepper::_GrepperThread() } -void -Grepper::_SetPattern(const char* src) +int32 +Grepper::_CountLines(BString& str, int32 startPos, int32 endPos) { - if (src == NULL) - return; - - if (!fEscapeText) { - fPattern = strdup(src); - return; + int32 ret = 0; + for (int32 i = startPos; i < endPos; i++) { + if (str[i] == '\n') + 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'; + return ret; } -bool -Grepper::_EscapeSpecialChars(char* buffer, ssize_t bufferSize) +BString +Grepper::_GetLine(BString& str, int32 pos) { - 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; + int32 startPos = 0; + int32 endPos = str.Length(); + for (int32 i = pos; i > 0; i--) { + if (str[i] == '\n') { + startPos = i + 1; + break; + } + } + for (int32 i = pos; i < endPos; i++) { + if (str[i] == '\n') { + endPos = i; break; } - *buffer++ = copy[count]; } - *buffer = '\0'; - free(copy); - return result; -} + BString ret; + return str.CopyInto(ret, startPos, endPos - startPos); +} diff --git a/src/apps/text_search/Grepper.h b/src/apps/text_search/Grepper.h index 221bff61fd..ea90da619a 100644 --- a/src/apps/text_search/Grepper.h +++ b/src/apps/text_search/Grepper.h @@ -6,6 +6,7 @@ #define GREPPER_H #include +#include class FileIterator; class Model; @@ -13,7 +14,7 @@ class Model; // Executes "grep" in a background thread. class Grepper { public: - Grepper(const char* pattern, const Model* model, + Grepper(BString pattern, const Model* model, const BHandler* target, FileIterator* iterator); virtual ~Grepper(); @@ -30,16 +31,14 @@ private: // 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); + // 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); private: - // The (escaped) search pattern. - char* fPattern; + // The search pattern. + BString fPattern; // The settings from the model. BMessenger fTarget; diff --git a/src/apps/text_search/Model.cpp b/src/apps/text_search/Model.cpp index c76d65ae41..4f001121c4 100644 --- a/src/apps/text_search/Model.cpp +++ b/src/apps/text_search/Model.cpp @@ -35,7 +35,6 @@ Model::Model() fRecurseLinks(false), fSkipDotDirs(true), fCaseSensitive(false), - fEscapeText(true), fTextOnly(true), fInvokePe(false), @@ -91,9 +90,6 @@ 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); @@ -147,9 +143,6 @@ 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)); diff --git a/src/apps/text_search/Model.h b/src/apps/text_search/Model.h index 7c465e7588..96e7dc6c0b 100644 --- a/src/apps/text_search/Model.h +++ b/src/apps/text_search/Model.h @@ -23,7 +23,6 @@ enum { MSG_RECURSE_DIRS, MSG_SKIP_DOT_DIRS, MSG_CASE_SENSITIVE, - MSG_ESCAPE_TEXT, MSG_TEXT_ONLY, MSG_INVOKE_PE, MSG_CHECKBOX_SHOW_LINES, @@ -35,7 +34,6 @@ enum { MSG_REPORT_FILE_NAME, MSG_REPORT_RESULT, - MSG_REPORT_ERROR, MSG_SEARCH_FINISHED, MSG_NEW_WINDOW, @@ -87,9 +85,6 @@ 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;