I am trying to utilize the different %rtnLocal% and %endlocal% return macros in order to utilize in my batch to carry-over 1000's of filepaths & names that contain "!" as posted in preserving exclamation marks in variable between setlocals batch.
I choose macros as I've also seen dbendham, jeb, Aacini, and others discuss how macros are generally a faster option; as opposed to Call functions or Call files.
Here is my sample and I just can't get them to function properly, I am not sure what I am doing wrong if perhaps a win10 since then has slightly modified that causes this to stop working. Setlocal(2) is the contains 1 of the 'return macros', after which are simulated setlocal levels for testing, and no matter what I change the level to rtnLocal*2 , *4, etc.. (except for more than setlocals are set; it then sets outside the batch at the prompt level) it does not populate outside the existing setlocal.
Thank you for any clarification
Edit: Corrected Setlocal imbalanace.
@echo OFF
Setlocal EnableExtensions DisableDelayedExpansion
SETlocal EnableExtensions DisableDelayedExpansion
::Return V2.0 - 2016 -jeb
:: https://stackoverflow.com/questions/29869394/preserving-exclamation-marks-in-variable-between-setlocals-batch/29869518#29869518
@rem The other/only problem is when you try to transfer a variable over an endlocal barrier (like endlocal & set "RetVar2=%modTestVar%").
@rem This is not trivial.
@rem
@rem This is a batch macro for this, used like this %endlocal% modTestVar
if "!" equ "" (
>&2 echo *** 'retLocals' macro must be loaded under 'disableDelayedExpansion'
exit /b 1
)
set LF=^
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
@rem single carriage-return char 0x0D (usable as !CR! under edx, only)
for /F "usebackq delims= " %%C in (`copy /z "%~f0" nul`) do set "CR=%%C"
:: macro to return multiple LF-free variables across endlocal barriers
::
:: syntax: %retLocals%[*cnt] out1[=in1] [, out2[=in2] [, out3[=in3]] ...]
:: - 'out#' (#=1,2,3,...) are variables being returned/set in the outer context
:: - 'in#' are local/inner context variables whose values are returned
:: - optional [=in#] defaults to 'out#=out#'
:: - optional [*cnt] is the nesting depth, default '*1' for one 'endlocal' call
:: - spaces around ',' commas and '=' equal signs are optional
::
:: e.g. %retLocals% var copies inner 'var' across 1 endlocal
:: to namesake 'var' in the outer context
::
:: %retLocals%*2 out1=in1, out2 copies 'in1', 'out2' across 2 endlocal's
:: to 'out1', 'out2' in the outer context
::
:: %retLocals%*0 out=in copies 'in' to 'out' within same context
:: like 'set out=%in%' but safe against
:: embedded quotes and funny chars except LF
::
:: ! names of variables 'out#', 'in#' are expected to be plain quote-less
:: well behaved strings, with no funny (<|>^%!=,;) characters
:: ! 'in#' names must not be 'cd' since that's used by %retLocals% internally
:: ! outer environment other than 'out#' is not modified
:: except for '%retLocals%*0' with '*0' de-nesting, which clears 'cd'
:: ! errorlevel is reset to '0' but the caller can preserve the inner value
:: if needed via '(%retLocals% ...) & set outErr=%errorlevel%'
set ^"retLocals=for %%# in (1 2) do if %%#==2 (%\n%
setlocal enableDelayedExpansion%\n%
set x=%\n%
for %%L in ("!LF!") do for %%R in ("!CR!") do ^
for /f "tokens=1,*" %%U in ("!cd!") do ^
for /f "tokens=2 delims=*" %%U in ("%%U*%%U") do (%\n%
set v=%%~V%\n%
for /f "delims=" %%V in ("!v:,=%%~L!") do ^
for /f "tokens=1,2 delims== " %%V in ("%%~V=%%~V") do (%\n%
set w=!%%~W!%\n%
if defined w (%\n%
set w=!w:^"=""q!%\n%
set w=!w:%%~R=""r!%\n%
set "path=" ^& set "pathExt=;"%\n%
set "w=!w:^=^^^^!"%\n%
call set "w=%%w:^!=^^^!%%"%\n%
set "w=!w:^^=^!")%\n%
if defined x set x=!x!!LF!%\n%
set x=!x!"%%~V=!%%~W!"!LF!"%%~V=!w!")%\n%
for /f "delims=" %%X in ("!x!") do (%\n%
if "!cd:~0,1!"=="*" (%\n%
for /l %%U in (0 1 %%U) do endlocal%\n%
set "cd=" ^& call;)%\n%
if errorlevel 1 ((if "!"=="" (%\n%
set "%%~X"!%\n%
for /f "delims==" %%V in ("%%~X") do (%\n%
if defined %%~V (%\n%
set %%~V=!%%~V:""r=%%~R!%\n%
set %%~V=!%%~V:^""q="!%\n%
)))) ^& call;%\n%
) else (if not "!"=="" set "%%~X") ^& call%\n%
))) else set cd=*1^"
SETlocal EnableExtensions DisableDelayedExpansion
SETlocal EnableExtensions DisableDelayedExpansion
SETlocal EnableExtensions DisableDelayedExpansion
SETlocal EnableExtensions DisableDelayedExpansion
SETlocal EnableExtensions EnableDelayedExpansion
ECHO -----------------------------
SET /a "ID2=2"
%retLocals%*3 ID5=ID2
Echo This0: %ID2%,%ID5%
EndLocal
Echo This1: %ID2%,%ID5%
EndLocal
Echo This2: %ID2%,%ID5%
EndLocal
Echo This3: %ID2%,%ID5%
ECHO *******************************
EndLocal
Echo This4: %ID2%,%ID5%
EndLocal
Echo This5: %ID2%,%ID5%
EndLocal
EndLocal