libede:FileSystemSearch: migration to FileSystemBox mostly done
[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
41    FileSystemSearch()
42    {
43       active = false;
44       terminate = false;
45    }
46
47    virtual bool Window::NotifyUpdateSearchLocation(FileSystemSearch search, char * location);
48    virtual bool Window::NotifySearchSortResults(FileSystemSearch search);
49    virtual bool Window::NotifySearchSortBrowser(FileSystemSearch search);
50    virtual bool Window::NotifySearchTerminated(FileSystemSearch search);
51
52    bool SearchFileContent(String path)
53    {
54       bool match = false;
55       File file = FileOpen(path, read);
56       if(file)
57       {
58          //
59          //   char line[65536];
60          //   char * find = null;
61          //   for( ; !find && file.GetLine(line, 65536) ; )
62          //      find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord);
63          //   //   find = strstr(line, contentSearch);
64          //
65
66          uint readCount = 16383;
67          char * find = null;
68          char buffer[16384];
69          int seekBack = 0 - strlen(contentSearch) - 2;
70          if(listLines)
71          {
72             uint line = 1;
73             while(readCount == 16383)
74             {
75                uint start = 0, len = 0;
76                readCount = file.Read(buffer, 1, 16383);
77                buffer[readCount] = '\0';
78                for( ; start < readCount; start += len ? len : 1)
79                {
80                   if( (len = strlen(&buffer[start])) )
81                   {
82                      char * newLine = buffer;
83                      uint bstart;
84                      find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
85
86                      // todo add a maximum line length possibility as param
87                      for(bstart = start; 
88                            bstart < readCount && newLine && (!find || newLine < find); 
89                               bstart += (newLine - &buffer[bstart]) / sizeof(char))
90                      {
91                         newLine = strstr(&buffer[bstart], "\n");
92                         newLine++;
93                         if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find))
94                            line++;
95                      }
96
97                      if(find)
98                      {
99                         len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch);
100                         match = true;
101                         if(!lines.first || ((NumberLink)lines.last).num != line)
102                            lines.Add(NumberLink { num = line });
103                      }
104
105                   }
106                }
107                file.Seek(seekBack, current);
108             }
109          }
110          else
111          {
112             for( ; !find && readCount == 16383; )
113             {
114                uint start = 0, len = 0;
115                readCount = file.Read(buffer, 1, 16383);
116                buffer[readCount] = '\0';
117                for( ; !find && start < readCount; start += len + 1)
118                   if( (len = strlen(&buffer[start])) )
119                      find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
120                file.Seek(seekBack, current);
121             }
122             match = (bool)find;
123          }
124          delete file;
125       }
126       return match;
127    }
128    
129    // I wonder if this is optimized at the c level to be compiled inline 
130    // and to use in-place in-stack memory for both the return value and the parameters
131    // if not, c should be more optimized...
132    // would the const have any impact on optimization?
133    unsigned int Main()
134    {
135       bool match;
136       int frame, stackTop = 0, treeTop = 0;
137       double lastTime = GetTime();
138       SearchStackFrame stack[1024];
139       //to be used for content replace... EditBox edit { multiLine = true, textHorzScroll = true, textVertScroll = true, maxLineSize = 65536 };
140
141       FileSystemNode node;
142       // This won't give drive attribs for c: or c:\ and other drives as well
143       // \\Nateus\data\ is not remote, etc...
144       // How to?
145       FileStats stats;
146       
147       terminate = false;
148       count = 0;
149       matchCount = 0;
150       
151       hasNameSearch = (strlen(nameSearch) != 0);
152       hasSizeSearch = false;  // this is temporary
153       hasContentSearch = (strlen(contentSearch) != 0);
154
155       listLines = true;
156       lines = OldList { };
157       
158       //SearchDir(location);
159
160       FileGetStats(location, stats);
161
162       strcpy(stack[0].path, location);
163       stack[0].listing = FileListing { stack[0].path };  // there should be a sorted = true/false 
164
165       fsb.list.Clear();
166                                                          // Binary Search sorting...
167       if(optionTree)
168          stack[0].branched = false;
169       /*if(optionBrowser)
170       {
171          guiApp.Lock();
172          {
173             //stack[0].browse = searchPanel.AddBrowserRow();
174             //node = MakeFileSystemNode(attribs, stack[0].path,
175             //      stack[0].path, fsb.bits.previewPictures, fsb.displaySystem);
176             //stack[0].browse.SetData(browserNameField, node);
177             //stack[0].browse.SetData(typeField, null);
178             //stack[0].browse.SetData(sizeField, null);
179
180             stack[0].browse = MakeFileSystemNode(stats, stack[0].path, stack[0].path,
181                   fsb.bits.previewPictures, fsb.displaySystem);
182             fsb.AddTreeNode(stack[0].browse, true, false, null); // TEMPORARY // searchPanel.AddBrowse(stack[0].browse, null);
183          }
184          guiApp.Unlock();
185       }*/
186       
187       for(frame = 0; frame >= 0 && !terminate; )
188       {
189          if(stack[frame].listing.Find())
190          {
191             count++;
192             
193             //match = (strcmp(stack[frame].listing.name, nameSearch) == 0);
194             //match = (stack[frame].listing.name[0] == nameSearch[0]);
195             //match = (bool)strstr(stack[frame].listing.name, nameSearch);
196                
197             if(hasNameSearch)
198                match = (bool)SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord);
199             else
200                match = true;
201
202             if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory)
203                if(!SearchFileContent(stack[frame].listing.path))
204                   match = false;
205
206             if(match)
207             {
208                matchCount++;
209                if(optionTree)
210                {
211                   for(frame = treeTop; frame <= stackTop; frame++)
212                   {
213                      if(!stack[frame].branched)
214                      {
215                         guiApp.Lock();
216                            if(frame)
217                            {
218                               stack[frame].result = MakeFileSystemNode(stack[frame - 1].listing.stats,
219                                     stack[frame - 1].listing.name, stack[frame - 1].path,
220                                     fsb.bits.previewPictures, fsb.displaySystem);
221                               fsb.AddTreeNode(stack[frame].result, true, false, stack[frame - 1].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[frame - 1].result);
222                               stack[frame].result.row.collapsed = false;
223                            }
224                            else
225                            {
226                               stack[0].result = MakeFileSystemNode(stats, stack[0].path, stack[0].path,
227                                     fsb.bits.previewPictures, fsb.displaySystem);
228                               fsb.AddTreeNode(stack[0].result, true, false, null); // TEMPORARY // searchPanel.AddResult(stack[0].result, null);
229                               stack[0].result.row.collapsed = false;
230                            }
231                            stack[frame].branched = true;
232                         guiApp.Unlock();
233                      }
234                   }
235                   treeTop = stackTop;
236                   frame--;
237                }
238             }
239             if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory)
240             {
241                guiApp.Lock();
242                   {
243                      double thisTime = GetTime();
244                      if(thisTime - lastTime > 0.25)
245                      {
246                         NotifyUpdateSearchLocation(owner, this, stack[stackTop].listing.path); // TEMPORARY // searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
247                         lastTime = thisTime;
248                      }
249                   }
250                   //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
251                   frame++;
252                   /*if(optionBrowser)
253                   {
254                      stack[frame].browse = MakeFileSystemNode(stack[stackTop].listing.stats,
255                            stack[stackTop].listing.name, stack[stackTop].path,
256                            fsb.bits.previewPictures, fsb.displaySystem);
257                      fsb.AddTreeNode(stack[frame].browse, true, false, stack[stackTop].browse); // TEMPORARY // searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse);
258
259                      if(frame)
260                         stack[frame].browse.row.collapsed = true;
261                      //if(frame == 1)
262                         //searchPanel.SortBrowser();  // this can be very bad for performance in some situations
263                                                 // there should be a way to sort the nodes as they are added
264                                                 // BinarySearch sorting implementation in listBox's Sort?
265                   }*/
266                guiApp.Unlock();
267                strcpy(stack[frame].path, stack[stackTop].listing.path);
268                stack[frame].listing = FileListing { stack[frame].path };
269                if(optionTree)
270                   stack[frame].branched = false;
271                if(match)
272                {
273                   guiApp.Lock();
274                      stack[frame].result = MakeFileSystemNode(stack[stackTop].listing.stats,
275                            stack[stackTop].listing.name, stack[stackTop].path,
276                            fsb.bits.previewPictures, fsb.displaySystem);
277                      if(optionTree)
278                      {
279                         fsb.AddTreeNode(stack[frame].result, true, false, stack[stackTop].result); // TEMPORARY // searchPanel.AddResult(stack[frame].result, stack[stackTop].result);
280                         stack[frame].result.row.collapsed = false;
281                         //searchPanel.SortResults();  // this can be very bad for performance in some situations
282                                                 // there should be a way to sort the nodes as they are added
283                                                 // BinarySearch sorting implementation in listBox's Sort?
284                         stack[frame].branched = true;
285                      }
286                      else
287                      {
288                         fsb.AddNode(stack[frame].result); //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path);
289                      }
290                   guiApp.Unlock();
291                }
292                stackTop++;
293             }
294             else
295             {
296                guiApp.Lock();
297                   /*if(optionBrowser)
298                   {
299                      FileSystemNode item;
300                      item = MakeFileSystemNode(stack[frame].listing.stats,
301                            stack[frame].listing.name, stack[frame].path,
302                            fsb.bits.previewPictures, fsb.displaySystem);
303                      fsb.AddTreeNode(item, true, false, stack[frame].browse); // TEMPORARY // searchPanel.AddBrowse(item, stack[frame].browse);
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                   if(match)
310                   {
311                      FileSystemNode item;
312                      item = MakeFileSystemNode(stack[frame].listing.stats,
313                            stack[frame].listing.name, stack[frame].path,
314                            fsb.bits.previewPictures, fsb.displaySystem);
315                      if(optionTree)
316                      {
317                         fsb.AddTreeNode(item, true, false, stack[frame].result); // TEMPORARY // searchPanel.AddResult(item, stack[frame].result);
318                         item.row.collapsed = false;
319                         //searchPanel.SortResults();  // this can be very bad for performance in some situations
320                                                 // there should be a way to sort the nodes as they are added
321                                                 // BinarySearch sorting implementation in listBox's Sort?
322
323                         if(listLines && lines.first)
324                         {
325                            NumberLink lin = lines.first;
326                            char temp[MAX_F_STRING];
327                            sprintf(temp, "lines %d", lin.num);
328                            for(lin = lin.next; lin && strlen(temp) < MAX_F_STRING; lin = lin.next)
329                               strcatf(temp, ", %d", lin.num);
330                            node = FileSystemNode { name = CopyString(temp), type = lineNumbers };
331                            fsb.AddTreeNode(node, true, false, item); // TEMPORARY // searchPanel.AddResult(node, item);
332                            //row.AddRow().SetData(resultsNameField, node);
333                            lines.Free(null);
334                         }
335                      }
336                      else
337                         fsb.AddNode(item); //searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path);
338                   }
339                guiApp.Unlock();
340             }
341          }
342          else
343          {
344             if(optionTree && stack[frame].branched && frame == treeTop)
345             {
346                stack[frame].branched = false;
347                treeTop--;
348             }
349             frame--;
350             stackTop--;
351          }
352       }
353       if(terminate)
354          for( ; frame >= 0 ; frame--)
355             stack[frame].listing.Stop();
356
357       guiApp.Lock();
358          if(optionTree)
359             NotifySearchSortResults(owner, this); // TEMPORARY // searchPanel.SortResults();
360          if(optionBrowser)
361             NotifySearchSortBrowser(owner, this); // TEMPORARY // searchPanel.SortBrowser();
362       guiApp.Unlock();
363
364       active = false;
365
366       guiApp.Lock();
367       NotifySearchTerminated(owner, this); // TEMPORARY // searchPanel.SearchTerminate();
368       guiApp.Unlock();
369       return 0;
370    }
371 }