Sign in to follow this  
Followers 0
slandau

Recursion error

9 posts in this topic

So I'm getting a recursion error with my script. Here is the error it's spitting out:

>"C:\Program Files (x86)\AutoIt3\SciTE\..\autoit3.exe" /ErrorStdOut "C:\Users\Scott\Documents\AutoItScripts\archive_tool.au3"

C:\Users\Scott\Documents\AutoItScripts\archive_tool.au3 (52) : ==> Recursion level has been exceeded - AutoIt will quit to prevent stack overflow.:

Local $fileList = _FileListToArray($dir)

>Exit code: 1 Time: 23.433

And here is my script:

;Tool to archive files with specific extensions grouped by that extension and kept in same file structure
;Will also keep original files in tact
;@Author - Scott Landau
;@Created - 5/23/2010
;@Last Edited - 5/23/2010

;Includes
#include <File.au3>
#include <Array.au3>
#include <Zip.au3>

;Globals
Local $tempExts = "txt|doc|cpp"
Local $arrayExts = StringSplit($tempExts, "|")

;Methods
;Get the root directory for the archive
;@Return String
Func getRoot()
    Local $root = InputBox("Root Directory", "Please enter the starting directory for the archive process...")
    Return $root
EndFunc

;Gets all the subdirectories of the given directory
;@Param String
;@Return Array
Func getAllDirs($dir)
    Local $added = 0
    Local $dirs[1]
    Local $fileList = _FileListToArray($dir)
    Local $size = UBound($fileList)
    For $i = 0 to $size - 1
        Local $pos = StringInStr($fileList[$i], ".")
        If ($pos == 0) Then
            If ($added == 0) Then
                $added = 1
                $dirs[0] = $fileList[$i]
            Else
                _ArrayAdd($dirs, $fileList[$i])
            EndIf
        EndIf
    Next
    Return $dirs
EndFunc

;Gets all the files of the given directory
;@Param String
;@Return Array
Func getAllFiles($dir)
    Local $added = 0
    Local $files[1]
    Local $fileList = _FileListToArray($dir)
    Local $size = UBound($fileList)
    For $i = 0 to $size - 1
        Local $pos = StringInStr($fileList[$i], ".")
        If Not ($pos == 0) Then
            If ($added == 0) Then
                $added = 1
                $files[0] = $fileList[$i]
            Else
                _ArrayAdd($files, $fileList[$i])
            EndIf
        EndIf
    Next
    Return $files
EndFunc

;Get the file extension
;@Param String
;@Return String
Func getExt($file)
    Local $ext
    Local $pos = StringInStr($file, ".")
    $ext = StringTrimLeft($file, $pos)
    Return $ext
EndFunc

;Is bad extension?
;@Param String
;@Return Int
Func isBad($file)
    Local $retval
    Local $ext = getExt($file)
    Local $pos = _ArraySearch($arrayExts, $ext)
    If Not ($pos == -1) Then
        $retval = 1
    Else
        $retval = 0
    EndIf
    Return $retval
EndFunc

;Get all file extensions in current directory
;@Param String
;@Return Array
Func getAllExts($dir)
    Local $added = 0
    Local $allExts[1]
    Local $files = getAllFiles($dir)
    Local $max = UBound($files)
    For $i = 0 to $max - 1
        Local $ext = getExt($files[$i])
        If ($added == 0) Then
            $allExts[0] = $ext
            $added = 1
        Else
            _ArrayAdd($allExts, $ext)
        EndIf
    Next
EndFunc

;Actual archiving algorithm
;@Param String
Func algorithm($dir)
    Local $dirs = getAllDirs($dir)
    Local $files = getAllFiles($dir)
    Local $allExts = getAllExts($dir)
    
    Local $numExts = UBound($arrayExts)
    Local $numFiles = UBound($files)
    
    For $i = 0 to $numExts - 1
        Local $pos = _ArraySearch($allExts, $arrayExts[$i])
        If Not ($pos == -1) Then
            $zip = _Zip_Create(@WorkingDir & "\" & $arrayExts[$i] & "_zip.zip")
            For $j = 0 to $numFiles - 1
                Local $fileExt = getExt($files[$j])
                If ($fileExt == $arrayExts[$i]) Then
                    _Zip_AddFile($zip, $files[$j])
                EndIf
            Next
        EndIf
    Next
    
    Local $numDirs = UBound($dirs)
    For $k = 0 to $numDirs - 1
        algorithm($dirs[$k])
    Next
    
EndFunc

;Main archiving function to be run in 'Main' comment field
;Void
Func main()
    
    Local $root = getRoot()
    
    algorithm($root)
    
EndFunc

;Main
main()

As you can see there is a recursive call to itself within the algorithm($dir) method, however it is within a for loop meaning it should only call it if a number of directories exist. If none exist, it shouldn't call it at all so that should be the 'exit' to that recursion, so I don't know why it's giving me an error.

Any ideas?

Share this post


Link to post
Share on other sites



Be aware that:

-) a directory name can contain (and even consist of) one or more dots

