--- /dev/null
+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;
+ }
+}
+
+