Batch "macros" with arguments

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

Re: Batch "macros" with arguments

#46 Post by Ed Dyreen » 01 Jul 2011 12:44

I do NOT recommend that comment because it contains a colon. It will not work properly :!:
Take out the : and it works fine.
That was a joke ben :mrgreen:

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

Re: Batch "macros" with arguments

#47 Post by Ed Dyreen » 02 Jul 2011 04:05


I discovered or should I say failed to discover something that might be of interest.
Sometimes it is usefull to have a macro that defines or undefines other macros.
This works great for functions, but it seems impossible to get it working for macros:

Code: Select all

   set ^"@Debug.on=( %$n1c%

      set "@Ddef=if defined $Debug.Sub" %$n1c%
   )"
This works:

Code: Select all

   set ^"@TraceOut=( %$n1c%

      if defined $Debug.Sub do something %$n1c%
   )"
This seems to be impossible:

Code: Select all

   set ^"@TraceOut=( %$n1c%

      ^^^!@Ddef^^^! do something %$n1c%
   )"
Tried the obvious:

Code: Select all

^^^!@Ddef^^^!
%%@Ddef%%
for.... in
for /f "usebackq" %%^^^! in ( `echo."^!@Ddef^!"` ) do %%~^^^! %$n1c%
etc...
That's too bad, as it could have raised abstraction. Maybe dereferencing is not such a bad idea in this situation, but I'm afraid things would get overly complex. Hard-coding seems to be the easiest :?

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

Re: Batch "macros" with arguments

#48 Post by Ed Dyreen » 05 Jul 2011 07:19


When I try to write a macro to a file, and then use type file everything is good.

However when I open the file there are 2 squares were the linefeeds should be.
I know they represent a linefeed and a carriage return but that was not my intention.
The file needs to have REAL linefeeds, not 2 squares :|

this is my code:

Code: Select all

   set ^"@WriteAdvancedReturn=do ( %$n1c%

      set "$NotDelayedFlag=!" %$n1c%
      setlocal EnableDelayedExpansion %$n1c%

      set "$token=%%~!" %$n1c%

      set "$RetVar=!$token!" %$n1c%
      set "$RetVal=!%%~!!" %$n1c%

      echo.$RetVal=!$RetVal! %$n1c%
   )"

echo.
( for %%! in ( @WriteAdvancedReturn ) %@WriteAdvancedReturn% ) >tst.txt
type tst.txt

%@endoftest%

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#49 Post by dbenham » 05 Jul 2011 09:51

My guess is that the squares are real control characters (both <LF>?) and your editor is choosing to display them as squares. Maybe your editor only recognizes the combination of <CR><LF> as the new line sequence and it displays naked <LF> as a square.

Use a hexdump or hex editor utility to verify exactly what your output is.

Dave Benham

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

Re: Batch "macros" with arguments

#50 Post by Ed Dyreen » 05 Jul 2011 12:37


My editor ?, hmm, I use notepad :?

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#51 Post by dbenham » 05 Jul 2011 13:12

Notepad ignores <LF> on my Vista machine (no line break, no box).

But a Google search shows that others are experiencing what you are seeing: http://forums.ni.com/t5/LabVIEW/Line-fe ... d-p/870878

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

Re: Batch "macros" with arguments

#52 Post by Ed Dyreen » 05 Jul 2011 13:58


Thanx ben, in their solution they are talking about using \r\n instead of \n,
but euh, what is \r, is that a carriage return ?
Does this mean I have to replace <LF> with <CR><LF> before writing to file ?
And will a macro still work if I then try to load it with for "usebackq" ?


I am playing with the idea of writing a macro to a file, so it can be loaded after endlocal.
Thought it would be handy to check defined macros and pasting and splitting macros and stuff.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#53 Post by dbenham » 05 Jul 2011 15:18

Ed Dyreen wrote:but euh, what is \r, is that a carriage return ?
Yes, that would be a carriage return.

