DOS - Function Collection

The functions listed in this section serve as copy source to enhance your batch program.Simply copy paste the function into your batch program and start calling them.The provided test codes serve as examples on how to call the functions.

 

1††††† Variable Persistency - :setPersist, :getPersistentVars, :savePersistentVars, :restorePersistentVars1

2††††† String Trimming Left and Right - :trim, :trimLeft, :trimRight. 2

3††††† String Length - :strLen. 3

4††††† Time Of Day and runtime measurements - :getTod, :getHHMMSSDD, :Tod2Str, :TodDiffNow4

5††††† Circulate thru a List - :getNextInList. 5

6††††† Choose from List of last entered Values - :choiceListInput. 6

7††††† Opening the Registry Editor at a defined Location - :regedit. 9

8††††† Float <-> Integer Conversion - :F2I, :I2F. 9

9††††† Extracting text blocks from a File - :extractFromFile. 11

10†††††††† Get THIS computers IP address - :getIP. 13

11†††††††† Wait, Sleep, Hold - :sleep. 13

12†††††††† Progress Indicator - :initProgress, :doProgress. 13

 

  

1        Variable Persistency - :setPersist, :getPersistentVars, :savePersistentVars, :restorePersistentVars

 

Variable persistency can be archived by storing the variable of interest into a file when the DOS batch terminates and read them back in when the DOS batch starts up.The setPersist function marks a variable to be persistent.The savePersistentVars function stores the persistent variables into a file.The restorePersistentVars function reads the variables back in from a file.

What itís good for

        Remembering the state of the batch program for the next run

        Allow user profiles

        Store information to be used in the next run

        Implement execution counters

 Code

:setPersist -- to be called to initialize persistent variables

::††††††††† -- %*: set command arguments

set %*

GOTO:EOF

 

 

:getPersistentVars -- returns a comma separated list of persistent variables

::†††††††††††††††† -- %~1: reference to return variable

SETLOCAL

set retlist=

set parse=findstr /i /c:"call:setPersist" "%~f0%"^|find /v "ButNotThisLine"

for /f "tokens=2 delims== " %%a in ('"%parse%"') do (set retlist=!retlist!%%a,)

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" SET %~1=%retlist%

)

GOTO:EOF

 

 

:savePersistentVars -- Save values of persistent variables into a file

::††††††††††††††††† -- %~1: file name

SETLOCAL

echo.>"%~1"

call :getPersistentVars persvars

for %%a in (%persvars%) do (echo.SET %%a=!%%a!>>"%~1")

GOTO:EOF

 

 

:restorePersistentVars Ė- Restore the values of the persistent variables

::†††††††††††††††††††† -- %~1: batch file name to restore from

if exist "%FilePersist%" call "%FilePersist%"

GOTO:EOF

 

 

Test Code

rem.--define the filename where persistent variables get stored

rem.just add a + to the name of THIS file, i.e. "DosTips.bat" - "DosTips+.bat"

set FilePersist=%~dpn0+%~x0

 

rem.--initialize the persistent variables

call:setPersist var=Hello

 

rem.--read the persistent variables from the storage

call:restorePersistentVars "%FilePersist%"

 

rem.--modify the persistent variable

echo.var = '%var%'

echo.

echo.Enter new string for var then run the batch again.

set /p var=var =

 

rem.--save the persistent variables to the storage

call:savePersistentVars "%FilePersist%"

 

 

Test Code Output

var = 'Hello'

 

Enter new string for var then run the batch again.

var =

2        String Trimming Left and Right - :trim, :trimLeft, :trimRight

 

Three functions to trim spaces around a value, i.e. left, right, left and right.

 Code

:trimLeft -- trim leading spaces

:†††††††† -- %~1: variable reference, string to be trimmed

for /f "tokens=* delims= " %%a in ("!%~1!") do set %~1=%%a

GOTO:EOF

 

 

:trimRight -- trim trailing spaces

:††††††††† -- %~1: variable reference, string to be trimmed

SETLOCAL

set s=!%~1!

:trimRight_LOOP

if "%s:~-1%"==" " set s=%s:~0,-1%&goto:trimRight_LOOP

(ENDLOCAL & REM.-- RETURN VALUES

††† IF "%~1" NEQ "" SET %~1=%s%

)

GOTO:EOF

 

 

:trim -- trim leading and trailing spaces

:†††† -- %~1: variable reference, string to be trimmed

