libede & explorer: esthetics
[ede] / explorer / src / Search.ec
1 import "ExplorerTree"
2 import "Finder"
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    ExplorerFileBranch result;
20    ExplorerFileBranch browse;
21 };
22
23 class SearchThread : Thread
24 {
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;
31    OldList lines;
32    //DataField resultsNameField;
33    //DataField browserNameField;
34
35    ExplorerSearch searchPanel;
36
37    SearchThread()
38    {
39       active = false;
40       terminate = false;
41    }
42
43    bool SearchFileContent(String path)
44    {
45       bool match = false;
46       File file = FileOpen(path, read);
47       if(file)
48       {
49          //
50          //   char line[65536];
51          //   char * find = null;
52          //   for( ; !find && file.GetLine(line, 65536) ; )
53          //      find = SearchString(line, 0, contentSearch, optionContentMatchCase, optionContentMatchWord);
54          //   //   find = strstr(line, contentSearch);
55          //
56
57          uint readCount = 16383;
58          char * find = null;
59          char buffer[16384];
60          int seekBack = 0 - strlen(contentSearch) - 2;
61          if(listLines)
62          {
63             uint line = 1;
64             while(readCount == 16383)
65             {
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)
70                {
71                   if( (len = strlen(&buffer[start])) )
72                   {
73                      char * newLine = buffer;
74                      uint bstart;
75                      find = SearchString(buffer, start, contentSearch, optionContentMatchCase, optionContentMatchWord);
76
77                      // todo add a maximum line length possibility as param
78                      for(bstart = start; 
79                            bstart < readCount && newLine && (!find || newLine < find); 
80                               bstart += (newLine - &buffer[bstart]) / sizeof(char))
81                      {
82                         newLine = strstr(&buffer[bstart], "\n");
83                         newLine++;
84                         if(bstart + (newLine - &buffer[bstart]) / sizeof(char) < readCount && newLine && (!find || newLine < find))
85                            line++;
86                      }
87
88                      if(find)
89                      {
90                         len = (find - &buffer[start]) / sizeof(char) + strlen(contentSearch);
91                         match = true;
92                         if(!lines.first || ((NumberLink)lines.last).num != line)
93                            lines.Add(NumberLink { num = line });
94                      }
95
96                   }
97                }
98                file.Seek(seekBack, current);
99             }
100          }
101          else
102          {
103             for( ; !find && readCount == 16383; )
104             {
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);
112             }
113             match = (bool)find;
114          }
115          delete file;
116       }
117       return match;
118    }
119    
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?
124    unsigned int Main()
125    {
126       bool match;
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 };
131
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...
135       // How to?
136       FileStats stats;
137       
138       terminate = false;
139       count = 0;
140       matchCount = 0;
141       
142       hasNameSearch = (strlen(nameSearch) != 0);
143       hasSizeSearch = false;  // this is temporary
144       hasContentSearch = (strlen(contentSearch) != 0);
145
146       listLines = true;
147       lines = OldList { };
148       
149       //SearchDir(location);
150
151       FileGetStats(location, stats);
152
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...
156       if(optionTree)
157          stack[0].branched = false;
158       if(optionBrowser)
159       {
160          app.Lock();
161          {
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);
167
168             stack[0].browse = MakeFileBranch(stats, stack[0].path);
169             searchPanel.AddBrowse(stack[0].browse, null);
170          }
171          app.Unlock();
172       }
173       
174       for(frame = 0; frame >= 0 && !terminate; )
175       {
176          if(stack[frame].listing.Find())
177          {
178             count++;
179             
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);
183                
184             if(hasNameSearch)
185                match = (bool)SearchString(stack[frame].listing.name, 0, nameSearch, optionNameMatchCase, optionNameMatchWord);
186             else
187                match = true;
188
189             if(match && hasContentSearch && !stack[frame].listing.stats.attribs.isDirectory)
190                if(!SearchFileContent(stack[frame].listing.path))
191                   match = false;
192
193             if(match)
194             {
195                matchCount++;
196                if(optionTree)
197                {
198                   for(frame = treeTop; frame <= stackTop; frame++)
199                   {
200                      if(!stack[frame].branched)
201                      {
202                         app.Lock();
203                            if(frame)
204                            {
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;
208                            }
209                            else
210                            {
211                               stack[0].result = MakeFileBranch(stats, stack[0].path);
212                               searchPanel.AddResult(stack[0].result, null);
213                               stack[0].result.row.collapsed = false;
214                            }
215                            stack[frame].branched = true;
216                         app.Unlock();
217                      }
218                   }
219                   treeTop = stackTop;
220                   frame--;
221                }
222             }
223             if(optionSubdirs && stack[frame].listing.stats.attribs.isDirectory)
224             {
225                app.Lock();
226                   {
227                      double thisTime = GetTime();
228                      if(thisTime - lastTime > 0.25)
229                      {
230                         searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
231                         lastTime = thisTime;
232                      }
233                   }
234                   //searchPanel.SearchUpdateLabel(stack[stackTop].listing.path);
235                   frame++;
236                   if(optionBrowser)
237                   {
238                      stack[frame].browse = MakeFileBranch(stack[stackTop].listing.stats, stack[stackTop].listing.name);
239                      searchPanel.AddBrowse(stack[frame].browse, stack[stackTop].browse);
240
241                      if(frame)
242                         stack[frame].browse.row.collapsed = true;
243                      //if(frame == 1)
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?
247                   }
248                app.Unlock();
249                strcpy(stack[frame].path, stack[stackTop].listing.path);
250                stack[frame].listing = FileListing { stack[frame].path };
251                if(optionTree)
252                   stack[frame].branched = false;
253                if(match)
254                {
255                   app.Lock();
256                      if(optionTree)
257                      {
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;
265                      }
266                      else
267                      {
268                         //searchPanel.SearchAddResultsItem(stack[stackTop].listing.name, stack[stackTop].listing.path);
269                      }
270                   app.Unlock();
271                }
272                stackTop++;
273             }
274             else
275             {
276                app.Lock();
277                   if(optionBrowser)
278                   {
279                      ExplorerFileBranch item;
280                      item = MakeFileBranch(stack[frame].listing.stats, stack[frame].listing.name);
281                      searchPanel.AddBrowse(item, stack[frame].browse);
282                      //if(frame == 1)
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?
286                   }
287                   if(match)
288                   {
289                      if(optionTree)
290                      {
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?
298
299                         if(listLines && lines.first)
300                         {
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);
309                            lines.Free(null);
310                         }
311                      }
312                      else
313                         ;//searchPanel.SearchAddResultsItem(stack[frame].listing.name, stack[frame].listing.path);
314                   }
315                app.Unlock();
316             }
317          }
318          else
319          {
320             if(optionTree && stack[frame].branched && frame == treeTop)
321             {
322                stack[frame].branched = false;
323                treeTop--;
324             }
325             frame--;
326             stackTop--;
327          }
328       }
329       if(terminate)
330          for( ; frame >= 0 ; frame--)
331             stack[frame].listing.Stop();
332
333       app.Lock();
334          if(optionTree)
335             searchPanel.SortResults();
336          if(optionBrowser)
337             searchPanel.SortBrowser();
338       app.Unlock();
339
340       active = false;
341
342       searchPanel.SearchTerminate();
343       return 0;
344    }
345 }
346
347