Ed Dyreen wrote:Does this mean I have to replace <LF> with <CR><LF> before writing to file ?
No, I don't think that is necessary. However, you might want to use a different text editor. Wordpad maybe? I use ConText - a free programmers editor. There are other free text editors out there.

Ed Dyreen wrote:And will a macro still work if I then try to load it with for "usebackq" ?
I don't think this is an issue if you don't change anything.

Do you plan to define all your macros in one go, spit the definitions out to a file, and then load them back in after ENDLOCAL :?: I'm not sure what kind of escaping you will have to do to preserve the special characters and line feeds in the definitions when you read them back in.

I hope you realize that my macro_BeginDef / macro.EndDef / macro_EndAnyRtn solution is intended to be applied to each macro individually. It really does work, as long as the macro doesn't get too big. And when the macro does become too large you can break it down into smaller macros and use your function that calls a macro to circumvent the problem. I don't see the need to go the temporary file route.

Dave Benham

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

Re: Batch "macros" with arguments

#54 Post by Ed Dyreen » 26 Jul 2011 18:46

'
I have been experimenting with macros for quite a while now.

Due to the fact that a macro definition cannot be larger than 8k,
I looked for solutions, I found that you could paste macro's with a helperfunction.
The results are discouraging.
It seems that large "combined" macro's become actually slower than functions because;
This is one call:

Code: Select all

:function
  @macro
  @macro
  @macro
  @macro
:endfunc
These are 4 calls:

Code: Select all

@combinedmacro=(

  call helperfunc: @macro
  call helperfunc: @macro
  call helperfunc: @macro
  call helperfunc: @macro
)
Now that wasn't dos syntax, all these languages are so confusing :roll:
I was completely ignoring this fact until now :!:
I though keeping helperfunc: in a separate file would be enough but CALL hits hard.
It feels like wasting hundreds of msecs !

Conclusion:
Macros are not a replacement for functions, rather function enhancers.
There is a fragile balance to be chased for "optimal" performance.
To strive for "pure" macro code is bad :twisted:

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#55 Post by dbenham » 26 Jul 2011 21:54

Ed Dyreen wrote:I thought keeping helperfunc: in a separate file would be enough but CALL hits hard.
It feels like wasting hundreds of msecs !
The extreme slowness of CALL is well documented:CALL me, or better avoid call

Ed Dyreen wrote:To strive for "pure" macro code is bad
The moment you call your helper function - it's no longer pure macro. Achieving pure macro code is impossible the moment the task becomes moderately complex. (in other words, more complex than what can be achieved in 8k). So, yes, I suppose trying to achieve the impossible is bad. :wink:

Ed Dyreen wrote:Conclusion:
Macros are not a replacement for functions, rather function enhancers.
There is a fragile balance to be chased for "optimal" performance.
Actually I think macros are a perfect replacement for most utility type functions, given that most functions have a very specific function that does fit within 8k. They most definitely are NOT replacements for entire batch processes.

But I see your point with regard to hybrid macros (macros that use CALL to circumvent the 8k barrier).

In my testing, it is generally faster to call a true macro via a function (my callMacro batch file, your helperfunc), then it is to call the same functionality written as a pure function.

I think a good crude indicator to decide if a hybrid macro is worthwhile is to look at the number of CALLs in the hybrid vs. the number of CALLs it takes to execute a pure function. (Assume the hybrid is executed as a true macro on not through the function) If the hybrid has the same number or fewer calls, then it probably can't hurt.

Don't forget the convenience factor of macro libraries. It is very easy to "include" a macro library in a batch. Not so for a function library.

Also, function libraries tend to slow down as the file size increases. Not generally true with macros. Though I saw where you reported that your large macro project seemed to slow down. I haven't seen that with macros yet.

Dave Benham

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

Re: Batch "macros" with arguments

#56 Post by Ed Dyreen » 26 Jul 2011 23:14