call:trimLeft %~1

call:trimRight %~1

GOTO:EOF

 

 

Test Code

set s=left trim nothing&††††††††††††††††† call:trimLeft s&echo."!s!"

set s= left trim one&†††††††††††††††††††† call:trimLeft s&echo."!s!"

set s=†††††††††††††††††† left trim plenty&call:trimLeft s&echo."!s!"

set s=right trim nothing&†††††††††††††††† call:trimRight s&echo."!s!"

set s=right trim one &††††††††††††††††††† call:trimRight s&echo."!s!"

set s=right trim plenty††††††††††††††††† &call:trimRight s&echo."!s!"

set s=trim nothing&†††††††††††††††††††††† call:trim s&echo."!s!"

set s= trim one left and one right &††††† call:trim s&echo."!s!"

set s=††† trim plenty left and right†††† &call:trim s&echo."!s!"

 

 

Test Code Output

"left trim nothing"

"left trim one"

"left trim plenty"

"right trim nothing"

"right trim one"

"right trim plenty"

"trim nothing"

"trim one left and one right"

"trim plenty left and right"

3        String Length - :strLen

 

The :strLen function uses a binary search approach to determine the length of a string.

 Code

:strLen -- returns the length of a string via binary search, maximum length 1023

::††††† -- %~1: in - varible name of a string variable

::††††† -- %~2: out- string length

SETLOCAL

set str=A!%~1!&rem keep the A up front to ensures we get the length and not the upper bond

†††††††††††††††† rem it also avoids trouble in case of empty string

set len=0

set /a n=1024

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

set /a n^>^>=1, len+=n

if !str:~%len%!. == . set /a len-=n

( ENDLOCAL & REM RETURN VALUES

††† IF "%~2" NEQ "" SET %~2=%len%

)

GOTO:EOF

 

 

Test Code

for /l %%a in (0,1,10) do (

††† set s=

††† for /l %%b in (0,1,%%a) do if /i %%b NEQ 0 set s=!s!x

††† call:strLen s len

††† echo."!s!" - length !len!

)

 

 

Test Code Output

"" - length 0

"x" - length 1

"xx" - length 2

"xxx" - length 3

"xxxx" - length 4

"xxxxx" - length 5

"xxxxxx" - length 6

"xxxxxxx" - length 7

"xxxxxxxx" - length 8

"xxxxxxxxx" - length 9

"xxxxxxxxxx" - length 10

4        Time Of Day and runtime measurements - :getTod, :getHHMMSSDD, :Tod2Str, :TodDiffNow

 

The getTod function returns a Time Of Day (Tod) integer value with a precision of 1/100th of a second.Together with the other functions this can be used for time capture calculations like runtime measurements.

The getHHMMSSDD function allows extracting the hours, minutes, seconds, and 1/100th of seconds from a Tod integer.

The Tod2Str function allows to freely format a Tod integer into a string, i.e. put the seconds, hours, minutes where you want them.

What itís good for

        Runtime measurement

Limits

        No corrector for days where daylight saving time is being turned on or off

Code

:getTod -- get a Time of Day value in 1/100th seconds

::†† -- %~1: out - timo of day

SETLOCAL

set /a t=0

for /f "tokens=1-4 delims=:." %%a in ("%time: =0%") do set /a t=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" SET %~1=%t%

)

GOTO:EOF

 

 

:getHHMMSSDD -- split a Time Of Day integer into hours, minutes, seconds, 1/100th

::†††††††††† -- %~1: in- time of day as integer

::†††††††††† -- %~2: out - hours

::†††††††††† -- %~3: out - minutes

::†††††††††† -- %~4: out - seconds

::†††††††††† -- %~5: out - 1/100th

SETLOCAL

set /a t=%~1

set /a hh=t/360000

set /a t-=hh*360000

set /a mm=t/6000

set /a t-=mm*6000

set /a ss=t/100

set /a t-=ss*100

( ENDLOCAL & REM RETURN VALUES

††† IF "%~2" NEQ "" SET %~2=%hh%

††† IF "%~3" NEQ "" SET %~3=%mm%

††† IF "%~4" NEQ "" SET %~4=%ss%

††† IF "%~5" NEQ "" SET %~5=%t%

)

GOTO:EOF

 

 

:Tod2Str -- format a Time Of Day integer into a time string

::†††††††††††† -- %~1: out - output string

