Here is what it look like in PB. To be able to do this I add directories in a stack directory structure.
Here is the code:
Code: Select all
;->Stack.pb
Structure TStackElement
*MptrData
*MptrNext.TStackElement
EndStructure
Structure TStack
*MptrFirst.TStackElement
EndStructure
Declare.l Stack_Init(*stack.TStack)
Declare.l Stack_Push(*stack.TStack, *ptrData)
Declare.l Stack_Pop(*stack.TStack)
Declare.l Stack_Clear(*stack.TStack)
Procedure.l Stack_Init(*stack.TStack)
If (*stack = 0) : ProcedureReturn(#False) : EndIf
*stack\MptrFirst = 0
ProcedureReturn(#True)
EndProcedure ;Procedure.l Stack_Init(*stack.TStack)
Procedure.l Stack_Push(*stack.TStack, *ptrData)
Protected *Lelement.TStackElement = 0
If(*stack = 0) : ProcedureReturn(#False) : EndIf
*Lelement = AllocateMemory(SizeOf(TStackElement))
If (*Lelement = 0) : ProcedureReturn(#False) : EndIf
*Lelement\MptrNext = *stack\MptrFirst
*Lelement\MptrData = *ptrData
*stack\MptrFirst = *Lelement
ProcedureReturn(#True)
EndProcedure ;Procedure.l Stack_Push(*stack.TStack, *ptrData)
Procedure.l Stack_Pop(*stack.TStack)
Protected *LptrFirstTemp.TStackElement = 0
If (*stack = 0) : ProcedureReturn(#False) : EndIf
If (*stack\MptrFirst = 0) : ProcedureReturn(#False) : EndIf
*LptrFirstTemp = *stack\MptrFirst
If (*LptrFirstTemp\MptrData <> 0) : FreeMemory(*LptrFirstTemp\MptrData) : EndIf
*stack\MptrFirst = *stack\MptrFirst\MptrNext
FreeMemory(*LptrFirstTemp)
ProcedureReturn(#True)
EndProcedure ;Procedure.l Stack_Pop(*stack.TStack)
Procedure.l Stack_Clear(*stack.TStack)
Protected LbooFnResult.l = #False
If (*stack = 0) : ProcedureReturn(#False) : EndIf
If (*stack\MptrFirst) : ProcedureReturn(#False) : EndIf
Repeat
LbooFnResult = Stack_Pop(*stack)
Until(*stack\MptrFirst = 0)
ProcedureReturn(#True)
EndProcedure ;Procedure.l Stack_Clear(*stack.TStack)
;->ScanDirStruct.pb
Structure TFileSysEntrie
MintDirectoryNumber.l
MdatCreated.l
MdatAccessed.l
MdatModified.l
MstrName.s
MbooIsDirectory.b
MqSize.q
MintAttributes.l
EndStructure
Structure TStructSearch
MstrPath.s
EndStructure
Prototype ProtoExecSearchHandler(*searchHandler, strPath.s, *entrieFileSys.TFileSysEntrie)
Structure TSearchHandler
Exec.ProtoExecSearchHandler
EndStructure
Enumeration
#CintGetNoEntrie
#CintGetFirstEntrie
#CintGetNextEntrie
EndEnumeration
Global GstrOSDirSep.s = ""
CompilerIf (#PB_Compiler_OS = #PB_OS_Linux) Or (#PB_Compiler_OS = #PB_OS_MacOS)
GstrOSDirSep = "/"
CompilerElse
GstrOSDirSep = "\"
CompilerEndIf
Declare.l __NameIsDotOrTwoDots(strName.s)
Declare.l __FillFileSysEntrie(intDirectoryNumber.l, *entrieFileSys.TFileSysEntrie, booNext.b = #False)
Declare.l __FindFirstFileSysEntrie(strPath.s, strFilter.s, *entrieFileSys.TFileSysEntrie)
Declare.l __FindNextFileSysEntrie(*entrieFileSys.TFileSysEntrie)
Declare.l __FindCloseFileSysEntrie(*entrieFileSys.TFileSysEntrie)
Declare.l ScanDirStruct(strPathDir.s, *searchHandler.TSearchHandler)
Procedure.l __NameIsDotOrTwoDots(strName.s)
Protected LstrDot.s = "."
Protected LstrTwoDots.s = ".."
Protected LbooIsDot.b = #False
Protected LbooIsTwoDots.b = #False
;If the name has no characters then return that the name received
;is not a "." or ".." string.
If Len(strName) = 0 : ProcedureReturn(#False) : EndIf
;If the size of the name received is the number of characters of LstrDot(which is 1) then
If Len(strName) = Len(LstrDot)
;If the name and LstrDot are the same then
;set that the name received is a "." string.
If CompareMemoryString(@strName, @LstrDot, #PB_String_NoCase, Len(LstrDot)) = #PB_String_Equal
LbooIsDot = #True
EndIf
EndIf ;If Len(strName) = Len(LstrDot)
;If the name is not a "." character then
If (LbooIsDot = #False)
;If the length of the name received is sam as the number of characeters of LstrDot(which is 2) then
If Len(strName) = Len(LstrTwoDots)
;If the name and LstrTowDots are the same then
;set that the name received is a ".." string.
If CompareMemoryString(@strName, @LstrTwoDots, #PB_String_NoCase, Len(LstrTwoDots)) = #PB_String_Equal
LbooIsTwoDots = #True
EndIf
EndIf ;If Len(strName) = Len(LTwoDots)
EndIf ;If (LbooIsDot = #False)
;Return if the name received is a "." or a ".." string.
ProcedureReturn((LbooIsDot = #True) Or (LbooIsTwoDots = #True))
EndProcedure ;Procedure.l __NameIsDotOrTwoDots(strName.s)
Procedure.l __FillFileSysEntrie(intDirectoryNumber.l, *entrieFileSys.TFileSysEntrie, booNext.b = #False)
;If the received file system entrie object is not a valid pointer
;then return that filling the system entrie object with the info
;of the current file system entrie examined failed.
If (*entrieFileSys = 0) : ProcedureReturn(#False) : EndIf
;If the received directory identify a invvalid directory then return that
;filling the file system entrie received failed.
If (IsDirectory(intDirectoryNumber) = 0) : ProcedureReturn(#False) : EndIf
;If it is specified to get the next directory entry and it is not possible to get it then
;return that filling file system entrie with the next entrie failed.
If (booNext = #True)
If (NextDirectoryEntry(intDirectoryNumber) = 0) : ProcedureReturn(#False) : EndIf
EndIf
;Assign the received directory number to the received file system entrie.
*entrieFileSys\MintDirectoryNumber = intDirectoryNumber
;Retrieve possible values of the current file system entrie and assign
;them to their respective members.
*entrieFileSys\MdatCreated = DirectoryEntryDate(intDirectoryNumber, #PB_Date_Created)
*entrieFileSys\MdatAccessed = DirectoryEntryDate(intDirectoryNumber, #PB_Date_Accessed)
*entrieFileSys\MdatModified = DirectoryEntryDate(intDirectoryNumber, #PB_Date_Modified)
*entrieFileSys\MstrName = DirectoryEntryName(intDirectoryNumber)
If (DirectoryEntryType(intDirectoryNumber) = #PB_DirectoryEntry_Directory)
*entrieFileSYs\MbooIsDirectory = #True
Else
*entrieFileSYs\MbooIsDirectory = #False
EndIf
*entrieFileSys\MqSize = DirectoryEntrySize(intDirectoryNumber)
*entrieFileSys\MintAttributes = DirectoryEntryAttributes(intDirectoryNumber)
;Return that filling the received file system entrie succeeded.
ProcedureReturn(#True)
EndProcedure ;Procedure.l __FillFileSysEntrie(intDirectoryNumber.l, *entrieFileSys.TFileSysEntrie, booNext.b =#False)
Procedure.l __FindFirstFileSysEntrie(strPath.s, strFilter.s, *entrieFileSys.TFileSysEntrie)
Protected LintDirectoryNumber.l = 0
Protected *LentrieFileSys.TFileSysEntrie = 0
Protected LbooFnResult.l = #False
;If the file system object is not a valid pointer then return
;that first entrie were not found.
If (*entrieFileSys = 0): ProcedureReturn(#False) : EndIf
;Try findinf first entrie in the received path.
LintDirectoryNumber = ExamineDirectory(#PB_Any, strPath, strFilter)
;If no entrie is found then return a invalid pointer
;as the first file system entrie found.
If (LintDirectoryNumber = 0) : ProcedureReturn(#False) : EndIf
;If the fist entrie in the directory were not found then
;close examination of the directory and return that nothing
;were found.
If (NextDirectoryEntry(LintDirectoryNumber) = 0)
FinishDirectory(LintDirectoryNumber)
ProcedureReturn(#False)
EndIf
;Retrieve information about current entrie examines by
;the opened directory list and assign them to the file
;system entrie object passed.
LbooFnResult = __FillFileSysEntrie(LintDirectoryNumber, *entrieFileSys)
;Return pointer to the first directory entrie of the directory
;list opened.
ProcedureReturn(#True)
EndProcedure ;Procedure.l __FindFirstFileSysEntrie(strPath.s, strFilter.s, *entrieFileSys.TFileSysEntrie)
Procedure.l __FindNextFileSysEntrie(*entrieFileSys.TFileSysEntrie)
;If the file system object is not a valid pointer then return
;that next entrie were not found.
If (*entrieFileSys = 0): ProcedureReturn(#False) : EndIf
;Try getting info of the next file system entrie and return
;if that were possible or not. #True is specified for booNext parameter to
;make the function call NextDirectoryEntry to move to the next file system entrie
;and get its info.
ProcedureReturn(__FillFileSysEntrie(*entrieFileSys\MintDirectoryNumber, *entrieFileSys, #True))
EndProcedure ;Procedure.l __FindNextFileSysEntrie(*entrieFileSys.TFileSysEntrie)
Procedure.l __FindCloseFileSysEntrie(*entrieFileSys.TFileSysEntrie)
;If the received file sytem entrie object is not a valid pointer then
;return that closing the directory list it contains failed.
If (*entrieFileSys = 0) : ProcedureReturn(#False) : EndIf
;If the directory number contained in the received file system entrie
;object is not valid directory list number then return that closing the directory list failed.
If (IsDirectory(*entrieFileSys\MintDirectoryNumber) = 0) : ProcedureReturn(#False) : EndIf
;Close opened directory list and clear members of the
;received file system entrie object.
FinishDirectory(*entrieFileSys\MintDirectoryNumber)
*entrieFileSys\MintDirectoryNumber = 0
*entrieFileSys\MdatCreated = 0
*entrieFileSys\MdatAccessed = 0
*entrieFileSys\MdatModified = 0
*entrieFileSys\MstrName = ""
*entrieFileSYs\MbooIsDirectory = #False
*entrieFileSys\MqSize = 0
*entrieFileSys\MintAttributes = 0
;Return that closing directory list of the received file system entrie succeeded.
ProcedureReturn(#True)
EndProcedure ;Procedure.l __FindCloseFileSysEntrie(*entrieFileSys.TFileSysEntrie)
Procedure.l ScanDirStruct(strPathDir.s, *searchHandler.TSearchHandler)
Shared GstrOSDirSep.s
Protected LstackDir.TStack
Protected LstrNewSearchDir.s = ""
Protected LentrieFileSys.TFileSysEntrie
Protected LstrPath.s = strPathDir
Protected LintAction.c = #CintGetNoEntrie
Protected LbooIsDirScanned.b = #False
Protected *LsearchElement.TStructSearch = 0
Protected LbooFnResult.l = #False
;If the received search handler is not a valid pointer then
;return tha scanning directory structure failed.
If (*searchHandler = 0) : ProcedureReturn(#False) : EndIf
;If the exec funtion of the search handler is not set then
;return that scanning directory structure failed.
If (*searchHandler\Exec = 0) : ProcedureReturn(#False) : EndIf
;Init the stack. This set the pointer *MptrFirst to 0.
LbooFnResult = Stack_Init(@LstackDir)
;If the first entrie of the received path can't be found then
;free memory allocated for the file system entrie and return
;that scanning directory structure failed.
If (__FindFirstFileSysEntrie(LstrPath, "*.*", @LentrieFileSys) = #False)
ProcedureReturn(#False)
EndIf
;If the first entrie found is a directory and is not "." or ".." then
If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Add the current path to the stack.
*LsearchElement = AllocateMemory(SizeOf(TStructSearch))
*LsearchElement\MstrPath = LstrPath + LentrieFileSys\MstrName + GstrOSDirSep
LbooFnResult = Stack_Push(@LstackDir, *LsearchElement)
;Execute the Exec function of the search handler by passing it
;the path and a pointer to the file system entrie found.
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
Else ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;If the file system entrie is not "." or ".." then execute the Exec function
;of the search handler by passing it the path and a pointer to the file system
;entrie found.
If (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
EndIf
EndIf ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Set to get the next file system entrie.
LintAction = #CintGetNextEntrie
;Scan until LintAction is equal to #CintGetNoEntrie
Repeat
;If FindFirst call needed then
If (LintAction = #CintGetFirstEntrie)
;If there is no entrie inside the directory then
If (__FindFirstFileSysEntrie(LstrPath, "*.*", @LentrieFileSys) = #False)
;Deallocate previous memory(by FindFirst Or FindNext).
LbooFnResult = __FindCloseFileSysEntrie(@LentrieFileSys)
;Get the first directory of the serarch stack And
;remove it from the stack.
If (LstackDir\MptrFirst <> 0)
;Get the saved path.
*LsearchElement = LstackDir\MptrFirst\MptrData
LstrPath = *LsearchElement\MstrPath
LbooFnResult = Stack_Pop(@LstackDir)
*LsearchElement = 0
;The stack serve only For directories, so
;we need an other call of FindFirst().
LintAction = #CintGetFirstEntrie
Else ;Else ;If (LstackDir\MptrFirst <> 0)
;All files and directory are scanned, so
;it is finished.
LintAction = #CintGetNoEntrie
LbooIsDirScanned = #True
EndIf ;Else ;If (LstackDir\MptrFirst <> 0)
Else ;Else ;If (__FindFirstFileSysEntrie(LstrPath, "*.*", @LentrieFileSys) = #False)
;Check current entrie is a directory but Not '.' or '..'
;because '.' go to the begining of the disk and '..' go
;to parent directory.
If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Add the current path to the stack.
*LsearchElement = AllocateMemory(SizeOf(TStructSearch))
*LsearchElement\MstrPath = LstrPath + LentrieFileSys\MstrName + GstrOSDirSep
LbooFnResult = Stack_Push(@LstackDir, *LsearchElement)
;Execute the Exec function of the search handler by passing it
;the path and a pointer to the file system entrie found.
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
Else ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;If the file system entrie is not "." or ".." then execute the Exec function
;of the search handler by passing it the path and a pointer to the file system
;entrie found.
If (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
EndIf
EndIf ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Set to get the next file system entrie.
LintAction = #CintGetNextEntrie
EndIf ;Else ;If (__FindFirstFileSysEntrie(LstrPath, "*.*", @LentrieFileSys) = #False)
Else ;Else ;If (intAction = #CintGetFirstEntrie)
;If a FindNext call is needed then
If (LintAction = #CintGetNextEntrie)
;If we can find a entrie in the directory then
If (__FindNextFileSysEntrie(@LentrieFileSys) = #True)
;Check current entrie is a directory but Not '.' or '..'
;because '.' go to the begining of the disk and '..' go
;to parent directory.
If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Add the current path to the stack.
*LsearchElement = AllocateMemory(SizeOf(TStructSearch))
*LsearchElement\MstrPath = LstrPath + LentrieFileSys\MstrName + GstrOSDirSep
LbooFnResult = Stack_Push(@LstackDir, *LsearchElement)
;Execute the Exec function of the search handler by passing it
;the path and a pointer to the file system entrie found.
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
Else ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) And (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;If the file system entrie is not "." or ".." then execute the Exec function
;of the search handler by passing it the path and a pointer to the file system
;entrie found.
If (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
*searchHandler\Exec(*searchHandler, LstrPath, @LentrieFileSys)
EndIf
EndIf ;Else ;If (LentrieFileSys\MbooIsDirectory = #True) (__NameIsDotOrTwoDots(LentrieFileSys\MstrName) = #False)
;Set to get the next file system entrie.
LintAction = #CintGetNextEntrie
Else ;Else ;If (__FindFirstFileSysEntrie(LstrPath, "*.*", @LentrieFileSys) = #False)
;Deallocate previous memory(by FindFirst Or FindNext).
LbooFnResult = __FindCloseFileSysEntrie(@LentrieFileSys)
;Get the first directory of the serarch stack And
;remove it from the stack.
If (LstackDir\MptrFirst <> 0)
;Get the saved path.
*LsearchElement = LstackDir\MptrFirst\MptrData
LstrPath = *LsearchElement\MstrPath
LbooFnResult = Stack_Pop(@LstackDir)
*LsearchElement = 0
;The stack serve only For directories, so
;we need an other call of FindFirst().
LintAction = #CintGetFirstEntrie
Else ;Else ;If (LstackDir\MptrFirst <> 0)
;All files and directory are scanned, so
;it is finished.
LintAction = #CintGetNoEntrie
LbooIsDirScanned = #True
EndIf ;Else ;If (LstackDir\MptrFirst <> 0)
EndIf ;Else ;If (__FindNextFileSysEntrie(@LentrieFileSys)
EndIf ;If (LintAction = #CintGetNextEntrie)
EndIf ;Else ;If (intAction = #CintGetFirstEntrie)
Until (LintAction = #CintGetNoEntrie) ;Repeat
;Return if the directory strucutre were scanned or not.
ProcedureReturn(LbooIsDirScanned)
EndProcedure ;Procedure.l ScanDirStruct(strPathDir.s, *searchHandler.TSearchHandler)
Global Gtest.TSearchHandler
Procedure Test(*searchHandler.TSearchHandler, strPath.s, *entrieFileSys.TFileSysEntrie)
Delay(1)
;If (*entrieFileSys\MbooIsDirectory = #False)
; PrintN(strPath + *entrieFileSys\MstrName)
;EndIf
EndProcedure
Gtest\Exec = @Test()
OpenConsole()
PrintN("[PRESS ESC]")
Repeat
Delay(1)
Until Inkey() = Chr(27)
ScanDirStruct(GstrOSDirSep + "usr" + GstrOSDirSep, @Gtest)
PrintN("[SCANNING FINISHED]")
PrintN("[PRESS ESC]")
Repeat
Delay(1)
Until Inkey() = Chr(27)