X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?p=ede;a=blobdiff_plain;f=libede%2Fsrc%2FFileSystemSearch.ec;fp=libede%2Fsrc%2FFileSystemSearch.ec;h=df805b01b6e524ca80226f87346f3370ebbab461;hp=0000000000000000000000000000000000000000;hb=eafcc117e8fb344bb09e4e672156691b18f8730f;hpb=4fc0669415b9f2bd30e0322acd9b03a688e36d4f diff --git a/libede/src/FileSystemSearch.ec b/libede/src/FileSystemSearch.ec new file mode 100644 index 0000000..df805b0 --- /dev/null +++ b/libede/src/FileSystemSearch.ec @@ -0,0 +1,347 @@ +import "ExplorerTree" +import "Finder" + +class NumberLink : struct +{ + NumberLink prev, next; + int num; +}; + +struct SearchStackFrame +{ + int tag; + char path[MAX_LOCATION]; + FileListing listing; + + bool branched; + //DataRow result; + //DataRow browse; + ExplorerFileBranch result; + ExplorerFileBranch browse; +}; + +class SearchThread : Thread +{ + 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; + + ExplorerSearch searchPanel; + + SearchThread() + { + active = false; + terminate = false; + } + + 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 }; + + ExplorerFileBranch fileTreeBranch; + // 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 + // Binary Search sorting... + if(optionTree) + stack[0].branched = false; + if(optionBrowser) + { + app.Lock(); + { + //stack[0].browse = searchPanel.AddBrowserRow(); + //fileTreeBranch = MakeFileBranch(attribs, stack[0].path); + //stack[0].browse.SetData(browserNameField, fileTreeBranch); + //stack[0].browse.SetData(typeField, null); + //stack[0].browse.SetData(sizeField, null); + + stack[0].browse = MakeFileBranch(stats, stack[0].path); + searchPanel.AddBrowse(stack[0].browse, null); + } + app.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) + { + app.Lock(); + if(frame) + { + stack[frame].result = MakeFileBranch(stack[frame - 1].listing.stats, stack[frame - 1].listing.name); + searchPanel.AddResult(stack[frame].result, stack[frame - 1].result); + stack[frame].result.row.collapsed = false; + } + else + { + stack[0].result = MakeFileBranch(stats, stack[0].path); + searchPanel.AddResult(stack[0].result, null); + stack[0].result.row.collapsed = false; + } + stack[frame].branched = true; + app.Unlock(); + } + } + treeTop = stackTop; + frame--; + } + } + if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory) + { + app.Lock(); + { + double thisTime = GetTime(); + if(thisTime - lastTime > 0.25) + { + searchPanel.SearchUpdateLabel(stack[stackTop].listing.path); + lastTime = thisTime; + } + } + //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path); + frame++; + if(optionBrowser) + { + stack[frame].browse = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name); + 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? + } + app.Unlock(); + strcpy(stack[frame].path, stack[stackTop].listing.path); + stack[frame].listing = FileListing { stack[frame].path }; + if(optionTree) + stack[frame].branched = false; + if(match) + { + app.Lock(); + if(optionTree) + { + stack[frame].result = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name); + 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 + { + //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path); + } + app.Unlock(); + } + stackTop++; + } + else + { + app.Lock(); + if(optionBrowser) + { + ExplorerFileBranch item; + item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name); + 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) + { + if(optionTree) + { + ExplorerFileBranch item; + item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name); + 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); + fileTreeBranch = ExplorerFileBranch { name = CopyString(temp), type = lineNumbers }; + searchPanel.AddResult(fileTreeBranch, item); + //row.AddRow().SetData(resultsNameField, fileTreeBranch); + lines.Free(null); + } + } + else + ;//searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path); + } + app.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(); + + app.Lock(); + if(optionTree) + searchPanel.SortResults(); + if(optionBrowser) + searchPanel.SortBrowser(); + app.Unlock(); + + active = false; + + searchPanel.SearchTerminate(); + return 0; + } +} + +