void SearchContext::searchProc() { int id = searchID_; HANDLE findHandle = INVALID_HANDLE_VALUE; StringList paths; paths = params_.paths; RegexList filespecRegexes; pcre *matchRegex = NULL; directoriesSearched_ = 0; directoriesSkipped_ = 0; filesSearched_ = 0; filesSkipped_ = 0; filesWithHits_ = 0; linesWithHits_ = 0; hits_ = 0; unsigned int startTick = GetTickCount(); bool filespecUsesRegexes = ((params_.flags & SF_FILESPEC_REGEXES) != 0); bool matchUsesRegexes = ((params_.flags & SF_MATCH_REGEXES) != 0); delete pokeData_; pokeData_ = new PokeData; if(matchUsesRegexes) { const char *error; int erroffset; int flags = 0; if(!(params_.flags & SF_MATCH_CASE_SENSITIVE)) flags |= PCRE_CASELESS; matchRegex = pcre_compile(params_.match.c_str(), flags, &error, &erroffset, NULL); if(!matchRegex) { MessageBox(window_, error, "Match Regex Error", MB_OK); goto cleanup; } } for(StringList::iterator it = params_.filespecs.begin(); it != params_.filespecs.end(); ++it) { std::string regexString = it->c_str(); if(!filespecUsesRegexes) convertWildcard(regexString); int flags = 0; if(!(params_.flags & SF_FILESPEC_CASE_SENSITIVE)) flags |= PCRE_CASELESS; const char *error; int erroffset; pcre *regex = pcre_compile(regexString.c_str(), flags, &error, &erroffset, NULL); if(regex) filespecRegexes.push_back(regex); else { MessageBox(window_, error, "Filespec Regex Error", MB_OK); goto cleanup; } } PostMessage(window_, WM_SEARCHCONTEXT_STATE, 1, 0); while(!paths.empty()) { directoriesSearched_++; stopCheck(); std::string currentSearchPath = paths.back(); std::string currentSearchWildcard = currentSearchPath + "\\*"; paths.pop_back(); WIN32_FIND_DATA wfd; findHandle = FindFirstFile(currentSearchWildcard.c_str(), &wfd); if(findHandle == INVALID_HANDLE_VALUE) continue; while(FindNextFile(findHandle, &wfd)) { stopCheck(); bool isDirectory = ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); if((wfd.cFileName[0] == '.') || (wfd.cFileName[0] == 0)) { if(isDirectory) directoriesSkipped_++; else filesSkipped_++; continue; } std::string filename = currentSearchPath; filename += "\\"; filename += wfd.cFileName; if(isDirectory) { if(params_.flags & SF_RECURSIVE) paths.push_back(filename); } else { if(searchFile(id, filename, filespecRegexes, matchRegex)) { filesSearched_++; } else { filesSkipped_++; } poke(id, "", HighlightList(), 0, false); } } if(findHandle != INVALID_HANDLE_VALUE) { FindClose(findHandle); } } cleanup: for(RegexList::iterator it = filespecRegexes.begin(); it != filespecRegexes.end(); ++it) { pcre_free(*it); } if(matchRegex) pcre_free(matchRegex); filespecRegexes.clear(); if(!stop_) { unsigned int endTick = GetTickCount(); char buffer[512]; float sec = (endTick - startTick) / 1000.0f; const char *verb = "searched"; if(params_.flags & SF_REPLACE) verb = "updated"; sprintf(buffer, "\n%d hits in %d lines across %d files.\n%d directories scanned, %d files %s, %d files skipped (%3.3f sec)", hits_, linesWithHits_, filesWithHits_, directoriesSearched_, filesSearched_, verb, filesSkipped_, sec); poke(id, buffer, HighlightList(), 0, true); } delete pokeData_; pokeData_ = NULL; PostMessage(window_, WM_SEARCHCONTEXT_STATE, 0, 0); }
int main(int argc, char **argv) { setvbuf(stdout, NULL, _IOLBF, 0); #ifdef XP_UNIX unlimit(); #endif fprintf(stdout, "\n"); unsigned long limit = 0; // no thread limit by default char *addr = NULL; PRBool log = PR_FALSE; LogLevel logLevel = LOGINFO; PLOptState *options; PRBool secure = PR_FALSE; PRBool NSTests = PR_FALSE; // don't execute Netscape tests by default PtrList<char> protlist; // list of security protocols PtrList<char> configlist; // list of configurations RegexList regexlist; // list of Sun tests/regex to load RegexList regexcludelist; // list of Sun tests/regex to exclude char* suitename = "suite1"; PRInt32 concurrent = 0; // number of concurrent threads for each test. 0 means sequential, single-threaded PRInt32 delay = 0; PRInt32 split = 0; PRInt32 timeout = 0; // leave timeout unchanged by default char* cert=NULL; char* certpwd=NULL; char* cipherString = NULL; char* version = "ENTERPRISE"; PRInt32 release = 41; PRInt32 hsp = 0; // SSL handshake period PRBool performance = PR_FALSE; PRInt32 maxtm = 0; PRUint16 af = PR_AF_INET; PRInt32 displayperiod=0; PRBool loop = PR_FALSE; Logger::logInitialize(logLevel); options = PL_CreateOptState(argc, argv, "X:C:h:H:l:c:d:n:w46r:sx:p:o:t:a:e:k:Ng:v:R:QPE:T:L:"); long repeat = 1; while ( PL_GetNextOpt(options) == PL_OPT_OK) { switch(options->option) { case 'L': loop = PR_TRUE; if (options->value) displayperiod = (PRInt32) atoi(options->value); break; case 'E': if (options->value) protlist.insert(strdup(options->value)); break; case 'T': if (options->value) maxtm = (PRInt32) atoi(options->value); break; case 'H': if (options->value) hsp = (PRInt32) atoi(options->value); break; case 'v': if (options->value) version = uppercase(strdup(options->value)); break; case 'g': if (options->value) configlist.insert(strdup(options->value)); break; case 'x': if (options->value) regexlist.add(options->value); break; case 'X': if (options->value) regexcludelist.add(options->value); break; case 'w': log = PR_TRUE; break; case 'r': if (options->value) repeat = atol(options->value); break; case 'e': if (options->value) timeout = atol(options->value); break; case 'o': if (options->value) split = atol(options->value); break; case 't': if (options->value) delay = atol(options->value); break; case 'd': if (options->value) suitename = strdup(options->value); break; case 'a': if (options->value) arch = strdup(options->value); break; case 'N': NSTests = PR_TRUE; break; case 'h': if (options->value) addr = strdup(options->value); break; case 'p': if (options->value) concurrent = atol(options->value); else concurrent = 1; // 1 thread per test break; case 'P': performance = PR_TRUE; // meaure performance only break; case 'l': if (options->value) logLevel = (LogLevel)atoi(options->value); break; case 'R': if (options->value) release = (PRInt32) atoi(options->value); break; case 's': secure = PR_TRUE; break; case 'n': if (options->value) cert = strdup(options->value); break; case 'k': if (options->value) certpwd = strdup(options->value); break; case 'c': if (options->value) { cipherString = strdup(options->value); if (PR_TRUE != EnableCipher(cipherString)) { Logger::logError(LOGINFO, "Invalid cipher specified.\n"); }; } break; case 'C': if (options->value) limit = atol(options->value); else limit = 0; // no thread limit break; case 'Q': printCipherOptions(); break; case '6': af = PR_AF_INET6; break; case '4': af = PR_AF_INET; break; }; }; SecurityProtocols secprots; if (PR_TRUE == secure) { NSString str; str.append(suitename); str.append("/certs/client"); secure = InitSecurity((char*)str.data(), cert, certpwd); if (PR_TRUE != secure) Logger::logError(LOGINFO, "Unable to initialize security.\n"); if (protlist.entries()) { secprots = protlist; }; }; PL_DestroyOptState(options); Logger::logInitialize(logLevel); nstime_init(); if (!addr) { usage(argv[0]); return -1; }; HttpServer server(addr, af); server.setSSL(secure); if (PR_FALSE == NSTests) { if (alltests) alltests->clear(); // cancel all the Netscape tests if (!regexlist.length()) regexlist.add(".*"); }; if (!configlist.entries()) configlist.insert("COMMON"); // if no config is specified, select default COMMON configuration Engine::globaltimeout = PR_TicksPerSecond()*timeout; SunTestSuite suite(configlist, suitename, regexlist, regexcludelist, arch, version, release, log, PR_TicksPerSecond()*timeout, split, delay, hsp, secprots, maxtm); PRInt32 percent = suite.runTests(server, concurrent, repeat, limit, performance, loop, displayperiod); return percent; };
bool SearchContext::searchFile(int id, const std::string &filename, RegexList &filespecRegexes, pcre *matchRegex) { bool matchesOneFilespec = false; for(RegexList::iterator it = filespecRegexes.begin(); it != filespecRegexes.end(); ++it) { pcre *regex = *it; if(pcre_exec(regex, NULL, filename.c_str(), filename.length(), 0, 0, NULL, 0) >= 0) { matchesOneFilespec = true; break; } } if(!matchesOneFilespec) return false; std::string contents; if(!readEntireFile(filename, contents, params_.maxFileSize)) return false; std::string workBuffer = contents; std::string updatedContents; bool atLeastOneMatch = false; int lineNumber = 1; char *p = &workBuffer[0]; char *line; while((line = nextToken(&p, '\n')) != NULL) { char *originalLine = line; std::string replacedLine; SearchEntry entry; int ovector[100]; do { bool matches = false; int matchPos; int matchLen; if(matchRegex) { int rc; if(rc = pcre_exec(matchRegex, 0, line, strlen(line), 0, 0, ovector, sizeof(ovector)) >= 0) { matches = true; matchPos = ovector[0]; matchLen = ovector[1] - ovector[0]; } } else { char *match; if(params_.flags & SF_MATCH_CASE_SENSITIVE) match = strstr(line, params_.match.c_str()); else match = strstri(line, params_.match.c_str()); if(match != NULL) { matches = true; matchPos = match - line; matchLen = params_.match.length(); } } if(params_.flags & SF_REPLACE) { if(matches) { replacedLine.append(line, matchPos); entry.highlights_.push_back(Highlight(replacedLine.length(), params_.replace.length())); replacedLine.append(params_.replace); line += matchPos + matchLen; } else { break; } } else { if(matches) { entry.filename_ = filename; entry.match_ = originalLine; entry.line_ = lineNumber; entry.highlights_.push_back(Highlight(matchPos + (line - originalLine), matchLen)); line += matchPos + matchLen; } else { break; } } if(matches) hits_++; } while(*line); if(!entry.filename_.empty()) { linesWithHits_++; atLeastOneMatch = true; } if(params_.flags & SF_REPLACE) { if(line && *line) replacedLine += line; if(replacedLine != originalLine) { entry.filename_ = filename; entry.match_ = replacedLine; entry.line_ = lineNumber; append(id, entry); } replacedLine += "\n"; updatedContents += replacedLine; } else { if(!entry.filename_.empty()) append(id, entry); } lineNumber++; } if(atLeastOneMatch) filesWithHits_++; if(params_.flags & SF_REPLACE) { if((contents != updatedContents)) { bool overwriteFile = true; if(params_.flags & SF_BACKUP) { std::string backupFilename = filename; backupFilename += "."; backupFilename += params_.backupExtension; if(!writeEntireFile(backupFilename, contents)) { std::string err = "WARNING: Couldn't write backup file (skipping replacement): "; err += backupFilename; err += "\n"; poke(id, err.c_str(), HighlightList(), 0, false); overwriteFile = false; } } if(overwriteFile) { if(writeEntireFile(filename, updatedContents)) { return true; } else { std::string err = "WARNING: Couldn't write to file: "; err += filename; err += "\n"; poke(id, err.c_str(), HighlightList(), 0, false); } } } return false; } return true; }
bool SearchContext::searchFile(int id, const std::string &filename, RegexList &filespecRegexes, pcre *matchRegex) { bool matchesOneFilespec = false; for(RegexList::iterator it = filespecRegexes.begin(); it != filespecRegexes.end(); ++it) { pcre *regex = *it; if(pcre_exec(regex, NULL, filename.c_str(), filename.length(), 0, 0, NULL, 0) >= 0) { matchesOneFilespec = true; break; } } if(!matchesOneFilespec) return false; std::string contents; if(!readEntireFile(filename, contents, params_.maxFileSize)) return false; std::string workBuffer = contents; std::string updatedContents; std::deque<char *> contextLines; bool atLeastOneMatch = false; int trailingContextLines = 0; int lineNumber = 1; char *p = &workBuffer[0]; char *line; while((line = nextToken(&p, '\n')) != NULL) { char *originalLine = line; std::string replacedLine; SearchEntry entry; int ovector[100]; // Strip newline, but remember exactly what kind it was bool hasCarriageReturn = false; int lineLen = strlen(line); if(lineLen && (line[lineLen - 1] == '\r')) { line[lineLen - 1] = 0; hasCarriageReturn = true; } // Matching loop (we might find our string a few times on a single line) bool lineMatched = false; do { bool matches = false; int matchPos; int matchLen; // The actual match. Either invoke PCRE or do a boring strstr if(matchRegex) { int rc; if(rc = pcre_exec(matchRegex, 0, line, strlen(line), 0, 0, ovector, sizeof(ovector)) >= 0) { matches = true; matchPos = ovector[0]; matchLen = ovector[1] - ovector[0]; } } else { char *match; if(params_.flags & SF_MATCH_CASE_SENSITIVE) match = strstr(line, params_.match.c_str()); else match = strstri(line, params_.match.c_str()); if(match != NULL) { matches = true; matchPos = match - line; matchLen = params_.match.length(); } } if(matches) lineMatched = true; // Handle the match. For replace or find, we: // * Add output explaining the match // * Advance the line pointer for another match attempt // ... or ... // * "break", which leaves the matching loop if(params_.flags & SF_REPLACE) { if(matches) { std::string temp(line, matchPos); replacedLine.append(temp); replacedLine.append(params_.replace); entry.textBlocks.addBlock(temp, config_.textColor_); entry.textBlocks.addBlock(params_.replace, config_.highlightColor_, true); line += matchPos + matchLen; } else { break; } } else { if(matches) { entry.textBlocks.addHighlightedBlock(originalLine, matchPos + (line - originalLine), matchLen, config_.textColor_, config_.highlightColor_, true); line += matchPos + matchLen; } else { break; } } if(matches) hits_++; } while(*line); // end of matching loop // If we're doing a replace, finish the line and append to the final updated contents if(params_.flags & SF_REPLACE) { if(line && *line) { replacedLine += line; entry.textBlocks.addBlock(line, config_.textColor_); } if(hasCarriageReturn) { replacedLine += "\r"; } replacedLine += "\n"; updatedContents += replacedLine; } bool outputMatch = false; if(lineMatched) { // keep stats linesWithHits_++; atLeastOneMatch = true; // If we matched, consider notifying the user. We'll always say something // unless the replaced text doesn't actually change the line. outputMatch = ( !(params_.flags & SF_REPLACE) ) || (replacedLine != originalLine); if(outputMatch) { entry.filename_ = filename; entry.line_ = lineNumber; // output all existing context lines if(contextLines.size()) { SearchEntry contextEntry; contextEntry.filename_ = entry.filename_; contextEntry.contextOnly_ = true; int currLine = entry.line_ - contextLines.size(); for(std::deque<char *>::iterator it = contextLines.begin(); it != contextLines.end(); ++it) { TextBlockList textBlocks; textBlocks.addBlock(*it, config_.textColor_); contextEntry.textBlocks.swap(textBlocks); contextEntry.line_ = currLine++; append(id, contextEntry); } contextLines.clear(); } append(id, entry); } // Remember that we'd like the next few lines, even if they don't match trailingContextLines = config_.contextLines_; } if(!outputMatch) { // Didn't output a match. Keep track or output the line anyway for contextual reasons. if(trailingContextLines > 0) { // A recent match wants to see this line in the output anyway SearchEntry trailingEntry; trailingEntry.filename_ = filename; trailingEntry.line_ = lineNumber; trailingEntry.contextOnly_ = true; trailingEntry.textBlocks.addBlock(originalLine, config_.textColor_); append(id, trailingEntry); trailingContextLines--; } else { // didn't output a match, and wasn't output as context. stash it in contextLines contextLines.push_back(originalLine); if((int)contextLines.size() > config_.contextLines_) contextLines.pop_front(); } } lineNumber++; } // end of line loop (done reading file) if(atLeastOneMatch) filesWithHits_++; if(params_.flags & SF_REPLACE) { if((contents != updatedContents)) { bool overwriteFile = true; if(params_.flags & SF_BACKUP) { std::string backupFilename = filename; backupFilename += "."; backupFilename += params_.backupExtension; if(!writeEntireFile(backupFilename, contents)) { std::string err = "WARNING: Couldn't write backup file (skipping replacement): "; err += backupFilename; err += "\n"; sendError(id, err); overwriteFile = false; } } if(overwriteFile) { if(writeEntireFile(filename, updatedContents)) { return true; } else { std::string err = "WARNING: Couldn't write to file: "; err += filename; err += "\n"; sendError(id, err); } } } return false; } return true; }