::†††††††††††† -- %~2: in- time of day

::†††††††††††† -- %~3: in- formatter string, default is HH:MM:SS.DD

SETLOCAL

set tod=%~2

set f=%~3

if "%f%"=="" set f=[TTTT]&††††††††††† rem --if no format given assume [TTTT] format

set f=%f:[TTTT]=[H]:[MM]:[SS].[DD]%&rem --replace [TTTT] with the default format

call:getHHMMSSDD tod h m s d&†††††††† rem --extract the numbers from the Time Of Day value

rem -- ensure two digits, add leading 0 where necessarily

set HH=0!h!&set HH=!HH:~-2!

set MM=0!m!&set MM=!MM:~-2!

set SS=0!s!&set SS=!SS:~-2!

set DD=0!d!&set DD=!DD:~-2!

rem -- replace the format specifyiers with real values

set f=!f:[HH]=%HH%!

set f=!f:[MM]=%MM%!

set f=!f:[SS]=%SS%!

set f=!f:[DD]=%DD%!

set f=!f:[H]=%h%!

set f=!f:[M]=%m%!

set f=!f:[S]=%s%!

set f=!f:[D]=%d%!

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" (SET %~1=%f%) ELSE (ECHO.%f%)

)

GOTO:EOF

 

 

:TodDiffNow -- echos the time of day difference of Now-Base

::††††††††† -- %~1: in - Base time as variable

::††††††††† -- %~2: in - formatter string, default is HH:MM:SS.DD

::††††††††† -- %~3: out- diff time or empty for screen output

SETLOCAL

set base=!%~1!

call:getTod curr&††††††††††††††††††† rem --get the current Time Of Day

set /a diff=curr-base&†††††††††††† ††rem --subtract the base to get the difference

if /i diff LSS 0 diff+=24*60*60*100& rem --when measuring over midnight add a full day

call:Tod2Str s %diff% "%~2"&†††††††† rem --format the difference as string

( ENDLOCAL & REM RETURN VALUES

††† IF "%~3" NEQ "" (SET %~3=%s%) ELSE (ECHO.%s%)

)

GOTO:EOF

 

 

Test Code

set delay=5

call:getTod t

echo.Starting a %delay%s delay via ping...

FOR /l %%a in (%delay%,-1,1) do ping -n 2 -w 1 127.0.0.1>NUL

echo....finished.

call:TodDiffNow t "The %delay%s delay via ping really took [TTTT]"

 

 

Test Code Output

Starting a 5s delay via ping...

...finished.

The 5s delay via ping really took 0:00:06.39

 

 

5        Circulate thru a List - :getNextInList

 

The getNextInList function allows a variable to circulate thru a set of values.Each time calling this function the next entry in the choice list will be returned.After passing the last entry the function will start again with the first entry.

What itís good for

        Creating a state automat in DOS

        Let the user circulate through option rather than force typing.

 Code

:getNextInList -- return next value in list

::†††††††††††† -- %~1 - in/out ref to current value, returns new value

::†††††††††††† -- %~2 - in†††† choice list, must start with delimiter which must not be '@'

SETLOCAL

set lst=%~2&†††††††††††† rem.-- get the choice list

if "%lst:~0,1%" NEQ "%lst:~-1%" echo.ERROR Choice list must start and end with the delimiter&GOTO:EOF

set dlm=%lst:~-1%&†††††† rem.-- extract the delimiter used

set old=!%~1!&†††††††††† rem.-- get the current value

set fst=&for /f "delims=%dlm%" %%a in ("%lst%") do set fst=%%a&rem.--get the first entry

†††††††††††††††††††††††† rem.-- replace the current value with a @, append the first value

set lll=!lst:%dlm%%old%%dlm%=%dlm%@%dlm%!%fst%%dlm%

†††††††††††††††††††††††† rem.-- get the string after the @

for /f "tokens=2 delims=@" %%a in ("%lll%") do set lll=%%a

†††††††††††††††††††††††† rem.-- extract the next value

for /f "delims=%dlm%" %%a in ("%lll%") do set new=%%a

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" (SET %~1=%new%) ELSE (echo.%new%)

)

GOTO:EOF

 

 

Test Code

rem.--modify the persistent variable

set choiceList=,MO,TU,WE,TH,FR,SA,SU,

echo.choice list = "%choiceList%"

set var=

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

echo.var = '%var%'&call:getNextInList var "%choiceList%"

 

 

