4 class NumberLink : struct
10 struct SearchStackFrame
13 char path[MAX_LOCATION];
19 ExplorerFileBranch result;
20 ExplorerFileBranch browse;
23 class SearchThread : Thread
25 bool active, terminate, hasNameSearch, hasSizeSearch, hasContentSearch, listLines;
26 int count, matchCount;
27 char location[MAX_LOCATION], nameSearch[1024], contentSearch[1024];
28 bool optionTree, optionBrowser, optionSubdirs;
29 bool optionNameMatchCase, optionNameMatchWord;
30 bool optionContentMatchCase, optionContentMatchWord;
32 //DataField resultsNameField;
33 //DataField browserNameField;
35 ExplorerSearch searchPanel;
43 bool SearchFileContent(String path)
46 File file = FileOpen(path, read);
51 // char * find = null;
52 // for( ; !find && file.GetLine(line, 65536) ; )
53 // find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord);
54 // // find = strstr(line, contentSearch);
57 uint readCount = 16383;
60 int seekBack = 0 - strlen(contentSearch) - 2;
64 while(readCount == 16383)
66 uint start = 0, len = 0;
67 readCount = file.Read(buffer, 1, 16383);
68 buffer[readCount] = '\0';
69 for( ; start < readCount; start += len ? len : 1)
71 if( (len = strlen(&buffer[start])) )
73 char * newLine = buffer;
75 find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
77 // todo add a maximum line length possibility as param
79 bstart < readCount && newLine && (!find || newLine < find);
80 bstart += (newLine - &buffer[bstart]) / sizeof(char))
82 newLine = strstr(&buffer[bstart], "\n");
84 if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find))
90 len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch);
92 if(!lines.first || ((NumberLink)lines.last).num != line)
93 lines.Add(NumberLink { num = line });
98 file.Seek(seekBack, current);
103 for( ; !find && readCount == 16383; )
105 uint start = 0, len = 0;
106 readCount = file.Read(buffer, 1, 16383);
107 buffer[readCount] = '\0';
108 for( ; !find && start < readCount; start += len + 1)
109 if( (len = strlen(&buffer[start])) )
110 find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
111 file.Seek(seekBack, current);
120 // I wonder if this is optimized at the c level to be compiled inline
121 // and to use in-place in-stack memory for both the return value and the parameters
122 // if not, c should be more optimized...
123 // would the const have any impact on optimization?
127 int frame, stackTop = 0, treeTop = 0;
128 double lastTime = GetTime();
129 SearchStackFrame stack[1024];
130 //to be used for content replace... EditBox edit { multiLine = true, textHorzScroll = true, textVertScroll = true, maxLineSize = 65536 };
132 ExplorerFileBranch fileTreeBranch;
133 // This won't give drive attribs for c: or c:\ and other drives as well
134 // \\Nateus\data\ is not remote, etc...
142 hasNameSearch = (strlen(nameSearch) != 0);
143 hasSizeSearch = false; // this is temporary
144 hasContentSearch = (strlen(contentSearch) != 0);
149 //SearchDir(location);
151 FileGetStats(location, stats);
153 strcpy(stack[0].path, location);
154 stack[0].listing = FileListing { stack[0].path }; // there should be a sorted = true/false
155 // Binary Search sorting...
157 stack[0].branched = false;
162 //stack[0].browse = searchPanel.AddBrowserRow();
163 //fileTreeBranch = MakeFileBranch(attribs, stack[0].path);
164 //stack[0].browse.SetData(browserNameField, fileTreeBranch);
165 //stack[0].browse.SetData(typeField, null);
166 //stack[0].browse.SetData(sizeField, null);
168 stack[0].browse = MakeFileBranch(stats, stack[0].path);
169 searchPanel.AddBrowse(stack[0].browse, null);
174 for(frame = 0; frame >= 0 && !terminate; )
176 if(stack[frame].listing.Find())
180 //match = (strcmp(stack[frame].listing.name, nameSearch) == 0);
181 //match = (stack[frame].listing.name[0] == nameSearch[0]);
182 //match = (bool)strstr(stack[frame].listing.name, nameSearch);
185 match = (bool)SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord);
189 if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory)
190 if(!SearchFileContent(stack[frame].listing.path))
198 for(frame = treeTop; frame <= stackTop; frame++)
200 if(!stack[frame].branched)
205 stack[frame].result = MakeFileBranch(stack[frame - 1].listing.stats, stack[frame - 1].listing.name);
206 searchPanel.AddResult(stack[frame].result, stack[frame - 1].result);
207 stack[frame].result.row.collapsed = false;
211 stack[0].result = MakeFileBranch(stats, stack[0].path);
212 searchPanel.AddResult(stack[0].result, null);
213 stack[0].result.row.collapsed = false;
215 stack[frame].branched = true;
223 if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory)
227 double thisTime = GetTime();
228 if(thisTime - lastTime > 0.25)
230 searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
234 //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
238 stack[frame].browse = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name);
239 searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse);
242 stack[frame].browse.row.collapsed = true;
244 //searchPanel.SortBrowser(); // this can be very bad for performance in some situations
245 // there should be a way to sort the nodes as they are added
246 // BinarySearch sorting implementation in listBox's Sort?
249 strcpy(stack[frame].path, stack[stackTop].listing.path);
250 stack[frame].listing = FileListing { stack[frame].path };
252 stack[frame].branched = false;
258 stack[frame].result = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name);
259 searchPanel.AddResult(stack[frame].result, stack[stackTop].result);
260 stack[frame].result.row.collapsed = false;
261 //searchPanel.SortResults(); // this can be very bad for performance in some situations
262 // there should be a way to sort the nodes as they are added
263 // BinarySearch sorting implementation in listBox's Sort?
264 stack[frame].branched = true;
268 //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path);
279 ExplorerFileBranch item;
280 item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name);
281 searchPanel.AddBrowse(item, stack[frame].browse);
283 //searchPanel.SortBrowser(); // this can be very bad for performance in some situations
284 // there should be a way to sort the nodes as they are added
285 // BinarySearch sorting implementation in listBox's Sort?
291 ExplorerFileBranch item;
292 item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name);
293 searchPanel.AddResult(item, stack[frame].result);
294 item.row.collapsed = false;
295 //searchPanel.SortResults(); // this can be very bad for performance in some situations
296 // there should be a way to sort the nodes as they are added
297 // BinarySearch sorting implementation in listBox's Sort?
299 if(listLines && lines.first)
301 NumberLink lin = lines.first;
302 char temp[MAX_F_STRING];
303 sprintf(temp, "lines %d", lin.num);
304 for(lin = lin.next; lin && strlen(temp) < MAX_F_STRING; lin = lin.next)
305 strcatf(temp, ", %d", lin.num);
306 fileTreeBranch = ExplorerFileBranch { name = CopyString(temp), type = lineNumbers };
307 searchPanel.AddResult(fileTreeBranch, item);
308 //row.AddRow().SetData(resultsNameField, fileTreeBranch);
313 ;//searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path);
320 if(optionTree && stack[frame].branched && frame == treeTop)
322 stack[frame].branched = false;
330 for( ; frame >= 0 ; frame--)
331 stack[frame].listing.Stop();
335 searchPanel.SortResults();
337 searchPanel.SortBrowser();
342 searchPanel.SearchTerminate();