-) a file name can contain one or more dots

-) files can be extensionless.

That alone undermines the behavior of your script in the general case.

Also _FileListToArray doesn't return the full path, but can be passed a parameter to list directories or files (or both).

Then you should probably be using the FileSelectFolder dialog to grab your root directory name.

Better use the search feature to locate recent Melba23's recurvive directory traversal and build from there, or weaponx'.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

Still haven't figured out why your script recurs so much but what I did find is that the error message occurs during a getAllFiles call. I tried following the function calls a bit and it seems to be just a continuous loop of calls consisting of: algorithm, getAllDirs, getAllFiles, getAllExts, getAllFile... Dunno what it looks like in recursion levels though.

I do agree that it would be much better for you to start off with a working search script then modify it or use it to your purpose. There are some quick recursive and stack-based search scripts here in the forums which can give full paths and filter between files and folders. Or, if you are feeling industrious for some reason, you can simply code one on your own. It's not make-your-brain-melt difficult to do.

Share this post


Link to post
Share on other sites

Be aware that:

-) a directory name can contain (and even consist of) one or more dots

-) a file name can contain one or more dots

-) files can be extensionless.

That alone undermines the behavior of your script in the general case.

Also _FileListToArray doesn't return the full path, but can be passed a parameter to list directories or files (or both).

Then you should probably be using the FileSelectFolder dialog to grab your root directory name.

Better use the search feature to locate recent Melba23's recurvive directory traversal and build from there, or weaponx'.

I made a couple changes. Added the parameter with _FileListToArray, and have the user pick a folder now instead of type in a directory. However, now it doesn't even run.

;Tool to archive files with specific extensions grouped by that extension and kept in same file structure
;Will also keep original files in tact
;@Author - Scott Landau
;@Created - 5/23/2010
;@Last Edited - 5/23/2010

;Includes
#include <File.au3>
#include <Array.au3>
#include <Zip.au3>

;Globals
Local $tempExts="ade|adp|app|asa|ashx|asp|bas|bat|cdx|cer|chm|class|cmd|com|cpl|crt|csh|der|exe|fxp|gadget|hlp|hta|htr|htw|ida|idc|idq|ins|isp|its|jse|ksh|lnk|mad|maf|mag|mam|maq|mar|mas|mat|mau|mav|maw|mda|mdb|mde|mdt|mdw|mdz|msc|msh|msh1|msh1xml|msh2|msh2xml|mshxml|msi|msp|mst|ops|pcd|pif|prf|prg|printer|pst|reg|rem|scf|scr|sct|shb|shs|shtm|shtml|soap|stm|url|vb|vbe|vbs|ws|wsc|wsf|wsh"
Local $arrayExts = StringSplit($tempExts, "|")