Test Code Output

choice list = ",MO,TU,WE,TH,FR,SA,SU,"

var = ''

var = 'MO'

var = 'TU'

var = 'WE'

var = 'TH'

var = 'FR'

var = 'SA'

var = 'SU'

var = 'MO'

var = 'TU'

Note

If var starts out empty or with a bogus value then the getNextInChoiceList function will assign the first value in the choice list, which is nice default behavior.

6        Choose from List of last entered Values - :choiceListInput

 

The choiceListInput function lets the user enter a value.The value entered is returned by the function and added to the end of a choice list.The choice list is shown next time this function is being called, and thus allows the user to pick from the list of last entered value.The last chosen or newly entered value is added to the end of the choice list and acts as default input next time this function is being called.

The choice list is being stored into a variable.The name of this variable is to be passed into the function, which allows this function to be called using different choice lists.

What itís good for

        Increases user efficiency

        Allows picking number from list instead of having to enter a long strings

        Only need to pick a value when different from last run, otherwise just hit enter

Tip

Make the choice list variable persistent in order to have it available over multiple batch file executions.

 Code

:choiceListInput Ė lets the user choose from list of last entered values

:††††††††††††††† -- %~1 - out, returns input value

:††††††††††††††† -- %~2 - in/out, ref to choice list, returns trimmed reordered choice list

:††††††††††††††† -- %~3 - in, list title

:††††††††††††††† -- %~4 - in, list entry count limit

SETLOCAL ENABLEDELAYEDEXPANSION

set l=,!%~2!,&††††††††† rem.-- get the choice list

set t=%~3&††††††††††††† rem.-- get the list title

set c=%~4&††††††††††††† rem.-- get the list entry count limit

set m=&†††††††††††††††† rem.-- a message

set l2=,

set v=

:choiceListInput_LOOP1

echo.%t%

set i=0&for %%a in (%l%) do (

†† set /a i+=1

††† set l2=!l2!!i!;%%~a,

††† set v=%%~a

††† echo.!i! - %%~a

)

if "%m%" NEQ "" echo.^>^> %m%

echo.Make a choice or enter a new value [%v%]

set v1=%v%

set /p v1=:

echo.

set v2=!v1!&set v2=!v2:,=!&set v2=!v2:@=!&set v2=!v2:;=!&set v2=!v2:"=!

rem.--reject entry with illegal character

if "!v1!" NEQ "!v2!" (

††† set m=Note: ,;@" and empty string not allowed.Try again.

††† goto:choiceListInput_LOOP1

)

rem.--if first character is minus then remove the entry

set remove=&if "%v1:~0,1%"=="-" set remove=y&set v1=%v1:~1%

set v=%v1%

rem.--if number chosen then find corresponding value

set l3=!l2:,%v%;=,@!

if "%l3%" NEQ "%l2%" (

††† for /f "delims=@ tokens=2" %%a in ("!l3!") do set l3=%%a

††† for /f "delims=,"††††††††† %%a in ("!l3!") do set v=%%a

)

rem.--remove value from list if exist

set l3=%l%

set l=!l:,%v%,=,!

if "%remove%"=="y" (

††† if "%l%"=="%l3%" (set m='%v%' cannot be removed from list

††† ) ELSE (set m='%v%' has been removed from list)

††† goto:choiceListInput_LOOP1

)

if "%l%"=="%l3%" echo.^>^>'%v%' has been added to the list

rem.--add to the value to the end

set l=!l:~1!%v%

rem.--enforce the list entry count limit if requested

if "%c%" NEQ "" (

††† set i=0&for %%a in (%l%) do set /a i+=1

††† if /i !i! GTR !c! (

††††††† for /f "delims=, tokens=1,*" %%a in ("!l!") do (

††††††††††† set l=%%b

††††††††††† echo.^>^>'%%a' dropped out of the list

††††††† )

††† )

)

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" (SET %~1=%v%) ELSE (echo.%v%)

††† IF "%~2" NEQ "" (SET %~2=%l%) ELSE (echo.%l%)

)

goto :eof

 

 

Test Code

if "%~1"=="" (

††† set z=%~dpn0.tmp

††† if exist "!z!" del "!z!"

††† echo.a>>"!z!"

††† echo.b>>"!z!"

††† echo.c>>"!z!"

††† echo.d>>"!z!"

††† echo.>>"!z!"

††† echo.2>>"!z!"

††† echo.-d>>"!z!"

††† echo.-1>>"!z!"

††echo.-1>>"!z!"

††† echo.z>>"!z!"

††† "%~f0" auto<"!z!"

)

 

