Question

This question is basically about how to mimic the function ability in batch files within the file itself for MS-DOS/Windows Command Prompt (minus extensions). In Command Prompt, with extensions, you could simply first call setlocal enableextensions at the beginning of the batch file and then call the function with call :function params, which would call it just like you would in most other languages (e.g. function(params)). This isn't as easy in DOS and the like (FreeDOS, etc.) because of the lack of command prompt extensions introduced in Windows XP.

Was it helpful?

Solution

If you're doing dinosaur-era programming, you should always consider dinosaur-era solutions. :-)

rem call the "hello world" function
set return=line101
goto helloworld
:line101

rem now call it again
set return=line102
goto helloworld
:line102

rem ok, I'm done
goto :eof

:helloworld
echo Hello, world!
goto %return%

:eof
rem the end

OTHER TIPS

I'm reasonably sure that you could CALL a subsidiary batchfile in those earlier versions, so you'd write a file like STRING2.BAT

@echo off
set %1=%2%3

and invoke it by

call string2 longstring,abcd,%wxyz%
echo concatenated string=%longstring%

(granted, this isn't an ideal way to concatenate two strings, it just serves as a demo)

Certainly, having a batch call itself and using a fixed parameter value like :: to modify the behaviour of thisbatch.bat was a common technique in the days of yore, but whereas it kept all of your code in one batchfile, you'd be forever copying code fragments between batches and creating a maintenance nightmare. The alternative was to create a separate cleverfunction.bat file, but communicating the need to create a separate file, and where it needed to be located, was a new nightmare.

In these days of you-must-spoonfeed-me-an-infallile-solution, such techniques are no longer viable.

The solution would seem hard to find, but it is actually simpler than it would seem. Basically, this implementation would cause a batch file to recursively call itself, which will make more sense later. First, you will need a way to differentiate a function call from a normal command line argument. In my example, I will (for simplicity's sake) use the colon : to denote that the argument is a function. This will result in the following code (only part of the command):

set fn=%1
if "%fn:0,1%"==":" ...

This code would first set a variable to take the first argument and accept that as the function name. Next, we need to go to that function in the recursive call, which is as simple as this.

goto %fn%

Now, we need a way to account for incorrect function calls and kill the execution of the batch file if it is wrong (like any language with proper function calls would). This modification would allow this error to be caught and will promptly kill the batch file. In case you're wondering, I separated the statement into a set a variable if the function doesn't exist. I added that echo statement to make it easier to debug.

goto %fn% || set err=t
if defined %err% (
    echo Undefined function: %fn%!
    goto :eof
)

So, after that, you can make the functions like you would otherwise normally, because the goto :eof call would act the same as it would with or without extensions. Here's the entire batch file implementation of this (I didn't mention the needed shift, which is here):

@echo off
:: You will not need to enable extensions
:: here.
setlocal
set fn=%1
shift
if "%fn:0,1%"==":" (
    goto %fn% || set err=t
    if defined %err% (
        echo Undefined function: %fn%!
        goto :eof
    )
)

:: Normal commands go here. You can also 
:: include your functions normally as well.

One little difference between the function calling mechanism with extensions and this implementation that must be noted is this: you have to call your function like this call %0 :function args instead of call :function args, like how you would with extensions enabled. If you don't, you will most assuredly find bugs that are insanely hard to find (the error won't start you in the right direction).

If you want a little sugar for this, you could always set call=call %%0 and use %call% :function args

EDIT: I forgot a small nuance in how to actually call the function. I fixed it in the main body.

I use write like code below:

@echo off

SETLOCAL

set ldt=nada

echo. %ldt%

call:setCurrentTime

echo. %ldt%

call:setCurrentTime

echo. %ldt%

ENDLOCAL

echo.&pause&goto:eof

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

::-- Function section starts below here

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

:setCurrentTime

rem **** Obtem data e hora corrente:INI **********************************

for /F "usebackq tokens=1,2 delims==" %%i in (wmic os get LocalDateTime /VALUE 2^>NUL) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j

set ldt=%ldt:~6,2%/%ldt:~4,2%/%ldt:~0,4% %ldt:~8,2%:%ldt:~10,2%:%ldt:~12,6%

rem **** Obtem data e hora corrente:FIM **********************************

goto:eof

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top