Bypass ENDLOCAL barrier

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Bypass ENDLOCAL barrier

#16 Post by jeb » 11 Mar 2015 08:46

Good point ... but solved the wrong way :D

You should transfer also empty values over the endlocal barrier, else it's not possible to erase a value.

What's about

Code: Select all

set myVar=HELLO
call :clearVar myVar
exit /b

:clearVar
setlocal
set "%1="
endlocal %1
exit /b


The solution is to move some lines

Code: Select all

 set "content=!%%C!"%\n%
       set "retContent=!retContent!"set !varName[%%n]!=!content!"!LF!"%\n%
       if defined content ( %\n%
 %=      This complex block is only for replacing '!' with '^!'      =%%\n%
...
           set ^"content_EDE=!content_EDE:""q="!"%\n%
       ) ELSE set "content_EDE="%\n%
       set "retContent=!retContent!set "!varName[%%n]!=!content_EDE!"!LF!"%\n%
      )%\n%
   )%\n%
 %= Now return all variables from retContent over the barrier =%%\n%
   for /F "delims=" %%V in ("!retContent!") DO (%\n%


This should solve the problem (untesteted)

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#17 Post by SilverHawk » 12 Mar 2015 04:48

Tested now, and obviously works as expected.
Thanks again

SilverHawk

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#18 Post by SilverHawk » 13 Mar 2015 02:38

UPDATE: I find out that only variables with EXACT name are exported, but not groups that begins with a prefix.
I need also this case, so I modified again the macro.
I post it in case it may be useful to others.
@jeb: could be the right way?
@Antonio: thanks for the hint, very useful.

Example:

Code: Select all

SET "Var1.a=alpha"
SET "Var1.b=beta"
%endlocal% Var1.
ECHO Var1.a: [%Var1.a%]
ECHO Var1.b: [%Var1.b%]


Previous result:

Code: Select all

Var1.a: []
Var1.b: []


New result:

Code: Select all

Var1.a: [alpha]
Var1.b: [beta]


This is the updated code (only first lines):

Code: Select all

set ^"endlocal=for %%# in (1 2) do if %%#==2 (%\n%
   setlocal EnableDelayedExpansion%\n%
 %=  Take all variable names into the varName array =%%\n%
   set varName_count=0%\n%
   set "args2=" %\n%
   for %%C in (!args!) do ( %\n%
     set "NewArg=" %\n%
     for /F "delims==" %%D in ('set %%C 2^^^>nul') do ( %\n%
       set "NewArg=!NewArg!, %%D" %\n%
     ) %\n%
     if not defined NewArg ( %\n%
       set "args2=!args2!, %%C" %\n%
    ) else ( %\n%
       set "args2=!args2!, !NewArg:~2!" %\n%
    ) %\n%
   ) %\n%
   set "args=!args2:~2!" %\n%
   for %%C in (!args!) do set "varName[!varName_count!]=%%~C" ^& set /a varName_count+=1%\n%
 %=    Build one variable with a list of set statements for each variable delimited by newlines =%%\n%
 %=    The lists looks like --> set result1=myContent\n"set result1=myContent1"\nset result2=content2\nset result2=content2\n =%%\n%
...


SilverHawk

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#19 Post by SilverHawk » 18 Mar 2015 10:18

Sorry guys but I've another matter :evil:, and exactly in this line of the macro:

Code: Select all

     call set "content_EDE=%%content_EDE:^!=""e^!%%"%\n%


In some contexts, and I don't understand which and why, the value obtained from the macro is different for EDE (may be a previous value?).
I solved removing the EDE management but it's a dirty way, and I prefer to keep it.
How can I solve??
Thanks

SilverHawk

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Bypass ENDLOCAL barrier

#20 Post by jeb » 18 Mar 2015 14:37

It's a little bit hard to solve a problem where the problem is unclear :?

What type of contents you try to transfer, exclamation marks, carets, percent signs or quotes or all?

Do you can show at least one content?

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#21 Post by SilverHawk » 19 Mar 2015 06:52

Hi jeb, thanks for the reply.
Sorry but it's bit tricky to understand what's is causing the problem.
I understood that in case of EDE the grabbed value is the previous one (may be due to a call, inside nested IF & FOR constructs).
I'll try to isolate the affecting context and I'll let you know.
Thanks in advance

SilverHawk

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#22 Post by SilverHawk » 19 Mar 2015 07:49

Catched!
Why the hell I obtain the wrong value [ blablaontent_EDE:] for O_01???

Actual result:

Code: Select all

O_01 A: []
DEBUG O_01 A: []
DEBUG O_01 B: [   blablaontent_EDE:]
Premere un tasto per continuare . . .


Test code:

Code: Select all

@echo off

CALL:Library.Initialize

SetLocal EnableDelayedExpansion

ECHO O_01 A: [%O_01%]
CALL:Test1
ECHO O_01 B: [%O_01%]
pause
EXIT 0

:Library.Initialize

REM :: LINE FEED - BEGIN - DO NOT REMOVE THE 2 LINES BELOW
set LF=^


REM :: LINE FEED - END - DO NOT REMOVE THE 2 LINES ABOVE

set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
%=   I use EDE for EnableDelayeExpansion and DDE for DisableDelayedExpansion =%

set ^"Library.Generic.ReturnWithErrors=for %%# in (1 2) do if %%#==2 (%\n%
   setlocal EnableDelayedExpansion%\n%
 %=  Take all variable names into the varName array =%%\n%
   set varName_count=0%\n%
   set "args2=" %\n%
   for %%C in (!args!) do ( %\n%
     set "NewArg=" %\n%
     for /F "delims==" %%D in ('set %%C 2^^^>nul') do ( %\n%
       set "NewArg=!NewArg!, %%D" %\n%
     ) %\n%
     if not defined NewArg ( %\n%
       set "args2=!args2!, %%C" %\n%
    ) else ( %\n%
       set "args2=!args2!, !NewArg:~2!" %\n%
    ) %\n%
   ) %\n%
   set "args=!args2:~2!" %\n%
   for %%C in (!args!) do set "varName[!varName_count!]=%%~C" ^& set /a varName_count+=1%\n%
 %=    Build one variable with a list of set statements for each variable delimited by newlines =%%\n%
 %=    The lists looks like --> set result1=myContent\n"set result1=myContent1"\nset result2=content2\nset result2=content2\n =%%\n%
 %=    Each result exists two times, the first for the case returning to DDE, the second for EDE =%%\n%
 %=    The correct line will be detected by the (missing) enclosing quotes  =%%\n%
     set "retContent=1!LF!"%\n%
     for /L %%n in (0 1 !varName_count!) do (%\n%
       for /F "delims=" %%C in ("!varName[%%n]!") DO (%\n%
         set "content=!%%C!"%\n%
         set "retContent=!retContent!"set !varName[%%n]!=!content!"!LF!"%\n%
         if defined content ( %\n%
 %=          This complex block is only for replacing '!' with '^!' =%%\n%
 %=          First replacing   '"'->'""q'   '^'->'^^' =%%\n%
           set ^"content_EDE=!content:"=""q!"%\n%
           set "content_EDE=!content_EDE:^=^^!"%\n%
 %=          Now it's poosible to use CALL SET and replace '!'->'""e!' =%%\n%
           call set "content_EDE=%%content_EDE:^!=""e^!%%"%\n%
 %=          Now it's possible to replace '""e' to '^', this is effectivly '!' -> '^!' =%%\n%
           set "content_EDE=!content_EDE:""e=^!"%\n%
 %=          Now restore the quotes  =%%\n%
           set ^"content_EDE=!content_EDE:""q="!"%\n%
         ) ELSE set "content_EDE="%\n%
         set "retContent=!retContent!set "!varName[%%n]!=!content_EDE!"!LF!"%\n%
       )%\n%
     )%\n%
 %=    Now return all variables from retContent over the barrier =%%\n%
     for /F "delims=" %%V in ("!retContent!") DO (%\n%
 %=      Only the first line can contain a single 1 =%%\n%
       if "%%V"=="1" (%\n%
 %=        We need to call endlocal twice, as there is one more setlocal in the macro itself =%%\n%
         endlocal%\n%
         endlocal%\n%
       ) ELSE (%\n%
 %=        This is true in EDE             =%%\n%
         if "!"=="" (%\n%
           if %%V==%%~V (%\n%
             %%V !%\n%
           )%\n%
         ) ELSE IF not %%V==%%~V (%\n%
           %%~V%\n%
         )%\n%
       )%\n%
     )%\n%
   ) else set args=Library.Error., "