rem.--modify the persistent variable

 

set choiceList=

set var=

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

call:choiceListInput var choiceList "Selection List:" 3&echo.--'!var!' has been selected

Test Code Output

Selection List:

Make a choice or enter a new value []

:

>>'a' has been added to the list

--'a' has been selected

Selection List:

1 - a

Make a choice or enter a new value [a]

:

>>'b' has been added to the list

--'b' has been selected

Selection List:

1 - a

2 - b

Make a choice or enter a new value [b]

:

>>'c' has been added to the list

--'c' has been selected

Selection List:

1 - a

2 - b

3 - c

Make a choice or enter a new value [c]

:

>>'d' has been added to the list

>>'a' dropped out of the list

--'d' has been selected

Selection List:

1 - b

2 - c

3 - d

Make a choice or enter a new value [d]

:

--'d' has been selected

Selection List:

1 - b

2 - c

3 - d

Make a choice or enter a new value [d]

:

--'c' has been selected

Selection List:

1 - b

2 - d

3 - c

Make a choice or enter a new value [c]

:

Selection List:

1 - b

2 - c

>> 'd' has been removed from list

Make a choice or enter a new value [c]

:

Selection List:

1 - c

>> 'b' has been removed from list

Make a choice or enter a new value [c]

:

Selection List:

1 - c

>> 'b' cannot be removed from list

Make a choice or enter a new value [c]

:

>>'z' has been added to the list

--'z' has been selected

 

 

7        Opening the Registry Editor at a defined Location - :regedit

 

When opening the registry editor regedit.exe it will have the last registry key remembered and opens right where the user left off the last time running it.The last registry key is being remembered in the registry itself using the LastKey value in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit.To have regedit.exe open up at a specific location we just have to set the LastKey value properly before invoking the regedit.exe.The regedit function

What is it good for

        Increasing user efficiency

        Shortcut for frequently observed registry entries

Code

:regedit Ė opens the regedit at a defined location

:††††††† -- %~1 - location

SETLOCAL

set StartKey=%~1

set tmpfile=%Temp%\RegeditLastKey.reg&††††† rem --use a temporary .reg file to be imported via regedit

set StartKey=%StartKey:\=\\%&†††††††††††††† rem --double up the back slashes

echo.Windows Registry Editor Version 5.00>"%tmpfile%"

echo.[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit]>>"%tmpfile%"

echo."LastKey"="%StartKey%">>"%tmpfile%"

regedit /s "%tmpfile%"&†††††††††††††††††††† rem --import the temporary .reg file

start /b regedit&†††††††††††††††††††††††††† rem --launch the registry editor and continue

GOTO:EOF

 

 

Test Code

REM --this example WILL open the registry editor at HKEY_CURRENT_USER\Software\Microsoft

call:regedit "HKEY_CURRENT_USER\Software\Microsoft"

8        Float <-> Integer Conversion - :F2I, :I2F

 

DOS does not support floating point arithmetic.However with a little trick floating point arithmetic is still possible.A string storing a floating point value can be converted into an integer using the F2I function.To preserve precision the float will be multiplied by 10, 100, 1000, or more so that the fractions move into the integer part of the value.Having an integer now the value can be used in calculation using standard DOS commands.At the end the integer can be converted back into a float using the I2F function.

This works perfect for additions and subtractions.

The result of a multiplication of two factors will need to be divided by the correcting factor 10, 100, 1000, or whatever was used.

In a division it is necessarily to multiply the dividend first the correcting factor 10, 100, 1000, or whatever was used.

Code 

:F2I†††††††††††††† -- float to integer

:††††††††††††††††† -- %~1: var ref, for in place conversion

:††††††††††††††††† -- %~2: precision

SETLOCAL

set f=!%~1!

set /a prec=%~2 + 1&rem.--keep one more for rounding

set nnn=&for /l %%n in (1,1,%prec%) do set nnn=!nnn!0

set mul=1%nnn%

for /f "tokens=1,2 delims=. " %%a in ("%f%") do (set f1=%%a&set f2=%%b%nnn%)

set f2=1!f2:~0,%prec%!&rem.--HexCludge--need the 1 up front to not be confused with hex

set /a i=f1*mul+f2

