libede: starting FileSystemSearch class based on old explorer SearchThread
[ede] / libede / src / FileSystemSearch.ec
diff --git a/libede/src/FileSystemSearch.ec b/libede/src/FileSystemSearch.ec
new file mode 100644 (file)
index 0000000..df805b0
--- /dev/null
@@ -0,0 +1,347 @@
+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;
+   }
+}
+
+