I want to make a file search function for my projects. I did a non-recursive search as it is faster because I don't need to pass a bunch of parameters between recursive calls. I am currently testing on Linux. I use an array of search descriptors. The maximum nesting depth of folders is 125. If each folder is 1 character long, the path will be 250 characters.
In the future I want to add parameters. The file filter can be set not only with a regular expression. Inversion: except for those specified in the filter. The output of the full or relative paths. Before you complicate it, what do you say about the concept, maybe there is something ready-made?
FileSearch.7z - source (Windows/Linux) + program (Linux)



Code:
; DisableDebugger
EnableExplicit
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
#sep$ = "\"
CompilerCase #PB_OS_Linux
#sep$ = "/"
CompilerEndSelect
Procedure __FileSearch2(sPath.s, List Files.s(), RID)
Protected sName.s, c = 0
Protected Dim aExaDir(125)
Protected Dim aSePath.s(125)
aSePath(c) = sPath
aExaDir(c) = ExamineDirectory(#PB_Any, sPath, "*")
If Not aExaDir(c)
ProcedureReturn
EndIf
Repeat
While NextDirectoryEntry(aExaDir(c))
sName=DirectoryEntryName(aExaDir(c))
If sName = "." Or sName = ".."
Continue
EndIf
If DirectoryEntryType(aExaDir(c)) = #PB_DirectoryEntry_Directory ; если путь является папкой, то
sPath = aSePath(c)
c + 1
; Debug c
aSePath(c) = sPath + sName + #sep$
; Debug "папка " + aSePath(c)
aExaDir(c) = ExamineDirectory(#PB_Any, aSePath(c), "*")
; Debug "+" + Str(c)
If Not aExaDir(c)
; Continue ; переходим к получению имени файла
; Else
c - 1
; aSePath(c) = sPath
EndIf
Else
If MatchRegularExpression(RID, sName) And AddElement(Files())
Files() = aSePath(c) + sName
; Files() = aSePath(c) + "|" + sName ; удобно обрабатывать рег.выр.-ом при наличии меток в файле
; Debug "файл " +sName
EndIf
EndIf
Wend
; Debug c
; Debug "-" + Str(c)
FinishDirectory(aExaDir(c))
c - 1
Until c < 0
EndProcedure
Procedure _FileSearch(*Result.string, Path$, Mask$ = ".+?")
Protected RID, Len, *Point
NewList Files.s() ; список для хранения путей
RID = CreateRegularExpression(#PB_Any, Mask$)
If RID
If Right(Path$, 1) <> #sep$
Path$ + #sep$
EndIf
__FileSearch2(Path$, Files.s(), RID)
FreeRegularExpression(RID)
Else
ProcedureReturn
Debug RegularExpressionError()
EndIf
Debug "Count = " + Str(ListSize(Files()))
Len=0
ForEach Files()
Len + Len(Files())+2 ; вычисляем длину данных для вмещения путей
Next
*Result\s = Space(Len) ; создаём строку забивая её пробелами
*Point = @*Result\s ; Получаем адрес строки
ForEach Files()
CopyMemoryString(Files()+#CRLF$, @*Point) ; копируем очередной путь в указатель
; CopyMemoryString(Files(), @*Point) ; копируем очередной путь в указатель
; CopyMemoryString(#CRLF$, @*Point) ; копируем очередной путь в указатель
Next
ClearList(Files()) ; очищаем список
; ProcedureReturn Res
EndProcedure
Define StartTime=ElapsedMilliseconds() ; метка времени
; Path$ = "C:\Музыка\" ; Создаёт список всех файлов и папок в домашнем каталоге.
Define Path$ = "/home/user"
; Define Path$ = "/home/user/"
; Result = ""
Define Result.string ; Объявили встроенную структуру string с именем Result и элементом структуры \s
; _FileSearch(@Result, Path$, "\A.*?\.mp3\z")
; _FileSearch(@Result, Path$, "\A.*?\.js\z")
; _FileSearch(@Result, Path$, "\A.*?\.pb\z")
_FileSearch(@Result, Path$, "\A.*?\.zip\z")
; Define Res.s = "Время выполнения функции = " + Str(ElapsedMilliseconds()-StartTime) + " мсек"
Define Res.s = "Time = " + Str(ElapsedMilliseconds()-StartTime) + " ms"
; EnableDebugger
Debug Res ; вывод данных о времени выполнения
Debug "_______________"
Debug Result\s
I wanted to use a variable instead of a structure in the outer scope, as in the example below, but it didn't work.
Code:
Procedure.s TrimRight(*a, n)
Protected *p.string = @*a
*p\s = Left(*p\s, Len(*p\s) - n)
EndProcedure
Define x.s = "Hello"
TrimRight(@x, 3)
Debug x