set /a i+=5&rem.--ensure correct rounding

set /a i-=mul&rem.--HexCludge--need to subtract the 1 added earlier

set i=%i:~0,-1%

(ENDLOCAL & REM.-- RETURN VALUES

††† IF "%~1" NEQ "" SET %~1=%i%

)

GOTO:EOF

 

 

:I2F†††††††††††††† -- integer to float

:††††††††††††††††† -- %~1: var ref, for in place conversion

:††††††††††††††††† -- %~2: precision

SETLOCAL

set i=!%~1!

set prec=%~2

set nnn=&for /l %%n in (1,1,%prec%) do set nnn=!nnn!0

set mul=1%nnn%

set /a f1=i/mul

set /a f2=i%%mul

set f2=%nnn%%f2%

set f2=!f2:~-%prec%!

set f=%f1%.%f2%

(ENDLOCAL & REM.-- RETURN VALUES

††† IF "%~1" NEQ "" SET %~1=%f%

)

GOTO:EOF

 

 

Test Code

echo.Example conversion Float to Integer

set x=3.03

call:F2I x 3&echo.%x%†† F2I†† !x!

set x=1.1††

call:F2I x 3&echo.%x%†† F2I†† !x!

set x=1.1114

call:F2I x 3&echo.%x%†† F2I†† !x!

set x=1.1115

call:F2I x 3&echo.%x%†† F2I†† !x!

set x=9.9994

call:F2I x 3&echo.%x%†† F2I†† !x!

set x=9.9995

call:F2I x 3&echo.%x%†† F2I†† !x!

echo.

echo.Example conversion Integer to Float

set y=1††††

call:I2F y 3&echo.%y%†† I2F†† !y!

set y=12†††

call:I2F y 3&echo.%y%†† I2F†† !y!

set y=123††

call:I2F y 3&echo.%y%†† I2F†† !y!

set y=1000

call:I2F y 3&echo.%y%†† I2F†† !y!

set y=1234

call:I2F y 3&echo.%y%†† I2F†† !y!

set y=12345

call:I2F y 3&echo.%y%†† I2F†† !y!

 

echo.

set /p x=Input x=

set /p y=Input y=

call:F2I x 3

call:F2I y 3

set calc=x*y & set /a z=!calc!/1000 & call:I2F z 3 & echo.!calc!= !z!

set calc=x/y & set /a z=1000*!calc! & call:I2F z 3 & echo.!calc!= !z!

set calc=x+y & set /a z=!calc!††††† & call:I2F z 3 & echo.!calc!= !z!

set calc=x-y & set /a z=!calc!††††† & call:I2F z 3 & echo.!calc!= !z!

 

 

Test Code Output

Example conversion Float to Integer

3.03†††† F2I†† 3030

1.1††††† F2I†† 1100

1.1114†† F2I†† 1111

1.1115†† F2I†† 1112

9.9994†† F2I†† 9999

9.9995†† F2I†† 10000

 

Example conversion Integer to Float

1††††††† I2F†† 0.001

12†††††† I2F†† 0.012

123††††† I2F†† 0.123

1000†††† I2F†† 1.000

1234†††† I2F†† 1.234

12345††† I2F†† 12.345

 

Input x=12.12

Input y=3.03

x*y = 36.723

x/y = 4.000

x+y = 15.150

x-y = 9.090

9        Extracting text blocks from a File - :extractFromFile

 

The extractFromFile function allows extracting blocks of lines from a file the extracted block will be send to the output window or can optionally be piped into a file.

Each block is identified by a begin marker and an optional end marker.If the end marker is omitted then the extraction stops at the end of the file.

If begin marker can be any string that is unique with in the file.If the begin marker end with a $ sign then all variables used in the block are being substituted by its values.

What itís good for

        Compact DOS batch, easy distribution

        Embedding text blocks within the batch file itself to be extracted at runtime

        I.e. Embed a FTP script or a registry script within the DOS batch file

Code

:extractFromFile - extract lines from a file between begin and end mark

::†††††††††††††† - %~1: begin mark, use '...$' mark to allow variable substitution

::†††††††††††††† - %~2: optional end mark, default is end of file

::†††††††††††††† - %~3: optional source file, default is THIS file

SETLOCAL

set bmk=%~1

set emk=%~2

set src=%~3

set /a b=-1

set /a e=-1

if "%src%"=="" set src=%~f0&††††††† ::- if no source file then assume THIS file

