Debugging .btm with >3 arguments fails on step.

May 23, 2010
60
1
Seattle
Code:
C:\batch]type foo.btm
@ echo off
  do until (%1) == ()
    echo parm is %1
    shift
  enddo
  echo at end
Code:
[C:\batch]foo one two three four five
parm is one
parm is two
parm is three
parm is four
parm is five
at end
Inside the debugger:
  • If I specify some batch arguments, set no breakpoints, then run to breakpoint, it executes correctly.
  • Using the same arguments, if I step through the code, it does not process more than three input parms.
 
Jun 2, 2008
388
2
Newton, MA
I generally debug my scripts the old-fashioned way, but I just tried your example in the debugger. I can confirm the problem. The batch parameters seem to shift properly, but the routine exits prematurely.
 
Jun 2, 2008
388
2
Newton, MA
However, it's unclear to me why you're using SHIFT - it's only useful when you're writing batch files for CMD. TCC allows %0 - %8191.

Hmmm. I use SHIFT quite often when a batch file will process a variable number of arguments. The following code seems much simpler than setting up a counter for the batch argument.

Code:
do while "%1" NE ""
  gosub routine
  shift
enddo

The subroutine can simply process %1.
 
May 20, 2008
11,840
120
Syracuse, NY, USA
Hmmm. I use SHIFT quite often when a batch file will process a variable number of arguments. The following code seems much simpler than setting up a counter for the batch argument.

Code:
do while "%1" NE ""
  gosub routine
  shift
enddo

The subroutine can simply process %1.
You can also loop i=1 to %# and call the subroutine with %[%i] as an argument. It's as easy as using SHIFT and avoids having "%1" hard-coded in the subroutine.

Code:
do i=1 to %#
    gosub foo %[%i]
enddo
quit

:foo [var]
    echo %var
return
 
May 20, 2008
11,840
120
Syracuse, NY, USA
You can also loop i=1 to %# and call the subroutine with %[%i] as an argument. It's as easy as using SHIFT and avoids having "%1" hard-coded in the subroutine.

Code:
do i=1 to %#
    gosub foo %[%i]
enddo
quit

:foo [var]
    echo %var
return
However, unless I have missed something, that doesn't let the subroutine look at the next parameter, or skip parameters. When called from a counted DO loop, the subroutine can't change the value of DO's counter and it can't use ITERATE. I wonder if that could be changed so subroutines called from a DO loop would inherit the context of the DO loop. SHIFT is looking pretty good.
 
May 23, 2010
60
1
Seattle
Vince, maybe I'm missing something. In your example, the subroutine can still see all the parameters by using %[%i].

In general, your approach offers an advantage over SHIFT in that all parameters are available all the time.
 
May 20, 2008
11,840
120
Syracuse, NY, USA
Yes but, as I did it, the subroutine only gets the value of the parameter, not the index. So it can't look at the next one. And even if it could (even if it got the index instead of the value), it can't process the next one and tell the DO loop to skip it. I'm thinking of cases in which some parameters have parameters of their own, like

Code:
/x 5 /y /z

It's not very hard to roll your own counted DO loop.

Code:
set i=1
do while i LE %#
    gosub foo %[%i]
    set i=%@inc[%i]
enddo

In that case, if the subroutine changes the value of i, the DO loop knows about it. But it is becoming (a little) more complicated than using SHIFT.
 
May 20, 2008
11,840
120
Syracuse, NY, USA
Not even the DO loop itself can monkey with the counter!

Code:
v:\> e args.btm

v:\> type args.btm
do i=1 to %#
    echo %[%i]
    set i=100
enddo

v:\> args.btm a b c d e f
a
b
c
d
e
f
 
May 23, 2010
60
1
Seattle
So it can't look at the next one.
Well, technically, it can, by referencing %[%@inc[%i]].

And even if it could (even if it got the index instead of the value), it can't process the next one and tell the DO loop to skip it.
Yes, it can:
Code:
[D:\TMP] type foo.btm
@ echo off
  set retval=0
  do i=1 to %#
    iff %retval gt 0 then
      set retval=0
      iterate
    endiff
    gosub foo %[%i]
    set retval=%_?
  enddo
  quit

:foo [var]
  echo var passed is %var
   iff %var eq /x then
    echo The subparm of %var is %[%@inc[%i]]
    return 1
  endiff
  return 0
Code:
[D:\TMP] foo /x 5 /y /z
var passed is /x
The subparm of /x is 5
var passed is /y
var passed is /z
Although this is a long way from Obfuscated Perl, I would not recommend it as clear, concise coding practice. The use of SHIFT is much more straightforward and more understandable to traditional .bat coders.
 

Similar threads