Also, function libraries tend to slow down as the file size increases. Not generally true with macros. Though I saw where you reported that your large macro project seemed to slow down. I haven't seen that with macros yet.
I am starting to believe this has everything to do with DOS memory.
Whenever we use a variable, DOS has to look it up in an array in memory and replace it.
Having a larger array will slow down the lookup process.
Using large amounts of DOS memory can make executables fail to start, run &exit properly.
In this case there is insufficient memory for the exe to properly initialize, and or run.

For example, I lost the ability to directly acces WMIC, It will run, but the result will never be returned to DOS, wmic.exe is idle, but will not shutdown ! Forcing me to launch another instance. It's weird that it works because i did not use the start /i option !
after defining: :|

Code: Select all

start "WMIC.EXE" /wait /high /min "%comspec%" /c 2^> "%%~?" 1^> "%%~!" WMIC.EXE !Alias!

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

Re: Batch "macros" with arguments

#57 Post by Ed Dyreen » 26 Nov 2011 00:23

dbenham wrote:OK - I have finally caught up with the macro "calling" macro discussion. Thanks Jeb and Ed, it's been a good exchange. :D

I had been hoping that the expansion of the inner macro could be delayed until run-time because, as Ed pointed out, I was concerned about the size limit of any single macro definition. But I now realize that there is no avoiding the fact that at run time the entire fully expanded macro must exist in memory as one parsed "statement", so it was a fools dream.
And the fool continiues :)

I want to fit a variable inside another one, but the result is over 8046 chars, so I can't.
But I still can enumerate it's contents, the result is the same, just a bit slower.

Code: Select all

echo.@endoftest>nul
echo.

set "@macro=echo.this is a macro &echo.that uses memory &echo.to hold this text &echo.memory use grows as the macro gets longer &echo.but i'm sure that 1 + 1 equals &set /a "val=1+1" &echo.'!val!'"

setlocal enableExtensions enableDelayedExpansion
:: (
   %@macro%

   for /f "usebackq tokens=*" %%? in ( `echo. ^&!@macro!` ) do echo.%%?
:: )
endlocal

%@endoftest%
result:

Code: Select all

this is a macro
that uses memory
to hold this text
memory use grows as the macro gets longer
but i'm sure that 1 + 1 equals
'2'

this is a macro
that uses memory
to hold this text
memory use grows as the macro gets longer
but i'm sure that 1 + 1 equals
2'2'

 endoftest Druk op een toets om door te gaan. . .
There is a little glitch as you can see, tried some nul redirections but then the text wouldn't get through. :(

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#58 Post by dbenham » 26 Nov 2011 07:29

Is this what you were trying to achieve?

Code: Select all

@echo off
setlocal
set "@macro=echo.this is a macro &echo.that uses memory &echo.to hold this text &echo.memory use grows as the macro gets longer &echo.but i'm sure that 1 + 1 equals &set /a "val=1+1" &rem '!val!'"

setlocal enableExtensions enableDelayedExpansion
set val

for /f "usebackq tokens=*" %%? in ( `echo. ^&!@macro!` ) do echo.%%?

echo(
set val

output:

Code: Select all

Environment variable val not defined

this is a macro
that uses memory
to hold this text
memory use grows as the macro gets longer
but i'm sure that 1 + 1 equals
2

Environment variable val not defined


I see how it works (both versions). But what is is good for :?:


Dave Benham

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

Re: Batch "macros" with arguments

#59 Post by Ed Dyreen » 26 Nov 2011 07:44

:)
so you knew how to do it ?!

I could use this to "call" a macro that would otherwise go over 8k.
I realize for takes time, but a function call takes time too.
I was wondering what would be fastest...

Thought it might be relevant...

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: Batch "macros" with arguments

#60 Post by dbenham » 26 Nov 2011 08:04

You do know that FOR IN() clause commands are executed in their own CMD session :?:

I'm wondering if there is a limit to the size of the command that CMD can take :?:

Also, the environment changes that take place within the IN() clause cannot be propagated back to the parent session. (Unless of course you use temporary files). Notice how VAR is undefined both before and after the FOR execution in my code example.

This is interesting, but I'm not seeing how it is useful for exceeding the 8k limit.

Dave Benham

Post Reply