for /f "tokens=1,* delims=:" %%a in ('"findstr /n /b /c:"%bmk%" "%~f0""') do (

††† set b=%%a

††† set bmk=%%b

)

if/i %b%==-1††† echo.ERROR: begin mark '%bmk%' not found in '%src%'&GOTO:EOF

if "%emk%"=="" (set /a e=2000000000) ELSE (

††† for /f "delims=:" %%a in ('"findstr /n /b /c:"%emk%" "%~f0""') do (

††††††† if /i %b% LSS %%a if /i !e!==-1 set e=%%a&rem -- find only the first one after b

††† )

)

if /i %e%==-1†††† echo.ERROR: end mark '%emk%' missing in '%src%'&GOTO:EOF

if /i %b% GEQ %e% echo.ERROR: end mark '%emk%' detected before begin mark '%bmk%' in '%src%'&GOTO:EOF

for /f "delims=: tokens=1,*" %%a in ('"findstr /v /n /b /c:"#$*ReturnAll*$#" "%src%""') do (

††† if /i %b% LSS %%a if /i %%a LSS %e% (

††††††† if "%bmk:~-1%"=="$" (

††††††††††† rem --substitution variables within %%b

††††††††††† call echo.%%b

††††††† ) ELSE (

††††††††††† rem --no variable substitution

††††††††††† echo.%%b

††††††† )

††† )

)

GOTO:EOF

 

 

Test Code

@ECHO OFF

REM.-- Prepare the Command Processor

SETLOCAL ENABLEEXTENSIONS

SETLOCAL ENABLEDELAYEDEXPANSION

 

echo.Extracting hello world block into "HelloWorld.bat" file

call:extractFromFile "###Hello" "###">"HelloWorld.bat"

 

set var=This variable will been substituted :)

echo.

echo.Extracting a block to screen with variable substitution

call:extractFromFile "###SubstBlock" "###"

 

echo.

echo.Extracting a block to screen as-is

call:extractFromFile "###AsIsBlock"

 

:skip

REM.-- End of application

FOR /l %%a in (5,-1,1) do (TITLE %title% -- closing in %%as&ping -n 2 -w 1 127.0.0.1>NUL)

TITLE Press any key to close the application&ECHO.&GOTO:EOF

 

 

::------------------------------------------------------------------

::-- functions start below here

::------------------------------------------------------------------

 

 

:extractFromFile - extract lines from a file between begin and end mark

::††††††††† †††††- %~1: begin mark, use '...$' mark to allow variable substitution

::†††††††††††††† - %~2: optional end mark, default is end of file

::†††††††††††††† - %~3: optional source file, default is THIS file

SETLOCAL

set bmk=%~1

set emk=%~2

set src=%~3

set /a b=-1

set /a e=-1

if "%src%"=="" set src=%~f0&††††††† ::- if no source file then assume THIS file

for /f "tokens=1,* delims=:" %%a in ('"findstr /n /b /c:"%bmk%" "%~f0""') do (

††† set b=%%a

††† set bmk=%%b

)

if/i %b%==-1††† echo.ERROR: begin mark '%bmk%' not found in '%src%'&GOTO:EOF

if "%emk%"=="" (set /a e=2000000000) ELSE (

††† for /f "delims=:" %%a in ('"findstr /n /b /c:"%emk%" "%~f0""') do (

††††††† if /i %b% LSS %%a if /i !e!==-1 set e=%%a&rem -- find only the first one after b

††† )

)

if /i %e%==-1†††† echo.ERROR: end mark '%emk%' missing in '%src%'&GOTO:EOF

if /i %b% GEQ %e% echo.ERROR: end mark '%emk%' detected before begin mark '%bmk%' in '%src%'&GOTO:EOF

for /f "delims=: tokens=1,*" %%a in ('"findstr /v /n /b /c:"#$*ReturnAll*$#" "%src%""') do (

††† if /i %b% LSS %%a if /i %%a LSS %e% (

††††††† if "%bmk:~-1%"=="$" (

††††††††††† rem --sustitution variables within %%b

††††††††††† call echo.%%b

††††††† ) ELSE (

††††††††††† rem --no variable substitution

††††††††††† echo.%%b

††††††† )

††† )

)

GOTO:EOF

 

 

::------------------------------------------------------------------

::-- blocks start below here

::------------------------------------------------------------------

 