GOTO:EOF

:Test1
SETLOCAL
SET "FileName=%~2"
FOR /F "usebackq eol=; tokens=1-7 delims=:" %%a IN ("C:\transfers.txt") DO (
  IF "0" EQU "0" (
   IF "0" EQU "0" (
     ECHO DEBUG O_01 A: [!O_01!]
      CALL:Test2
     ECHO DEBUG O_01 B: [!O_01!]
     pause
   )
  )
)
GOTO:EOF

:Test2
SETLOCAL
SET "O_01=blabla"
%Library.Generic.ReturnWithErrors% O_01
GOTO:EOF


Content of [C:\transfers.txt]:

Code: Select all

;
;## User Guides - BEGIN ##
User Guides           : Inve*    :   blabla
;## User Guides - END ##
;


SilverHawk

P.S. I edited the production code to get a test case, may be some lines / values are unnecessary.
P.P.S. I think the cause of the problem is caused by the line [call set "content_EDE=%%content_EDE:^!=""e^!%%"%\n%]

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Bypass ENDLOCAL barrier

#23 Post by jeb » 19 Mar 2015 08:50

A simplified test case

Code: Select all

:Test1
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1-4 delims=," %%a IN ("AAA,BBB,CCC,DDD") DO (
      SET "O_01=blabla"
        %Library.Generic.ReturnWithErrors% O_01
       SET O_01
)
exit /b


