ReturnVar macro revisited
Posted: 19 Oct 2013 14:49
A while back jeb came up with a ReturnVar Macro single that could return poison character strings across the endlocal barrier and worked with both enabled and disabled delayed expansion with a helper function that was required if called with expansion disabled. It could also handle CR and LineFeeds.
http://www.dostips.com/forum/viewtopic.php?f=3&t=4827&hilit=return+macro
I came up with a modification that seems to work without a helper function when called with expansion enabled or disabled but I had to simplify it without CR and LineFeed handling. Can this concept even handle CR and LF??
TestReturnVar.bat
http://www.dostips.com/forum/viewtopic.php?f=3&t=4827&hilit=return+macro
I came up with a modification that seems to work without a helper function when called with expansion enabled or disabled but I had to simplify it without CR and LineFeed handling. Can this concept even handle CR and LF??
TestReturnVar.bat
Code: Select all
:TestReturnVar.bat
@echo off
setlocal
Set "Return=%~1"
if not defined Return (
Echo Please specify a return variable as first argument
goto :eof
)
Echo(Variable entered will be returned in %Return% variable
call :getvar var="Enter %Return%: "
call :eco "%Return%=" var /n
choice /n /C EDQ /m "Select return with expansion [E]nabled or [D]isabled or [Q]uit"
set/a Expansion=%errorlevel%
rem define the macro
setlocal disabledelayedexpansion
call :ReturnVar
goto :%Expansion%
:1
setlocal enabledelayedexpansion
%ReturnVar% %~1 var 3
call :eco "%~1=" %~1 /n
goto :eof
:2
rem expansion is already disabled here
%ReturnVar% %~1 var 2
call :eco "%~1=" %~1 /n
goto :eof
:3
echo(Variable %Return% is undefined or unchanged
call :eco "%~1=" %~1 /n
goto :eof
:ReturnVar Macro
@if defined ReturnVar @exit /b -1
:initReturnVar
@if "!" equ "" (
>&2 @echo ERROR: ReturnVar must be initialized with delayed expansion disabled
@exit /b 1
)
@set LF=^
:: Above 2 blank lines are critical - Do not remove ::
@set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
@for /f "usebackq delims= " %%C in (`copy /z "%~f0" nul`) do @set "CR=%%C"
@REM ** ReturnVar <resultVariable> <TransferVariable> [endlocalCount] by jeb
@REM ** return a <TransferVariable> over one or more endlocal barriers to a resultVariable
@REM ** endlocalCount default=1, is the number of endlocals that should be executed
@REM ** All special characters can be transferd from TranferVariable to the result variable,
@REM ** even "<>&|!^"
@REM ** The result is correct, independent of the delayed expansion mode after the endlocals
@set ^"ReturnVar=@for %%# in (1 2) do @if %%#==2 @(%\n%
setlocal EnableDelayedExpansion%\n%
set/a safeReturn_count=0%\n%
for %%C in (!args!) do @(%\n%
set "safeReturn[!safeReturn_count!]=%%~C" ^& set /a safeReturn_count+=1%\n%
)%\n%
if not defined safeReturn[2] set "safeReturn[2]=1"%\n%
set /a safeReturn[2]+=2%\n%
for /f "delims=" %%T in ("!safeReturn[1]!") do @set "_#_$_safeReturn=!%%T!"%\n%
for /f "delims=" %%N in (""!safeReturn[0]!"") do @(%\n%
for /f tokens^^=^^1^^*^^ delims^^=^^=^^ eol^^= %%U in ('set _#_$_safeReturn') do @(%\n%
for /l %%n in (1 1 !safeReturn[2]!) do @endlocal%\n%
set "%%~N=%%V"%\n%
)%\n%
)%\n%
) else @setlocal ^& @set args="
@exit /b 0
:GetVar
:: SYNTAX: GetVar ^<EnVar^> [="User Prompt: "] [length] [/m]
::
:: Assigns User input to the Environment variable passed as 1st argument
:: Allows unbalance quotes and 'poison' characters mixed with quotes
:: The only editing key available to the User is 'backspace'
:: The user string entered is set in the Environment variable, 'Envar'
:: If no arguments are passed the routine quits, stand alone version displays help
:: The fisrt argument is mandatory, the rest are optional
:: To display a variable with Poison chars and quotes use: Eco.bat
:: To mask input with '*'s place /m at the very end of the argument list
:: Must be called with delayed expansion disabled for '!', '^' and '&' in string
::
:: Example:
::
:: GetVar.bat Pa$$word="Enter your 'Poison Password' string: " len /m
:: Eco.bat "Your Poison Password is: '" Pa$$word "' with length: " len
:::
::: Dependencies - None Author: Carl with ideas borrowed from Dostips.com
:::
if "%~1"=="" goto :End_GetVar
SetLocal DisableDelayedExpansion
set "Masked="
echo(%*|find /i " /m">nul
if %errorlevel% equ 0 set "Masked=*"
For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do Set "BS=%%#"
Set "Line="
if /i "%~2" neq "/m" <Nul set/p=".%BS% %BS%%~2"
:Char_Loop_
Set "Key="
For /F "delims=" %%# In (
'Xcopy /L /W "%~f0" "%~f0" 2^>Nul'
) Do If Not Defined Key Set "Key=%%#"
Set "Key=%Key:~-1%"
SetLocal EnableDelayedExpansion
If Not Defined Key ( Rem Enter pressed
echo(
If not Defined Line EndLocal&EndLocal&(
If Defined %~1 Set "%~1="
If Defined %~3 Set/a "%~3=0
)&exit/b 0
For /F delims^=^ eol^= %%# In ("!Line!") Do (
EndLocal&EndLocal&(
If not "%~3"=="" Set/a "%~3=%length%"
If Not "%~1"=="" (Set "%~1=%%#")
exit/b %length%
)
)
)
If %BS%==^%Key% (
Set "Key="
If Defined Line set/a length-=1& Set "Line=!Line:~0,-1!"& Set /P "=%BS% %BS%" <Nul
) Else (
If defined Masked (Set "Display=*") Else (Set "Display=!Key:~-1!")
set/a length+=1& Set /p=".%BS%!Display!" <Nul
)
If Not Defined Line (
EndLocal& Set/a length=1& Set "Line=%Key%"
) Else For /F delims^=^ eol^= %%# In ("!Line!") Do (
EndLocal& Set/a length=%length%& Set "Line=%%#%Key%"
)
Goto :Char_Loop_
:End_GetVar
EndLocal&exit/b 0
:Eco "Here is a char: " char " and a string: " EnvarString /n "This is line two."
::
:: Echo's strings mixed with environment variables with or without CR/LF or embed CR/LF inside
:: Environment variables must be passed by name (not reference) and may contain poison chars
:: Quoted strings are echo'd as is and may have leading or trailing spaces
:: To place a newline (CF/LF) use '/n' unquoted
:::
::: Dependencies - None
:::
@SetLocal DisableDelayedExpansion
@For /F %%# In ('"Prompt;$H&For %%# in (1) Do Rem"') Do @Set "BS=%%# %%#"
@SetLocal EnableDelayedExpansion
:Eco_Loop
@if "%~1"=="" @EndLocal& @EndLocal& @exit/b
@if /i "/n" equ "%~1" @(
echo(
) else @if not defined %1 @(
set "string=.%BS%%~1"
for /f delims^=^ eol^= %%# in ("!string!") do @EndLocal& @set/p="%%#" <nul
SetLocal EnableDelayedExpansion
) else @( <nul set/p=".%BS%!%~1!")
@shift& @goto :Eco_Loop
:End_Eco