public import "ecere" import "FileSystemBox" class NumberLink : struct { NumberLink prev, next; int num; }; struct SearchStackFrame { int tag; char path[MAX_LOCATION]; FileListing listing; bool branched; //DataRow result; //DataRow browse; FileSystemNode result; FileSystemNode browse; }; public class FileSystemSearch : Thread { public: bool active, terminate, hasNameSearch, hasSizeSearch, hasContentSearch, listLines; int count, matchCount; char location[MAX_LOCATION], nameSearch[1024], contentSearch[1024]; bool optionTree, optionBrowser, optionSubdirs; bool optionNameMatchCase, optionNameMatchWord; bool optionContentMatchCase, optionContentMatchWord; OldList lines; //DataField resultsNameField; //DataField browserNameField; // TEMPORARY // ExplorerSearch searchPanel; Window owner; FileSystemBox fsb; FileSystemSearch() { active = false; terminate = false; } virtual bool Window::NotifyUpdateSearchLocation(FileSystemSearch search, char * location); virtual bool Window::NotifySearchSortResults(FileSystemSearch search); virtual bool Window::NotifySearchSortBrowser(FileSystemSearch search); virtual bool Window::NotifySearchTerminated(FileSystemSearch search); bool SearchFileContent(String path) { bool match = false; File file = FileOpen(path, read); if(file) { // // char line[65536]; // char * find = null; // for( ; !find && file.GetLine(line, 65536) ; ) // find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord); // // find = strstr(line, contentSearch); // uint readCount = 16383; char * find = null; char buffer[16384]; int seekBack = 0 - strlen(contentSearch) - 2; if(listLines) { uint line = 1; while(readCount == 16383) { uint start = 0, len = 0; readCount = file.Read(buffer, 1, 16383); buffer[readCount] = '\0'; for( ; start < readCount; start += len ? len : 1) { if( (len = strlen(&buffer[start])) ) { char * newLine = buffer; uint bstart; find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord); // todo add a maximum line length possibility as param for(bstart = start; bstart < readCount && newLine && (!find || newLine < find); bstart += (newLine - &buffer[bstart]) / sizeof(char)) { newLine = strstr(&buffer[bstart], "\n"); newLine++; if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find)) line++; } if(find) { len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch); match = true; if(!lines.first || ((NumberLink)lines.last).num != line) lines.Add(NumberLink { num = line }); } } } file.Seek(seekBack, current); } } else { for( ; !find && readCount == 16383; ) { uint start = 0, len = 0; readCount = file.Read(buffer, 1, 16383); buffer[readCount] = '\0'; for( ; !find && start < readCount; start += len + 1) if( (len = strlen(&buffer[start])) ) find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord); file.Seek(seekBack, current); } match = (bool)find; } delete file; } return match; } // I wonder if this is optimized at the c level to be compiled inline // and to use in-place in-stack memory for both the return value and the parameters // if not, c should be more optimized... // would the const have any impact on optimization? unsigned int Main() { bool match; int frame, stackTop = 0, treeTop = 0; double lastTime = GetTime(); SearchStackFrame stack[1024]; //to be used for content replace... EditBox edit { multiLine = true, textHorzScroll = true, textVertScroll = true, maxLineSize = 65536 }; FileSystemNode node; // This won't give drive attribs for c: or c:\ and other drives as well // \\Nateus\data\ is not remote, etc... // How to? FileStats stats; terminate = false; count = 0; matchCount = 0; hasNameSearch = (strlen(nameSearch) != 0); hasSizeSearch = false; // this is temporary hasContentSearch = (strlen(contentSearch) != 0); listLines = true; lines = OldList { }; //SearchDir(location); FileGetStats(location, stats); strcpy(stack[0].path, location); stack[0].listing = FileListing { stack[0].path }; // there should be a sorted = true/false fsb.list.Clear(); // Binary Search sorting... if(optionTree) stack[0].branched = false; /*if(optionBrowser) { guiApp.Lock(); { //stack[0].browse = searchPanel.AddBrowserRow(); //node = MakeFileSystemNode(attribs, stack[0].path, // stack[0].path, fsb.bits.previewPictures, fsb.displaySystem); //stack[0].browse.SetData(browserNameField, node); //stack[0].browse.SetData(typeField, null); //stack[0].browse.SetData(sizeField, null); stack[0].browse = MakeFileSystemNode(stats, stack[0].path, stack[0].path, fsb.bits.previewPictures, fsb.displaySystem); fsb.AddTreeNode(stack[0].browse, true, false, null); // TEMPORARY // searchPanel.AddBrowse(stack[0].browse, null); } guiApp.Unlock(); }*/ for(frame = 0; frame >= 0 && !terminate; ) { if(stack[frame].listing.Find()) { count++; //match = (strcmp(stack[frame].listing.name, nameSearch) == 0); //match = (stack[frame].listing.name[0] == nameSearch[0]); //match = (bool)strstr(stack[frame].listing.name, nameSearch); if(hasNameSearch) match = (bool)SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord); else match = true; if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory) if(!SearchFileContent(stack[frame].listing.path)) match = false; if(match) { matchCount++; if(optionTree) { for(frame = treeTop; frame <= stackTop; frame++) { if(!stack[frame].branched) { guiApp.Lock(); if(frame) { stack[frame].result = MakeFileSystemNode(stack[frame - 1].listing.stats, stack[frame - 1].listing.name, stack[frame - 1].path, fsb.bits.previewPictures, fsb.displaySystem); fsb.AddTreeNode(stack[frame].result, true, false, stack[frame - 1].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[frame - 1].result); stack[frame].result.row.collapsed = false; } else { stack[0].result = MakeFileSystemNode(stats, stack[0].path, stack[0].path, fsb.bits.previewPictures, fsb.displaySystem); fsb.AddTreeNode(stack[0].result, true, false, null); // TEMPORARY // searchPanel.AddResult(stack[0].result, null); stack[0].result.row.collapsed = false; } stack[frame].branched = true; guiApp.Unlock(); } } treeTop = stackTop; frame--; } } if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory) { guiApp.Lock(); { double thisTime = GetTime(); if(thisTime - lastTime > 0.25) { NotifyUpdateSearchLocation(owner, this, stack[stackTop].listing.path); // TEMPORARY // searchPanel.SearchUpdateLabel(stack[stackTop].listing.path); lastTime = thisTime; } } //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path); frame++; /*if(optionBrowser) { stack[frame].browse = MakeFileSystemNode(stack[stackTop].listing.stats, stack[stackTop].listing.name, stack[stackTop].path, fsb.bits.previewPictures, fsb.displaySystem); fsb.AddTreeNode(stack[frame].browse, true, false, stack[stackTop].browse); // TEMPORARY // searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse); if(frame) stack[frame].browse.row.collapsed = true; //if(frame == 1) //searchPanel.SortBrowser(); // this can be very bad for performance in some situations // there should be a way to sort the nodes as they are added // BinarySearch sorting implementation in listBox's Sort? }*/ guiApp.Unlock(); strcpy(stack[frame].path, stack[stackTop].listing.path); stack[frame].listing = FileListing { stack[frame].path }; if(optionTree) stack[frame].branched = false; if(match) { guiApp.Lock(); stack[frame].result = MakeFileSystemNode(stack[stackTop].listing.stats, stack[stackTop].listing.name, stack[stackTop].path, fsb.bits.previewPictures, fsb.displaySystem); if(optionTree) { fsb.AddTreeNode(stack[frame].result, true, false, stack[stackTop].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[stackTop].result); stack[frame].result.row.collapsed = false; //searchPanel.SortResults(); // this can be very bad for performance in some situations // there should be a way to sort the nodes as they are added // BinarySearch sorting implementation in listBox's Sort? stack[frame].branched = true; } else { fsb.AddNode(stack[frame].result); //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path); } guiApp.Unlock(); } stackTop++; } else { guiApp.Lock(); /*if(optionBrowser) { FileSystemNode item; item = MakeFileSystemNode(stack[frame].listing.stats, stack[frame].listing.name, stack[frame].path, fsb.bits.previewPictures, fsb.displaySystem); fsb.AddTreeNode(item, true, false, stack[frame].browse); // TEMPORARY // searchPanel.AddBrowse(item, stack[frame].browse); //if(frame == 1) //searchPanel.SortBrowser(); // this can be very bad for performance in some situations // there should be a way to sort the nodes as they are added // BinarySearch sorting implementation in listBox's Sort? }*/ if(match) { FileSystemNode item; item = MakeFileSystemNode(stack[frame].listing.stats, stack[frame].listing.name, stack[frame].path, fsb.bits.previewPictures, fsb.displaySystem); if(optionTree) { fsb.AddTreeNode(item, true, false, stack[frame].result); // TEMPORARY // searchPanel.AddResult(item, stack[frame].result); item.row.collapsed = false; //searchPanel.SortResults(); // this can be very bad for performance in some situations // there should be a way to sort the nodes as they are added // BinarySearch sorting implementation in listBox's Sort? if(listLines && lines.first) { NumberLink lin = lines.first; char temp[MAX_F_STRING]; sprintf(temp, "lines %d", lin.num); for(lin = lin.next; lin && strlen(temp) < MAX_F_STRING; lin = lin.next) strcatf(temp, ", %d", lin.num); node = FileSystemNode { name = CopyString(temp), type = lineNumbers }; fsb.AddTreeNode(node, true, false, item); // TEMPORARY // searchPanel.AddResult(node, item); //row.AddRow().SetData(resultsNameField, node); lines.Free(null); } } else fsb.AddNode(item); //searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path); } guiApp.Unlock(); } } else { if(optionTree && stack[frame].branched && frame == treeTop) { stack[frame].branched = false; treeTop--; } frame--; stackTop--; } } if(terminate) for( ; frame >= 0 ; frame--) stack[frame].listing.Stop(); guiApp.Lock(); if(optionTree) NotifySearchSortResults(owner, this); // TEMPORARY // searchPanel.SortResults(); if(optionBrowser) NotifySearchSortBrowser(owner, this); // TEMPORARY // searchPanel.SortBrowser(); guiApp.Unlock(); active = false; guiApp.Lock(); NotifySearchTerminated(owner, this); // TEMPORARY // searchPanel.SearchTerminate(); guiApp.Unlock(); return 0; } }