00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00015 #include "findtext.hpp"
00016 #include <string.h>
00017 #include <errno.h>
00018 #include "findfile.hpp"
00019 #include "textfinder.hpp"
00020 #include "autofile.hpp"
00021 #include "stringbuf.hpp"
00022
00023 using namespace std;
00024
00025 namespace {
00026
00028 struct AutoFlag {
00030 bool& flag;
00031
00033 AutoFlag(bool& f) : flag(f) {}
00035 ~AutoFlag() { flag=0; }
00036 };
00037
00038 struct OpenCloseSender;
00039
00043 class FindTextImpl : public FindText, FindFileCallback, Publisher<FoundMsg>,
00044 Publisher<InfoMsg>, Publisher<ErrorMsg> {
00045 friend struct OpenCloseSender;
00046
00048 bool running;
00050 bool shouldStop;
00052 sh_ptr<TextFinder> txtFnd;
00053
00054 virtual void search(const std::string& dir, bool recur,
00055 const std::string& mask, const std::string& text);
00056
00057 virtual void stopSearch();
00058
00059 virtual Publisher<FoundMsg>& foundPub();
00060
00061 virtual Publisher<InfoMsg>& infoPub();
00062
00063 virtual Publisher<ErrorMsg>& errorPub();
00064
00070 virtual bool found(const std::string& fileName);
00071
00076 bool readLine(FILE* f, string& str, const std::string& file);
00077
00078 public:
00082 FindTextImpl() : running(0), shouldStop(0) {}
00083 };
00084
00089 struct OpenCloseSender {
00091 FindTextImpl& fti;
00093 const string& file;
00094
00096 OpenCloseSender(FindTextImpl& fti_, const string& file_) : fti(fti_),
00097 file(file_)
00098 {
00099 fti.Publisher<InfoMsg>::send(InfoMsg(fti, InfoMsg::opened, file));
00100 }
00101
00103 ~OpenCloseSender()
00104 {
00105 fti.Publisher<InfoMsg>::send(InfoMsg(fti, InfoMsg::closed, file));
00106 }
00107 };
00108
00109 void FindTextImpl::search(const std::string& dir, bool recur,
00110 const std::string& mask, const std::string& text)
00111 {
00112 try {
00113 if (running)
00114 throw newCException(_FLINE_, "search() already running");
00115 running=1;
00116
00117 AutoFlag autoRunning(running);
00118 AutoFlag autoShouldStop(shouldStop);
00119
00120 txtFnd=Factory::newTextFinder(text);
00121
00122 sh_ptr<FindFile> ff=Factory::newFindFile();
00123 ff->find(dir, recur, mask, *this);
00124 }
00125 catch (...) {
00126 throw newCException(_FLINE_, "Can't search", toCException(_FLINE_));
00127 }
00128 }
00129
00130 void FindTextImpl::stopSearch()
00131 {
00132 if (!running) throw newCException(_FLINE_, "search() isn't running");
00133 shouldStop=1;
00134 }
00135
00136 Publisher<FoundMsg>& FindTextImpl::foundPub()
00137 {
00138 return *this;
00139 }
00140
00141 Publisher<InfoMsg>& FindTextImpl::infoPub()
00142 {
00143 return *this;
00144 }
00145
00146 Publisher<ErrorMsg>& FindTextImpl::errorPub()
00147 {
00148 return *this;
00149 }
00150
00151 bool FindTextImpl::found(const std::string& fileName)
00152 {
00153 try {
00154 if (shouldStop) return 0;
00155
00156 AutoFILE f(fopen(fileName.c_str(), "r"));
00157 if (!f.get()) {
00158 Publisher<ErrorMsg>::send(ErrorMsg(*this, StringBuf("Can't open \"")+
00159 fileName+"\": "+strerror(errno)));
00160 return 1;
00161 }
00162
00163 OpenCloseSender ocs(*this, fileName);
00164
00165 string str;
00166 str.reserve(1024);
00167
00168 for (int lineNum=1; readLine(f.get(), str, fileName); lineNum++) {
00169 if (txtFnd->findIn(str))
00170 Publisher<FoundMsg>::send(FoundMsg(*this, fileName, lineNum, str));
00171 }
00172
00173 return 1;
00174 }
00175 catch (...) {
00176 throw newCException(_FLINE_, "Can't process \""+fileName+"\"",
00177 toCException(_FLINE_));
00178 }
00179 }
00180
00181 bool FindTextImpl::readLine(FILE* f, string& str, const std::string& file)
00182 {
00183 if (feof(f)) return 0;
00184 str.clear();
00185
00186 for (int ch; ; ) {
00187 switch (ch=fgetc(f)) {
00188 case EOF: {
00189 if (ferror(f)) {
00190 Publisher<ErrorMsg>::send(ErrorMsg(*this,
00191 StringBuf("Can't read from \"")+file+"\": "+
00192 strerror(errno)));
00193 return 0;
00194 }
00195
00196 return (str.size()) ? 1 : 0;
00197 }
00198 case '\n': return 1;
00199 default: {
00200 str.push_back(ch);
00201 break;
00202 }
00203 }
00204 }
00205 }
00206
00207 }
00208
00209 sh_ptr<FindText> Factory::newFindText()
00210 {
00211 try { return sh_ptr<FindText>(new FindTextImpl); }
00212 catch (...) {
00213 throw newCException(_FLINE_, "Can't create FindTextImpl object",
00214 toCException(_FLINE_));
00215 }
00216 }