I'm back here for another question, this time about macros.
I'd want to call a multi-line macro by using !..! (if possible) in order to use dynamic macro names like in the following call for a single-line macro:
setlocal disabledelayedexpansion
:: Simple single-line macros for testing purpose.
set "_testA=echo A" & set "_testB=echo B"
setlocal enabledelayedexpansion
:: Choose macro _testA or _testB.
set /p char="Type A or B:"
:: Execute the chosen macro.
!_test%char%!
endlocal
endlocal
For example,
setlocal disabledelayedexpansion
:: Line feed character.
(set CHR10=^
%=Do not remove this line, or you will be turned into a frog=%
)
:: End of line in a macro code.
set ^"\nmac=^^^%CHR10%%CHR10%^%CHR10%%CHR10%^^"
:: Simple multi-line macro for testing purpose, it could be replace with one receiving parameters obviously.
set _test=(echo A%\nmac%
echo B%\nmac%
echo C)
setlocal enabledelayedexpansion
:: Works as expected, displays A then B then C.
%_test%
:: Doesn't work... as expected also, displays `(echo Is Not Recognized as an Internal or External Command, Operable Program or Batch File.`
!_test!
endlocal
endlocal
The problem seems to comes from the definition of CHR10 when using with !..! (using %_test% works, obviously).
Any idea to solve this ? A solution could help me to refactor some code.
Thanks in advance for your answer.
CodePudding user response:
Mofi, lets clarify a few stuffs then.
The word "macro" is ALSO used in Batch coding to define environment variables containing executable code, even if the rigourous definition of a "macro" is different. For reference i advice you to read the thread here opened by jeb a few year ago, he discovered the nice way to pass parameters to these kind of variables.
About what i want to achieve, i can't enter into details that much, but as you guess the benefits of inserting inline code are VERY interesting. Mainly this kind of code allows to avoid the damn slow call
command. You're not totally free to do what you want in the code of a macros but in various situation it's the way to go to keep an optimal performance.
So now about my question. Being able to call a macro by using a dynamic name has a lot of benefits too, it allows to automatize chains of statements depending from dynamic conditions (for example an user input, but there are a lot of different situations).
About reading the page "How does the Windows Command Interpreter (CMD.EXE) parse scripts" i already did it a few years ago when i started my project (in fact, it's the very first page i did read^^).
Today my application is done (about 42000 lines), but i decided to refactor a bit by deleting some lines, hence my question. I know !_test! can't work, but i was wondering if there is a way to escape the value of \nmac to mimic what happens with a single-line macro. Hope i'm clearer, sorry if i wasn't enough.
CodePudding user response:
The solution is easy, you always need percent expansion for the execution of a batch macro. Obviously you can't make the the variable name dynamic for a percent expansion, but you can make the content dynamic.
@echo off
(set ^"$\n=^^^
%= Do not remove this line=%
)
set macro1=(echo #1 Line1 %$\n%
echo #1 Line2)
set macro2=(echo #2 Line1 %$\n%
echo #2 Line2)
setlocal EnableDelayedExpansion
%macro1%
%macro2%
set /p "macroNum=Select 1 or 2: "
set "macroName=macro%macroNum%"
REM *** Copy the content of the 'dynamic macro' to indirectMacro
set "indirectMacro=!%macroName%!"
%indirectMacro%
Btw. Your definition and use of \nmac
is superfluous, because a single linefeed
(with a single caret) is enough in batch macros, when they are enclosed in parenthesis.