I'm writing a complex batch patch file with generation of other files. I know that batch is not the best for it but I've mostly got it all working. However, there is a headache of keeping all subroutines duplicated in all files if I don't want to make a separate file for each subroutine. My question was whether there is any way of keeping a library file of multiple subroutines and call them somehow?
So I'm going to answer my own question because I managed to get something working.
Lets say you have main.bat and lib.bat files.
Main.bat
@ECHO off
SETLOCAL
SET return=
SET reference=this is just a reference variable
CALL lib.bat return "subroutine" "static arg" reference
IF NOT "%ERRORLEVEL%"=="0" (
ECHO Execution failed - %ERRORLEVEL%
EXIT /b 1
)
ECHO.
ECHO subroutine return value: "%return%"
ECHO.
CALL lib.bat NUL "procedure" "static arg" reference
ECHO.
CALL lib.bat return "error" "static arg" reference
IF NOT "%ERRORLEVEL%"=="0" (
ECHO Execution failed - %ERRORLEVEL%
EXIT /b 1
)
ENDLOCAL
EXIT /b 0
Lib.bat
@ECHO off
::
:: ===================================================================================
:: Library Main Handler
:: ===================================================================================
:: %~1 - [out] - NUL | reference to a return variable
:: %~2 - [in] - subroutine label to be invoked
:: %~3+ - [in] - optional arguments to the subroutine
::
:: ERRORLEVEL is passed through to the caller
::
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
SET callSub=%~2
SET return=
SET args=
IF "%callSub%"=="" (
ECHO Subroutine label was not provided to the library. 1>&2
EXIT /b 1
)
:buildUpArgumentList
IF "%~3"=="" GOTO end_buildUpArgumentList
SET args=%args% "%~3"
SHIFT /3
GOTO buildUpArgumentList
:end_buildUpArgumentList
IF NOT "%~1"=="NUL" (
call:%callSub% return %args%
IF NOT "!ERRORLEVEL!"=="0" (
EXIT /b !ERRORLEVEL!
)
) ELSE (
call:%callSub% %args%
IF NOT "!ERRORLEVEL!"=="0" (
EXIT /b !ERRORLEVEL!
)
)
(
ENDLOCAL
IF NOT "%~1"=="NUL" (
SET %~1=%return%
)
)
EXIT /b 0
::
:: ===================================================================================
:: Library Subroutine Definitions
:: ===================================================================================
::
:subroutine <r_return> <static> <r_reference>
SETLOCAL
ECHO subroutine^<static^>: "%~2"
ECHO subroutine^<r_reference^>: "!%~3!"
(
ENDLOCAL
SET %~1=subroutine executed OK
)
EXIT /b 0
:procedure <static> <r_reference>
SETLOCAL
ECHO procedure^<static^>: "%~1"
ECHO procedure^<r_reference^>: "!%~2!"
ENDLOCAL
EXIT /b 0
:error <r_return> <static> <r_reference>
SETLOCAL
ECHO error^<static^>: "%~2"
EXIT /b 2
ECHO error^<r_reference^>: "!%~3!"
(
ENDLOCAL
SET %~1=error executed OK
)
EXIT /b 0
Output:
subroutine<static>: "static arg"
subroutine<r_reference>: "this is just a reference variable"
subroutine return value: "subroutine executed OK"
procedure<static>: "static arg"
procedure<r_reference>: "this is just a reference variable"
error<static>: "static arg"
Execution failed - 2
Some comments:
Additional thoughts:
Any other comments are much appreciated!