Page 1 of 1

Setup a batch macro by calling a different file

Posted: 07 Mar 2017 02:31
by Sounak@9434
Hello again everyone.
This time I'm working with a batch macro.
I'm working on a alignment macro. Here is the script.

Code: Select all

@echo off
setlocal disabledelayedexpansion
set ^"LF=^
%= This creates a variable containing a single linefeed (0x0A) character =%
^"
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set @align=for %%. in (1 2) do if %%.==2 (%\n%
 setlocal%\n%
 for %%1 in (!argv!) do (%\n%
   if not defined _align (if "%%1"=="/s" (set "_line=") ELSE (set "_align=%%1")) ELSE (%\n%
     if not defined _text (set "_text=%%~1") ELSE (%\n%
      if not defined _var if "%%1" neq "" set "_var=%%1"%\n%
     )%\n%
    )%\n%
   )%\n%
   if not defined _line for /f "skip=4 tokens=2 delims= " %%a in ('mode con') do if not defined _line set "_line=%%a"%\n%
   set "_s=A!_text!"%\n%
   set "_len=0"%\n%
   for %%p in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (%\n%
     if "!_s:~%%p,1!" neq "" (%\n%
      set /a "_len+=%%p"%\n%
      set "_s=!_s:~%%p!"%\n%
     )%\n%
   )%\n%
   set /a "_space=!_line!-!_len!"%\n%
   if "!_align!"=="/m" set /a _space/=2%\n%
   if "!_align!"=="/l" set _space=0%\n%
   if "!_align!"=="/r" set /a _space-=1%\n%
   set "_bsp="%\n%
   for /l %%A in (1,1,!_space!) do set "_bsp=!_bsp! "%\n%
   if not defined _var for %%V in ("!_bsp!!_text!") do (endlocal^&endlocal^&endlocal^&echo %%~V) ELSE for %%Z in ("!_var!") do for %%V in ("!_bsp!!_text!") do (endlocal^&endlocal^&endlocal^&set %%~Z=%%~V)%\n%
) else setlocal enabledelayedexpansion^&setlocal^&set argv=
%@align% /m "Hello world"
%@align% /r "Goodbye Cruel World" _out
echo(%_out%

But according to my tests so many amounts of for loop used in the script has slowed down the script a lot.
I have a different approach with an additional batch file that uses string-length macro.
Here is the script.

Code: Select all

@echo off
::Align.bat
::Show help check
if "%~1"=="" type help.txt&exit /b
if "%~1"=="/?" type help.txt&exit /b
::Line reset check
if "%~1"=="/s" set "_line="&shift
::Getting Data
set "_align=%1"
set "_text=%~2"
if not "%~3"=="" set "_var=%~3"
::Getting window length if not defined
if not defined _line for /f "skip=4 tokens=2 delims= " %%a in ('mode con') do if not defined _line set "_line=%%a"
::Setting up variables if not done already
if not defined @strlen call :macro
::Getting string length
%@strlen% _text _len
::Mathematical part
set /a "_space=%_line%-%_len%"
if "%_align%"=="/m" set /a _space/=2
if "%_align%"=="/l" set _space=0
if "%_align%"=="/r" set /a _space=%_space%-1
::Setting up spaces
setlocal enabledelayedexpansion
for /l %%a in (1,1,%_space%) do set "_bsp=!_bsp! "
::Printing aligned text or setting it to a variable for further use
if not defined _var (echo(%_bsp%%_text%) ELSE (endlocal&&endlocal&&set %_var%=%_bsp%%_text%)
exit /b
:macro
::Creating string length macro
::Created at dostips.com
set ^"LF=^
%= This creates a variable containing a single linefeed (0x0A) character =%
^"
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set @strLen=for %%. in (1 2) do if %%.==2 (%\n%
  for /f "tokens=1,2 delims=, " %%1 in ("!argv!") do ( endlocal%\n%
    set "s=A!%%~1!"%\n%
    set "len=0"%\n%
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (%\n%
      if "!s:~%%P,1!" neq "" (%\n%
        set /a "len+=%%P"%\n%
        set "s=!s:~%%P!"%\n%
      )%\n%
    )%\n%
    for %%V in (!len!) do endlocal^&if "%%~2" neq "" (set "%%~2=%%V") else echo %%V%\n%
  )%\n%
) else setlocal enableDelayedExpansion^&setlocal^&set argv=,

This code is pretty much twice as fast but it needs to set up the "@strlen" file each time which I want to avoid.
Adding an endlocal is not possible because the macro needs delayed expansion as disabled.
So people, any Idea about how to permanently setup the '@strlen' macro so that while calling the script from a separate file it would not need to set up the value of '@strlen'?

Re: Setup a batch macro by calling a different file

Posted: 07 Mar 2017 11:34
by aGerman
Why so complicated? Just take the :strLen function and modify it in order to avoid the call of a label and insert it into your code.

Code: Select all

::Getting string length
setlocal EnableDelayedExpansion
set "str=A!_text!" &set "len=0"
for /L %%A in (12,-1,0) do (
  set /a "len|=1<<%%A"
  for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
endlocal &set /a "_len=%len%"

Steffen

Re: Setup a batch macro by calling a different file

Posted: 07 Mar 2017 12:16
by Squashman
I know Dave came up with better align routine then the one in the library. Can't find it at the moment.

Found it.
viewtopic.php?t=4027

Re: Setup a batch macro by calling a different file

Posted: 07 Mar 2017 13:25
by aGerman
Right and left alignments are pretty simple tasks. Only for center-aligned text you would even need the string length.

Steffen

Re: Setup a batch macro by calling a different file

Posted: 07 Mar 2017 21:59
by Sounak@9434
aGerman wrote:Why so complicated? Just take the :strLen function and modify it in order to avoid the call of a label and insert it into your code.

Code: Select all

::Skipped

Steffen

@aGerman: I am actually using it this way at this moment but I'm just curious if a batch macro can be set up by a different file.
Like we add a 'load-macros.bat' with the main file as adding macro setup in the beginning only makes the script hard for beginners to understand.
Of course we can keep these macros in the end and use a call command but.........Just thought if that was possible.

Squashman wrote:I know Dave came up with better align routine then the one in the library. Can't find it at the moment.

Found it.
http://www.dostips.com/forum/viewtopic.php?t=4027

@Squashman: Thanks these new scripts helped a lot. I had found some on the forum already. Just wanted to test the macro function and build one macro myself. Thanks anyway :wink:

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 02:27
by jeb
Hi Sounak@9434,

Sounak@9434 wrote: I'm just curious if a batch macro can be set up by a different file.

There is no problem for macros, it's even easier than to use functions from other files, as the macro definitions only need to set the macro variables.

And when you also use also a macro for returning values from setlocal scope (former: "endlocal barrier") you can even define the macros in a defined setlocal environment, normally that would be setlocal DisableDelayedExpansion.

AllMacros.bat wrote:setlocal DisableDelayedExpansion
set LF=^
...
set @endlocalMacro=for ...

%@endlocalMacro% @endlocalMacro

setlocal DisableDelayedExpansion
set LF=^
...
set @myNextMacro=...
%@endlocalMacro% @myNextMacro

jeb

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 07:33
by Sounak@9434
jeb wrote:
AllMacros.bat wrote:setlocal DisableDelayedExpansion
set LF=^
...
set @endlocalMacro=for ...

%@endlocalMacro% @endlocalMacro

setlocal DisableDelayedExpansion
set LF=^
...
set @myNextMacro=...
%@endlocalMacro% @myNextMacro

jeb


Thanks jeb, but I'm not sure about which '@endlocalMacro' you are talking about. Is it this one or this one?
Thanks in advance, Sounak.

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 10:35
by penpen
@Sounak@9434:
I've once made a tool ("packageToMacro.bat") to create such loadMacro.bat files:
http://www.dostips.com/forum/viewtopic.php?f=3&t=5871.

But i noticed, that i've messed up the example:
I currently have a tooth root infection, so i left it "as is" and give just an example here how to use it (i hope this is sufficient).

"SampleFile.txt":

Code: Select all


@for %%N in (0 1) do @if %%N == 1 (
   echo Hello world!
)


"AnotherSampleFile.txt":

Code: Select all


@for %%N in (0 1) do @if %%N == 1 (
   echo Main routine
   set params
) else set params=,



"SamplePackage.txt":

Code: Select all

#packInfo Some               info
#packInfo      text      the
#packInfo           with
#packInfo

#packInfo      other
#packInfo
#packInfo Some       text

#macroDef "SampleMacro.txt"
#macroDef Some
#macroDef macro
#macroDef info
#macroDef text.

#macroDef "AnotherSampleMacro.txt"
#macroDef Some
#macroDef macro
#macroDef info
#macroDef text2.


Create the loader for your macro using:

Code: Select all

Z:\>packageToMacro.bat "SamplePackage.txt" "loadSamplePackage.bat"
started:  17:23:29,00
File "table.dat" with binary ascii data [0x20, 0x01 : 0xFF] does not exist.
This file is needed, so it will be created: This may take a while.
        1 Datei(en) verschoben.
Successfully created file: "table.dat".
finsihed: 17:23:46,83

Z:\>loadSamplePackage.bat

Z:\>%$SampleMacro%
Hello world!

Z:\>%$AnotherSampleMacro% a b c
Main routine
params=,  a b c

Z:\>
Note: Don't delete the file "table.dat", or it has to be rebuild every time.


penpen

Edit: Added "SamplePackage.txt".

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 11:19
by Sounak@9434
@penpen:Cool method penpen. Just one questions.
1)Do I need to have one separate file for each macros? Meaning 3 files for '@strlen' & '@align' and one 'Package.txt'?

@jeb: Maybe you meant this one. I tested it on my macro script and it failed as it only set the last line ') else setlocal enabledelayedexpansion^&setlocal^&set argv=' to @align variable.

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 12:18
by aGerman
Sounak@9434 wrote:I'm just curious if a batch macro can be set up by a different file.

Sure.

strlen_init.bat

Code: Select all

set ^"LF=^
%= This creates a variable containing a single linefeed (0x0A) character =%
^"
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
set @strLen=for %%. in (1 2) do if %%.==2 (%\n%
  for /f "tokens=1,2 delims=, " %%1 in ("!argv!") do ( endlocal%\n%
    set "s=A!%%~1!"%\n%
    set "len=0"%\n%
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (%\n%
      if "!s:~%%P,1!" neq "" (%\n%
        set /a "len+=%%P"%\n%
        set "s=!s:~%%P!"%\n%
      )%\n%
    )%\n%
    for %%V in (!len!) do endlocal^&if "%%~2" neq "" (set "%%~2=%%V") else echo %%V%\n%
  )%\n%
) else setlocal enableDelayedExpansion^&setlocal^&set argv=,



whatever.bat

Code: Select all

@echo off &setlocal DisableDelayedExpansion

call strlen_init.bat

set "string=Hello, World!"

set "length="
%@strlen% string length
echo %length%

pause

Steffen

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 14:29
by penpen
Sounak@9434 wrote:Do I need to have one separate file for each macros? Meaning 3 files for '@strlen' & '@align' and one 'Package.txt'?
Yes, but it compiles to one "loadPackage.bat". The main reason was to know the maximum filesize of the dummy file, but doing it this way also has the advantage that one source file could be reused in many packages without find-copy-paste the source.


penpen

Re: Setup a batch macro by calling a different file

Posted: 08 Mar 2017 21:14
by Sounak@9434
@aGerman: Cool, :D Beautiful method Steffen.
@penpen: You have a point penpen. In your way the source can be used in many differant ways.
But lets see, if We want to add everything in a single file (Means, creating those macroes and loadmacros.bat by redirection) a simple macro would become like this.

Code: Select all

echo(setlocal disabledelayedexpansion>>basicmacro.bat
echo(set LF=^^>>basicmacro.bat
echo(>>basicmacro.bat
echo(>>basicmacro.bat
echo(set ^^"\n=^^^%%LF%%%%LF%%^%%LF%%%%LF%%^^">>basicmacro.bat
echo(set @macro=for %%%%. in (1 2) do if %%%%. equ 2 (%%\n%%>>basicmacro.bat
echo(   echo(!args!%%\n%%>>basicmacro.bat
echo(   endlocal%%\n%%>>basicmacro.bat
echo() else setlocal enabledelayedexpansion^^^&setlocal^^^&set /p args=>>basicmacro.bat

Not too much tough to create though. Thanks again penpen.

I'll be still looking for more answers. Especially for, about which endlocal macro jeb was talking about.

Thanks again everyone.

Sounak