The function returns 0 when an error occured and ErrorLevel will contain a detailed error message.
The function replaces the "#" in the given file name with a number (with leading zeros). The number starts from 1 or from any given StartID. E.g. ###.ahk with StartID = 12 will result in 012.ahk, 013.ahk, 014.ahk, etc.
All formats are possible, e.g. x#.#y##z.ahk with StartID = 4199 will result in x4.1y99z.ahk, x4.2y00z.ahk, x4.2y01z.ahk, etc.
The path for the file can be specified or the current directory will be used.
The function is 90 lines of code while the most part is error handling. Without these error handling the function is only 16 lines. I added the "pure" function below.
;######################## Testing Eval( GetAvailableFileName( A_ScriptName )) ; should be error Eval( GetAvailableFileName( "xyz.ahk" )) ; ok Eval( GetAvailableFileName( "xy#z.ahk" )) ; ok Eval( GetAvailableFileName( "x#y#z.ahk" )) ; ok Eval( GetAvailableFileName( "xy##z.ahk" )) ; ok Eval( GetAvailableFileName( "x#.#y##z.ahk" )) ; ok Eval( GetAvailableFileName( "####.ahk" )) ; ok Eval( GetAvailableFileName( "xy##z.ahk", "C:\" )) ; ok Eval( GetAvailableFileName( "xy##z.ahk", "C:\Windows" )) ; ok Eval( GetAvailableFileName( "xy##z.ahk", "C:\XYZ0125RET\" )) ; should be error Eval( GetAvailableFileName( "xy##z.ahk", "", 5 )) ; ok Eval( GetAvailableFileName( "xy##z.ahk", "", 115 )) ; should be error Eval( GetAvailableFileName( "xy##z.ahk", "", 33 )) ; ok Eval( GetAvailableFileName( "xy##z.ahk", "", 33.3 )) ; ok Msgbox, % Eval("") ;% Return Eval(FileName) { static MsgTxt If FileName = 0 MsgTxt = %MsgTxt%Error: %ErrorLevel%`n`n Else MsgTxt = %MsgTxt%%FileName%`n`n Return MsgTxt } ;######################## Func: GetAvailableFileName GetAvailableFileName( GivenFileName, GivenPath = "", StartID = 1 ) { ;check if GivenPath exist and add "\" if necessary If GivenPath is not space { StringRight, LastChar, GivenPath, 1 If ( LastChar <> "\" ) GivenPath = %GivenPath%\ If ( InStr(FileExist(GivenPath), "D") = 0 ) { ErrorLevel = The given path >%GivenPath%< doesn't exist. Return 0 } } ;check if StartID is reasonable If ( StartID < 0 Or Mod(StartID, 1) <> 0 ) { ErrorLevel = (LTrim The StartID >%StartID%< is smaller then zero or not an integer. It has to be a positive integer. ) Return 0 } ;split GivenFileName with # StringSplit, NameArray, GivenFileName, # ;if GivenFileName doesn't contain # ... If NameArray0 < 2 { ;check if GivenFileName exists If FileExist(GivenPath . GivenFileName) { ErrorLevel = (LTrim The given file >%GivenFileName%< does exist in path >%GivenPath%<. (if path is empty, it's the path of the script/exe) ) Return 0 } Else Return GivenPath . GivenFileName } ;check if StartID isn't too large If ( StrLen(StartID) > NameArray0 - 1 ) { ErrorLevel = (LTrim The StartID >%StartID%< is too large for the filename >%GivenFileName%<. ) Return 0 } ;Search from StartID ... Loop { Number := A_Index + StartID - 1 ;untill number is too large ... If ( StrLen(Number) > NameArray0 - 1 ) { ErrorLevel = (LTrim All files exist for >%GivenFileName%< with all # between %StartID% and %Number%. ) Return 0 } ;otherwise fill number with leading zeros Loop, % NameArray0 - 1 - StrLen(Number) ;% Number = 0%Number% ;split number in an array StringSplit, NumberArray, Number ;mix and concatenate the names array with the numbers array FileName = Loop, %NameArray0% FileName := FileName . NameArray%A_Index% . NumberArray%A_Index% ;check if GivenFileName doesn't exist If not FileExist(GivenPath . FileName) Return GivenPath . FileName } }
Without error handling
GetAvailableFileName( GivenFileName, GivenPath = "", StartID = 1 ) { StringSplit, NameArray, GivenFileName, # Loop { Number := A_Index + StartID - 1 Loop, % NameArray0 - 1 - StrLen(Number) ;% Number = 0%Number% StringSplit, NumberArray, Number FileName = Loop, %NameArray0% FileName := FileName . NameArray%A_Index% . NumberArray%A_Index% If not FileExist(GivenPath . FileName) Return GivenPath . FileName } }