8

Here's one interesting thread. And I tried to play with the two things discussed there.

  1. You can access labels with special symbols with double expansion.
  2. Labels that contain /? cannot be used because GOTO and CALL prints their help messages instead of execution.

And here's the result:

@echo off

setlocal enableDelayedExpansion
set "label=/?"

    call :%%label%%
    echo == Test message to check if the CALL or GOTO ( or neither ) command is executed  ==

exit /b 0

:/?
    echo == CALL or GOTO has been executed ==
exit /b 0

And the output:

Directs cmd.exe to a labeled line in a batch program.

GOTO label

  label   Specifies a text string used in the batch program as a label.

You type a label on a line by itself, beginning with a colon.

If Command Extensions are enabled GOTO changes as follows:

GOTO command now accepts a target label of :EOF which transfers control
to the end of the current batch script file.  This is an easy way to
exit a batch script file without defining a label.  Type CALL /?  for a
description of extensions to the CALL command that make this feature
useful.
== Test message to check if the CALL or GOTO ( or neither ) command is executed  ==
== Test message to check if the CALL or GOTO ( or neither ) command is executed  ==

And the code after the CALL is executed twice??

EDIT

This is even more unexplainable to me:

@echo off

setlocal enableDelayedExpansion
set "label=/?"
    set /a x=1
    call :%%label%% >nul

    set /a x=x+1
    echo ---
    echo -%x%-
    echo ---

exit /b 0

:/?
    echo == CALL or GOTO has been executed ==
    echo == first argument : %1 ==
exit /b 0 

The output is:

---
-3-
---

The code after the call of the CALL for sure is executed twice, but the output of the first run can be redirected in the same line?

Mofi
  • 46,139
  • 17
  • 80
  • 143
npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • 3
    What makes this even more perplexing (if that is possible) is if you add a `& pause` after the `call` it echo's everything once, pauses and than echoes it **after** the pause! – Monacraft Aug 13 '15 at 12:07

2 Answers2

7

I'm always surprised, that you still found things that never came to my mind to test.

Contrary to Aacini, I don't believe that :/? acts here as a valid label.
Else this should find such a label.

I suppose that the CALL command is internally composed of a stack pusher function and then just use GOTO to jump to the label.

And as you are using late expansion the /? isn't detected by the CALL command itself, but by the GOTO command.
The goto shows only the help info and finished, but as the call has already pushed the fileposition to the stack it works like calling this filepostion and later return to the same location!

set "help=^ /?"
call :myLabel%%help%%

This shows also the help, like a GOTO :myLabel /? would do.
But this one don't

set "help=/?"
call :myLabel %%help%%

I suppose, the GOTO gets only the label parsed by the CALL, the other parameters are moved to %1, %2, ...

And this could explain why only the label can use delayed expansion two times.

@echo off
setlocal EnableDelayedExpansion
set "label=myLabel"
set "pointer=^!label^!"
call :!pointer!
exit /b

:myLabel
echo it works
jeb
  • 78,592
  • 17
  • 171
  • 225
  • 2
    Right. The `call` command followed by a colon starts the generation of a new batch context. The batch code is loaded into this context and, if the element that generated the context starts with a colon it is considered a label and a `goto` is executed to jump to this label. It was used and indicated [here](http://stackoverflow.com/a/30170342/2861476). Just as a curiosity, there is a internal variable defined just to hide the `goto` execution when `echo` is enabled. – MC ND Aug 13 '15 at 14:31
  • Sound like the answer! First thing that came to my mind was - Is it possible to force a `call :eof` to jump to the end of file like the `goto`.btw most of the internal commands prints their help no matter where the string `?` is placed in the arguments.But only `rem` has a problems with double expansion here : `set "h=/?"&call rem %%h%%` – npocmaka Aug 13 '15 at 14:40
  • @MCND - what internal variable? – npocmaka Aug 13 '15 at 14:47
  • Excuse me jeb, but I disagree. If the `call :%%label%%` command would fail, the standard response would be to show "Label not found" message and set errorlevel=1. No one of these things happen here. See the EDIT #2 in my answer... – Aacini Aug 13 '15 at 14:56
  • 3
    @npocmaka, nothing accesible from batch code. Just a memory address used as a flag. I saw it when debugging `cmd` just to be sure before posting the answer linked in the previous comment. – MC ND Aug 13 '15 at 15:03
  • @Aacini - but I think it's reasonable.If `CALL` uses the `GOTO` to parse the label , and then `GOTO` detects the `/?` there'll be no need of error message. – npocmaka Aug 13 '15 at 15:11
  • 2
    Ok. I reviewed this point and concluded that jeb is right, with one detail. He said "The goto simply fails", but no; the execution of `goto :/?` execute correctly and show the GOTO help screen. The CALL part see no error in the GOTO part, so it continue normally... – Aacini Aug 13 '15 at 17:25
  • 2
    Great analysis to come up with simple rules that account for the behavior. – dbenham Aug 14 '15 at 04:19
  • 2
    @Aacini Thanks, and you are right, the `goto :/?` doesn't fail, I will change the text – jeb Aug 14 '15 at 08:01
3

Interesting! The first code may be reduced to:

@echo off

setlocal
set "label=/?"

    call :%%label%%
    echo == Test message to check if the CALL or GOTO ( or neither ) command is executed  ==

and still show the same output, that is, it behaves the same way than this code:

@echo off

setlocal

call :/?
echo == Test message to check if the CALL or GOTO ( or neither ) command is executed  ==

where the call :/? is both a call command and a valid label, AND considering :/? a valid label. Wow!

Why the GOTO help is displayed? No idea!!!

EDIT: Additional tests

This code:

@echo off

setlocal
set "label=/?"

    set i=0
    call :%%label%%  &  echo Command in same line:  i=%i%
    set /A i+=10
    echo == Test message ==     i=%i%

show the GOTO help screen first, and then:

== Test message ==     i=10
Command in same line:  i=0
== Test message ==     i=20

but if EnableDelayedExpansion is added and %i% is changed by !i! in the call line, then it shows:

== Test message ==     i=10
Command in same line:  i=10
== Test message ==     i=20

as "expected"...

EDIT #2

The test below show that the call :%%label%% command does NOT report the ERRORLEVEL=1 standard on "label not found" error:

@echo off

setlocal
set "label=/?"

    call :notFound
    echo Label not found: ERRROLEVEL = %ERRORLEVEL%
    ver > NUL
    echo Reset errorlevel: ERRROLEVEL = %ERRORLEVEL%

    call :%%label%%
    echo == Test message == ERRROLEVEL = %ERRORLEVEL%
Aacini
  • 65,180
  • 12
  • 72
  • 108