###Hello###

@ECHO OFF

ECHO.Hello world

ECHO.

PAUSE

GOTO.EOF

###

 

###SubstBlock###$

Arg 0 = %~0

batch = %~d0

batch = %~nx0

mark= %bmk%

var†† = %var%

###

 

###AsIsBlock###

Arg 0 = %~0

batch = %~d0

batch = %~nx0

mark= %bmk%

var†† = %var%

 

 

Test Code Output

Extracting hello world block into "HelloWorld.bat" file

 

Extracting a block to screen with variable substitution

Arg 0 = :extractFromFile

batch = C:

batch = myExtract.cmd

mark= ###SubstBlock###$

var†† = This variable will been substituted :)

 

Extracting a block to screen as-is

Arg 0 = %~0

batch = %~d0

batch = %~nx0

mark= %bmk%

var†† = %var%

10    Get THIS computers IP address - :getIP

 

The getIP function filters the IP address from the ipconfig command output and returns it to the caller.

Code

:getIP -- return THIS computers IP address

::†††† -- %~1 - out, IP

SETLOCAL

set ip=

for /f "tokens=2,* delims=:. " %%a in ('"ipconfig|find "IP Address""') do set ip=%%b

( ENDLOCAL & REM RETURN VALUES

††† IF "%~1" NEQ "" (SET %~1=%ip%) ELSE (echo.%ip%)

)

goto :eof

 

 

Test Code

rem.show this computers IP address

call:getIP ip

echo This computers IP is: %ip%

 

 

Test Code Output

This computers IP is: 4.239.36.199

11    Wait, Sleep, Hold - :sleep

 

The :sleep function puts the batch execution on hold for a certain amount of second.

Code

:sleep -Ė waits some seconds before returning

::†††† -- %~1 Ė in, number of seconds to wait

FOR /l %%a in (%~1,-1,1) do (ping -n 2 -w 1 127.0.0.1>NUL)

goto :eof

12    Progress Indicator - :initProgress, :doProgress

 

When a function processes tasks in multiple steps itís always nice to give the user some progress indication.The initProgress function will initialize a progress counter by telling it the number of steps to come and initializes the progress display to 0%. Calling doProgress after finishing each step will update the progress display by the internally calculated percentage.I.e. Letís say 20 steps are to be performed then each call to doProgress will update the progress display by 5 percent.

The progress will be shown in the Window title which as two advantages.First, the progress output will not clutter the output window.Second, even a minimized window will still show the progress in the Windows task bar.

What itís good for

        Show progress when copying multiple files. Call initProgress passing the number of files to be copied.Call doProgress after each file.

        Show progress when executing loops,Call initProgress passing the loop count.Insert the doProgress call as last command within the loop.

Code

:initProgress -- initialize an internal progress counter and display the progress in percent

::††††††††††† -- %~1: in- progress counter maximum, equal to 100 percent

::††††††††††† -- %~2: in- title string formatter, default is '[P] completed.'

set /a ProgressCnt=-1

set /a ProgressMax=%~1

set ProgressFormat=%~2

if "%ProgressFormat%"=="" set ProgressFormat=[PPPP]

set ProgressFormat=!ProgressFormat:[PPPP]=[P] completed.!

call :doProgress

GOTO:EOF

 

 

:doProgress -- display the next progress tick

set /a ProgressCnt+=1

SETLOCAL

set /a per=100*ProgressCnt/ProgressMax

set per=!per!%%

title %ProgressFormat:[P]=!per!%

GOTO:EOF

 

 

Test Code

@ECHO OFF

REM.-- Prepare the Command Processor

SETLOCAL ENABLEEXTENSIONS

SETLOCAL ENABLEDELAYEDEXPANSION

 

REM.-- Set the window title

SET title=Window Title

TITLE %title%

 

set maxcnt=11

call:initProgress maxcnt "%title%:[P] progress"&††† rem --format string is optional

 

echo.Simulating an task with !maxcnt! cycles...

for /l %%C in (1,1,!maxcnt!) do (

††† echo.%%C&call:sleep 1

††† call:doProgress

)

Test Code Output

Window Title:0% progress

Window Title:9% progress

Window Title:18% progress

Window Title:27% progress

Window Title:36% progress

Window Title:45% progress

Window Title:54% progress

Window Title:63% progress

Window Title:72% progress

Window Title:81% progress

Window Title:90% progress

Window Title:100% progress