Explorer; libede: Fixes to compile, warnings; fixed single window coming up when...
[ede] / libede / src / FileSystemSearch.ec
1 public import "ecere"
2 import "FileSystemBox"
3
4 class NumberLink : struct
5 {
6    NumberLink prev, next;
7    int num;
8 };
9
10 struct SearchStackFrame
11 {
12    int tag;
13    char path[MAX_LOCATION];
14    FileListing listing;
15
16    bool branched;
17    //DataRow result;
18    //DataRow browse;
19    FileSystemNode result;
20    FileSystemNode browse;
21 };
22
23 public class FileSystemSearch : Thread
24 {
25 public:
26    bool active, terminate, hasNameSearch, hasSizeSearch, hasContentSearch, listLines;
27    int count, matchCount;
28    char location[MAX_LOCATION], nameSearch[1024], contentSearch[1024];
29    bool optionTree, optionBrowser, optionSubdirs;
30    bool optionNameMatchCase, optionNameMatchWord;
31    bool optionContentMatchCase, optionContentMatchWord;
32    OldList lines;
33    //DataField resultsNameField;
34    //DataField browserNameField;
35
36    // TEMPORARY // ExplorerSearch searchPanel;
37
38    Window owner;
39    FileSystemBox fsb;
40    FileSystemBox tree;
41
42    FileSystemNode messageNode;
43
44    FileSystemSearch()
45    {
46       active = false;
47       terminate = false;
48    }
49
50    virtual bool Window::NotifyUpdateSearchLocation(FileSystemSearch search, const char * location);
51    virtual bool Window::NotifySearchSortResults(FileSystemSearch search);
52    virtual bool Window::NotifySearchSortBrowser(FileSystemSearch search);
53    virtual bool Window::NotifySearchTerminated(FileSystemSearch search);
54
55    void InitResults()
56    {
57       fsb.Clear();
58       //CreateMessageNode();
59       //messageNode.label = "No results yet!";
60    }
61
62
63
64    bool SearchFileContent(const String path)
65    {
66       bool match = false;
67       File file = FileOpen(path, read);
68       if(file)
69       {
70          //
71          //   char line[65536];
72          //   char * find = null;
73          //   for( ; !find && file.GetLine(line, 65536) ; )
74          //      find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord);
75          //   //   find = strstr(line, contentSearch);
76          //
77
78          uint readCount = 16383;
79          char * find = null;
80          char buffer[16384];
81          int seekBack = 0 - strlen(contentSearch) - 2;
82          if(listLines)
83          {
84             uint line = 1;
85             while(readCount == 16383)
86             {
87                uint start = 0, len = 0;
88                readCount = file.Read(buffer, 1, 16383);
89                buffer[readCount] = '\0';
90                for( ; start < readCount; start += len ? len : 1)
91                {
92                   if( (len = strlen(&buffer[start])) )
93                   {
94                      char * newLine = buffer;
95                      uint bstart;
96                      find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
97
98                      // todo add a maximum line length possibility as param
99                      for(bstart = start;
100                            bstart < readCount && newLine && (!find || newLine < find);
101                               bstart += (newLine - &buffer[bstart]) / sizeof(char))
102                      {
103                         newLine = strstr(&buffer[bstart], "\n");
104                         newLine++;
105                         if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find))
106                            line++;
107                      }
108
109                      if(find)
110                      {
111                         len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch);
112                         match = true;
113                         if(!lines.first || ((NumberLink)lines.last).num != line)
114                            lines.Add(NumberLink { num = line });
115                      }
116
117                   }
118                }
119                file.Seek(seekBack, current);
120             }
121          }
122          else
123          {
124             for( ; !find && readCount == 16383; )
125             {
126                uint start = 0, len = 0;
127                readCount = file.Read(buffer, 1, 16383);
128                buffer[readCount] = '\0';
129                for( ; !find && start < readCount; start += len + 1)
130                   if( (len = strlen(&buffer[start])) )
131                      find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
132                file.Seek(seekBack, current);
133             }
134             match = find != null;
135          }
136          delete file;
137       }
138       return match;
139    }
140
141    // I wonder if this is optimized at the c level to be compiled inline
142    // and to use in-place in-stack memory for both the return value and the parameters
143    // if not, c should be more optimized...
144    // would the const have any impact on optimization?
145    unsigned int Main()
146    {
147       bool match;
148       int frame, stackTop = 0, treeTop = 0;
149       double lastTime = GetTime();
150       SearchStackFrame stack[1024];
151       //to be used for content replace... EditBox edit { multiLine = true, textHorzScroll = true, textVertScroll = true, maxLineSize = 65536 };
152
153       FileSystemNode node;
154       // This won't give drive attribs for c: or c:\ and other drives as well
155       // \\Nateus\data\ is not remote, etc...
156       // How to?
157       FileStats stats;
158
159       terminate = false;
160       count = 0;
161       matchCount = 0;
162
163       hasNameSearch = (strlen(nameSearch) != 0);
164       hasSizeSearch = false;  // this is temporary
165       hasContentSearch = (strlen(contentSearch) != 0);
166
167       listLines = true;
168       lines = OldList { };
169
170       //SearchDir(location);
171
172       FileGetStats(location, stats);
173
174       strcpy(stack[0].path, location);
175       stack[0].listing = FileListing { stack[0].path };  // there should be a sorted = true/false
176
177       //fsb.list.Clear();
178                                                          // Binary Search sorting...
179       if(optionTree)
180          stack[0].branched = false;
181       if(optionBrowser)
182       {
183          guiApp.Lock();
184          {
185             //stack[0].browse = searchPanel.AddBrowserRow();
186             //DeleteMessageNode();
187             //node = MakeFileSystemNode(attribs, stack[0].path, true,
188             //      stack[0].path, fsb.bits.previewPictures, fsb.displaySystem);
189             //stack[0].browse.SetData(browserNameField, node);
190             //stack[0].browse.SetData(typeField, null);
191             //stack[0].browse.SetData(sizeField, null);
192
193             //DeleteMessageNode();
194             tree.Clear();
195             stack[0].browse = MakeFileSystemNode(stats, stack[0].path, stack[0].path, false,
196                   tree.bits.previewPictures, false, tree.displaySystem);
197             tree.AddTreeNode(stack[0].browse, false, true, true, null); // TEMPORARY // searchPanel.AddBrowse(stack[0].browse, null);
198          }
199          guiApp.Unlock();
200       }
201
202       for(frame = 0; frame >= 0 && !terminate; )
203       {
204          guiApp.Lock();
205          {
206             double thisTime = GetTime();
207             if(thisTime - lastTime > 0.25)
208             {
209                NotifyUpdateSearchLocation(owner, this, stack[frame].listing.path); // TEMPORARY // searchPanel.SearchUpdateLabel(stack[frame].listing.path);
210                //if(!messageNode)
211                //   CreateMessageNode();
212                //delete messageNode.label;
213                //messageNode.label = PrintString("Searching '", stack[frame].listing.path, "'...");
214                //messageNode.EnsureVisible(false);
215                //fsb.Select(messageNode);
216                //fsb.Update(null);
217                //guiApp.UpdateDisplay();
218                lastTime = thisTime;
219             }
220          }
221          guiApp.Unlock();
222          if(stack[frame].listing.Find())
223          {
224             count++;
225
226             //match = (strcmp(stack[frame].listing.name, nameSearch) == 0);
227             //match = (stack[frame].listing.name[0] == nameSearch[0]);
228             //match = (bool)strstr(stack[frame].listing.name, nameSearch);
229
230             if(hasNameSearch)
231                match = SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord) != null;
232             else
233                match = true;
234
235             if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory)
236                if(!SearchFileContent(stack[frame].listing.path))
237                   match = false;
238
239             if(match)
240             {
241                matchCount++;
242                if(optionTree)
243                {
244                   for(frame = treeTop; frame <= stackTop; frame++)
245                   {
246                      if(!stack[frame].branched)
247                      {
248                         guiApp.Lock();
249                            if(frame)
250                            {
251                               DeleteMessageNode();
252                               stack[frame].result = MakeFileSystemNode(stack[frame - 1].listing.stats,
253                                     stack[frame - 1].listing.name, stack[frame - 1].path, true,
254                                     fsb.bits.previewPictures, false, fsb.displaySystem);
255                               fsb.AddTreeNode(stack[frame].result, true, true, false, stack[frame - 1].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[frame - 1].result);
256                               stack[frame].result.row.collapsed = false;
257                            }
258                            else
259                            {
260                               DeleteMessageNode();
261                               stack[0].result = MakeFileSystemNode(stats, stack[0].path, stack[0].path, true,
262                                     fsb.bits.previewPictures, false, fsb.displaySystem);
263                               fsb.AddTreeNode(stack[0].result, true, true, false, null); // TEMPORARY // searchPanel.AddResult(stack[0].result, null);
264                               stack[0].result.row.collapsed = false;
265                            }
266                            stack[frame].branched = true;
267                         guiApp.Unlock();
268                      }
269                   }
270                   treeTop = stackTop;
271                   frame--;
272                }
273             }
274             if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory)
275             {
276                /*guiApp.Lock();
277                   {
278                      double thisTime = GetTime();
279                      if(thisTime - lastTime > 0.25)
280                      {
281                         NotifyUpdateSearchLocation(owner, this, stack[stackTop].listing.path); // TEMPORARY // searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
282                         if(!messageNode)
283                            CreateMessageNode();
284                         //delete messageNode.label;
285                         messageNode.label = PrintString("Searching '", stack[stackTop].listing.path, "'...");
286                         messageNode.EnsureVisible(false);
287                         fsb.Update(null);
288                         guiApp.UpdateDisplay();
289                         lastTime = thisTime;
290                      }
291                   }
292                   //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);*/
293                   frame++;
294                /*   /-*if(optionBrowser)
295                   {
296                      DeleteMessageNode();
297                      stack[frame].browse = MakeFileSystemNode(stack[stackTop].listing.stats,
298                            stack[stackTop].listing.name, stack[stackTop].path, true,
299                            fsb.bits.previewPictures, fsb.displaySystem);
300                      fsb.AddTreeNode(stack[frame].browse, true, true, false, stack[stackTop].browse); // TEMPORARY // searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse);
301
302                      if(frame)
303                         stack[frame].browse.row.collapsed = true;
304                      //if(frame == 1)
305                         //searchPanel.SortBrowser();  // this can be very bad for performance in some situations
306                                                 // there should be a way to sort the nodes as they are added
307                                                 // BinarySearch sorting implementation in listBox's Sort?
308                   }*-/
309                guiApp.Unlock();*/
310                strcpy(stack[frame].path, stack[stackTop].listing.path);
311                stack[frame].listing = FileListing { stack[frame].path };
312                if(optionTree)
313                   stack[frame].branched = false;
314                if(match)
315                {
316                   guiApp.Lock();
317                      DeleteMessageNode();
318                      stack[frame].result = MakeFileSystemNode(stack[stackTop].listing.stats,
319                            stack[stackTop].listing.name, stack[stackTop].path, true,
320                            fsb.bits.previewPictures, false, fsb.displaySystem);
321                      if(optionTree)
322                      {
323                         fsb.AddTreeNode(stack[frame].result, true, true, false, stack[stackTop].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[stackTop].result);
324                         stack[frame].result.row.collapsed = false;
325                         //searchPanel.SortResults();  // this can be very bad for performance in some situations
326                                                 // there should be a way to sort the nodes as they are added
327                                                 // BinarySearch sorting implementation in listBox's Sort?
328                         stack[frame].branched = true;
329                      }
330                      else
331                      {
332                         fsb.AddNode(stack[frame].result); //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path);
333                      }
334                   guiApp.Unlock();
335                }
336                stackTop++;
337             }
338             else
339             {
340                guiApp.Lock();
341                   /*if(optionBrowser)
342                   {
343                      FileSystemNode item;
344                      DeleteMessageNode();
345                      item = MakeFileSystemNode(stack[frame].listing.stats,
346                            stack[frame].listing.name, stack[frame].path, true,
347                            fsb.bits.previewPictures, fsb.displaySystem);
348                      fsb.AddTreeNode(item, true, true, false, stack[frame].browse); // TEMPORARY // searchPanel.AddBrowse(item, stack[frame].browse);
349                      //if(frame == 1)
350                         //searchPanel.SortBrowser();  // this can be very bad for performance in some situations
351                                                 // there should be a way to sort the nodes as they are added
352                                                 // BinarySearch sorting implementation in listBox's Sort?
353                   }*/
354                   if(match)
355                   {
356                      FileSystemNode item;
357                      DeleteMessageNode();
358                      item = MakeFileSystemNode(stack[frame].listing.stats,
359                            stack[frame].listing.name, stack[frame].path, true,
360                            fsb.bits.previewPictures, false, fsb.displaySystem);
361                      if(optionTree)
362                      {
363                         fsb.AddTreeNode(item, true, true, false, stack[frame].result); // TEMPORARY // searchPanel.AddResult(item, stack[frame].result);
364                         item.row.collapsed = false;
365                         //searchPanel.SortResults();  // this can be very bad for performance in some situations
366                                                 // there should be a way to sort the nodes as they are added
367                                                 // BinarySearch sorting implementation in listBox's Sort?
368
369                         if(listLines && lines.first)
370                         {
371                            NumberLink lin = lines.first;
372                            char temp[MAX_F_STRING];
373                            sprintf(temp, "lines %d", lin.num);
374                            for(lin = lin.next; lin && strlen(temp) < MAX_F_STRING; lin = lin.next)
375                               strcatf(temp, ", %d", lin.num);
376                            node = FileSystemNode { name = temp/*CopyString(temp)*/, type = lineNumbers };
377                            fsb.AddTreeNode(node, true, true, false, item); // TEMPORARY // searchPanel.AddResult(node, item);
378                            //row.AddRow().SetData(resultsNameField, node);
379                            lines.Free(null);
380                         }
381                      }
382                      else
383                         fsb.AddNode(item); //searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path);
384                   }
385                guiApp.Unlock();
386             }
387          }
388          else
389          {
390             if(optionTree && stack[frame].branched && frame == treeTop)
391             {
392                stack[frame].branched = false;
393                treeTop--;
394             }
395             frame--;
396             stackTop--;
397          }
398       }
399       if(terminate)
400          for( ; frame >= 0 ; frame--)
401             stack[frame].listing.Stop();
402
403       guiApp.Lock();
404          if(optionTree)
405             NotifySearchSortResults(owner, this); // TEMPORARY // searchPanel.SortResults();
406          if(optionBrowser)
407             NotifySearchSortBrowser(owner, this); // TEMPORARY // searchPanel.SortBrowser();
408       guiApp.Unlock();
409
410       active = false;
411
412       guiApp.Lock();
413       NotifySearchTerminated(owner, this); // TEMPORARY // searchPanel.SearchTerminate();
414       //delete messageNode.label;
415       //messageNode.label = PrintString("Searching '", stack[stackTop].listing.path, "'...");
416       //delete the messageNode;
417       //fsb.Update(null);
418       guiApp.Unlock();
419       return 0;
420    }
421
422 private:
423    void CreateMessageNode()
424    {
425       //messageNode = MakeFileSystemNode({ }, " ", " ", false, false, fsb.displaySystem);
426       //messageNode.type = normalFile;
427       //fsb.AddNode(messageNode);
428    }
429    void DeleteMessageNode()
430    {
431       //if(messageNode)
432       //   fsb.DeleteNode(messageNode);
433       //messageNode = null;
434    }
435 }