;Methods
;Get the root directory for the archive
;@Return String
Func getRoot()
    Local $root = FileSelectFolder("Select Root:", "C:\")
    Return $root
EndFunc

;Gets all the subdirectories of the given directory
;@Param String
;@Return Array
Func getAllDirs($dir)
    Local $folderList = _FileListToArray($dir, "*", 2)
    Return $folderList
EndFunc

;Gets all the files of the given directory
;@Param String
;@Return Array
Func getAllFiles($dir)
    Local $fileList = _FileListToArray($dir, "*", 1)
    Return $fileList
EndFunc

;Get the file extension
;@Param String
;@Return String
Func getExt($file)
    Local $ext
    Local $pos = StringInStr($file, ".")
    $ext = StringTrimLeft($file, $pos)
    Return $ext
EndFunc

;Is bad extension?
;@Param String
;@Return Int
Func isBad($file)
    Local $retval
    Local $ext = getExt($file)
    Local $pos = _ArraySearch($arrayExts, $ext)
    If Not ($pos == -1) Then
        $retval = 1
    Else
        $retval = 0
    EndIf
    Return $retval
EndFunc

;Get all file extensions in current directory
;@Param String
;@Return Array
Func getAllExts($dir)
    Local $added = 0
    Local $allExts[1]
    Local $files = getAllFiles($dir)
    Local $max = UBound($files)
    For $i = 0 to $max - 1
        Local $ext = getExt($files[$i])
        If ($added == 0) Then
            $allExts[0] = $ext
            $added = 1
        Else
            _ArrayAdd($allExts, $ext)
        EndIf
    Next
EndFunc

;Actual archiving algorithm
;@Param String
Func algorithm($dir)
    Local $dirs = getAllDirs($dir)
    Local $files = getAllFiles($dir)
    Local $allExts = getAllExts($dir)
    
    Local $numExts = UBound($arrayExts)
    Local $numFiles = UBound($files)
    
    For $i = 0 to $numExts - 1
        Local $pos = _ArraySearch($allExts, $arrayExts[$i])
        If Not ($pos == -1) Then
            $zip = _Zip_Create(@WorkingDir & "\" & $arrayExts[$i] & "_zip.zip")
            For $j = 0 to $numFiles - 1
                Local $fileExt = getExt($files[$j])
                If ($fileExt == $arrayExts[$i]) Then
                    _Zip_AddFile($zip, $files[$j])
                EndIf
            Next
        EndIf
    Next
    
    Local $numDirs = UBound($dirs)
    For $k = 0 to $numDirs - 1
        algorithm($dirs[$k])
    Next
    
EndFunc

;Main archiving function to be run in 'Main' comment field
;Void
Func main()
    
    Local $root = getRoot()
    
    algorithm($root)
    
EndFunc

;Main
main()

Share this post


Link to post
Share on other sites

What is #include <Zip.au3> ?

If a remove that the script compiles...

Share this post


Link to post
Share on other sites

What is #include <Zip.au3> ?

If a remove that the script compiles...

It compiles no matter what. It just doesn't do anything (not even error) anymore after choosing the directory and running the script.

#include <Zip.au3> is required for the archiving process.

Share this post


Link to post
Share on other sites

I always found stepping it out on paper to be most beneficial. Play the computer and step though it line by line. In the end it will save you lots of time. :idea:


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

I modified your script a bit to make tracking it a little easier. Apparently, your 'algorithm' function keeps recurring repeatedly even for a shallow folder containing few files.

Modified script:

;Tool to archive files with specific extensions grouped by that extension and kept in same file structure
;Will also keep original files in tact
;@Author - Scott Landau
;@Created - 5/23/2010
;@Last Edited - 5/23/2010

;Includes
#include <File.au3>
#include <Array.au3>
;#include <Zip.au3>

;Globals
Local $tempExts = "txt|doc|cpp"
Local $arrayExts = StringSplit($tempExts, "|")

;counters for functions
Global $getAllDirs = 0, $getAllFiles = 0, $getAllExts = 0, $algorithm = 0
;log file location
Global $logpath = @DesktopDir & "\board.txt"

;writes line to log file
Func _WriteLog($msg)
    $fhandle = FileOpen($logpath, 9)
    FileWriteLine($fhandle, $msg)
    FileClose($fhandle)
EndFunc

;Methods
;Get the root directory for the archive
;@Return String
Func getRoot()
    Local $root = InputBox("Root Directory", "Please enter the starting directory for the archive process...")
    Return $root
EndFunc

;Gets all the subdirectories of the given directory
;@Param String
;@Return Array
Func getAllDirs($dir1)
    ;write count to log file
    _WriteLog("getAllDirs" & @TAB & $getAllDirs)
    ;increase count by 1 on function start
    $getAllDirs += 1
    Local $added = 0
    Local $dirs[1]
    Local $fileList = _FileListToArray($dir1)
    Local $size = UBound($fileList)
    For $i = 0 to $size - 1
        Local $pos = StringInStr($fileList[$i], ".")
        If ($pos == 0) Then
            If ($added == 0) Then
                $added = 1
                $dirs[0] = $fileList[$i]
            Else
                _ArrayAdd($dirs, $fileList[$i])
            EndIf
        EndIf
    Next
    ;decrease count by 1 one function exit
    $getAllDirs -= 1
   Return $dirs
EndFunc

;Gets all the files of the given directory
;@Param String
;@Return Array
Func getAllFiles($dir2)
    _WriteLog("getAllFiles" & @TAB & $getAllFiles)
    $getAllFiles += 1
    Local $added = 0
    Local $files[1]
    Local $fileList = _FileListToArray($dir2)
    Local $size = UBound($fileList)
    For $i = 0 to $size - 1
        Local $pos = StringInStr($fileList[$i], ".")
        If Not ($pos == 0) Then
            If ($added == 0) Then
                $added = 1
                $files[0] = $fileList[$i]
            Else
                _ArrayAdd($files, $fileList[$i])
            EndIf
        EndIf
    Next
    $getAllFiles -= 1
    Return $files
EndFunc

;Get the file extension
;@Param String
;@Return String
Func getExt($file)
    Local $ext
    Local $pos = StringInStr($file, ".")
    $ext = StringTrimLeft($file, $pos)
    Return $ext
EndFunc

;Is bad extension?
;@Param String
;@Return Int
Func isBad($file)
    Local $retval
    Local $ext = getExt($file)
    Local $pos = _ArraySearch($arrayExts, $ext)
    If Not ($pos == -1) Then
        $retval = 1
    Else
        $retval = 0
    EndIf
    Return $retval
EndFunc

;Get all file extensions in current directory
;@Param String
;@Return Array
Func getAllExts($dir3)
    _WriteLog("getAllExts" & @TAB & $getAllExts)
    $getAllExts += 1
    Local $added = 0
    Local $allExts[1]
    Local $files = getAllFiles($dir3)
    Local $max = UBound($files)
    For $i = 0 to $max - 1
        Local $ext = getExt($files[$i])
        If ($added == 0) Then
            $allExts[0] = $ext
            $added = 1
        Else
            _ArrayAdd($allExts, $ext)
        EndIf
    Next
    $getAllExts -= 1
EndFunc

;Actual archiving algorithm
;@Param String
Func algorithm($dir)
    _WriteLog("algorithm" & @TAB & $algorithm)
    $algorithm += 1
    Local $dirs = getAllDirs($dir)
    Local $files = getAllFiles($dir)
    Local $allExts = getAllExts($dir)
    
    Local $numExts = UBound($arrayExts)
    Local $numFiles = UBound($files)
    
    For $i = 0 to $numExts - 1
        Local $pos = _ArraySearch($allExts, $arrayExts[$i])
        If Not ($pos == -1) Then
;           $zip = _Zip_Create(@WorkingDir & "\" & $arrayExts[$i] & "_zip.zip")
            For $j = 0 to $numFiles - 1
                Local $fileExt = getExt($files[$j])
                If ($fileExt == $arrayExts[$i]) Then
;                   _Zip_AddFile($zip, $files[$j])
                EndIf
            Next
        EndIf
    Next
    
    Local $numDirs = UBound($dirs)
    For $k = 0 to $numDirs - 1
        algorithm($dirs[$k])
    Next
    $algorithm -= 1
EndFunc

;Main archiving function to be run in 'Main' comment field
;Void
Func main()
    
    Local $root = getRoot()
    
    algorithm($root)
    
EndFunc

;Main
main()

Input used in testing: "D:\_Setup\Kiosk"

Contents of folder used for testing:

D:\_Setup\Kiosk\antivirus.bat
D:\_Setup\Kiosk\pcsetup.bat
D:\_Setup\Kiosk\wallpaper.bat
D:\_Setup\Kiosk\files\SetWallpaper.exe
D:\_Setup\Kiosk\files\CB.url
D:\_Setup\Kiosk\files\Autorun.reg
D:\_Setup\Kiosk\files\nt2kxp2k3.exe
D:\_Setup\Kiosk\files\RB.url

EDIT: Upon further inspection of your code, I think I may have found the root of your problem. You keep using _FileListToArray but you use UBound to get the array size. Thing is, _FileListToArray returns an array with the [0] element containing the count of the elements returned. Using UBound on that will always give you a value of at least 1. That's why your recursion doesn't terminate.

Edited by omikron48

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0