The problem is here that in the line the %%content_EDE is parsed the wrong way.

Code: Select all

call set "content_EDE=%%content_EDE:^!=""e^!%%"%\n%


One simple way to solve it:

Code: Select all

set "percent=%%"
set ^"Library.Generic.ReturnWithErrors=for %%# in (1 2) do if %%#==2 (%\n%
....
          call set "content_EDE=!percent!content_EDE:^!=""e^!!percent!"%\n%

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: Bypass ENDLOCAL barrier

#24 Post by Ed Dyreen » 19 Mar 2015 09:18

Or add an extra caret to prevent token expansion.

Code: Select all

@echo off &setlocal enableDelayedExpansion

set "cc=unit^!Test"
set "cc"
for %%c in ( testFailed ) do call set "cc=%%cc:^!=""e^!%%"
set "cc"

set "cc=unit^!Test"
set "cc"
for %%c in ( testFailed ) do call set "cc=%%^cc:^!=""e^!%%"
set "cc"

pause
exit

Code: Select all

cc=unit!Test
cc=testFailedc:!=""e!
cc=unit!Test
cc=unit""e!Test
Druk op een toets om door te gaan. . .

SilverHawk
Posts: 17
Joined: 04 Mar 2015 01:42

Re: Bypass ENDLOCAL barrier

#25 Post by SilverHawk » 19 Mar 2015 09:34

Approved, and works in both ways.
Thank you!!

SilverHawk

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: Bypass ENDLOCAL barrier

#26 Post by jeb » 19 Mar 2015 09:47

Ed Dyreen's solution still can fail.

It doesn't fail with %%c but now it fails for %%" and also %%^^
See the official reference page at SO: Benham's table :wink:

Code: Select all

set "cc=unit^!Test"
set "cc"
for %%^^ in ( testFailed ) do call set "cc=%%^cc:^!=""e^!%%"
for %%^" in ( testFailed ) do call set "cc=%%^cc:^!=""e^!%%"
set "cc"


It could also be solved with setlocal DisableExtensions, but this will complicate other things.

Post Reply