Functions and Ctrl-C

  • This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

nchernoff

Administrator
Staff member
May 16, 2008
42
2
#1
Migrated From JP Software Wiki

Description

A function that expands across multiple lines can be defined using the function command by joining all lines together with the & separator. Single-line functions created this way can't handle cancellation by means of Ctrl-C or Ctrl-Break. This page compares the effects of Ctrl-C cancellation of single-line functions vs. multi-line functions as describe in article Complex Functions.

To start with, we need to create a single-line function for our batch script. It is easier to write the definition in its own file and then source that file into the batch script.
Code:
REM Source the definition of a function
function /R "%@path[%_batchname]%@name[%_batchname].fun"
In this example, "%@path[%_batchname]%@name[%_batchname].fun" is used instead of specifying a fixed file name of the file that contains the function definition. This allows the script file name to change without having to change the script code. For instance, a script named MyProgram.btm will source a file named MyProgram.fun located in the start directory of the script.

The function is defined as
Code:
: a multi-line function defined on a single line
Single=%@execstr[^
pause Single:Press Ctrl-C then do (N)ot cancel batch job... 1>2 &^
echo Single returns %1^
]
Single is a simple function, but it could be much more complex and still be written as a one-liner. All lines are joined using the & separator followed by the ^ escape character as the last character of the line. The command processor knows to join lines together when it finds the escape character at the end of a line.

Single pauses to print instructions to the standard error file, then prints its return value which is captured by the %@execstr function and returned to the caller.

Then we need to call Single from our script file
Code:
REM Call the function
echo %@Single[1]
echo Script ended
and run the script file
Code:
C:\>CancelFunction.btm
Single:Press Ctrl-C then do (N)ot cancel batch job...^C

Cancel batch job C:\CancelFunction.btm ? (Y/N/A) : N
Script ended

C:\>
In this example, Single did not return its value. This is because pressing Ctrl-C stopped execution of the current line of CancelFunction.btm, that is echo %@Multi[1] to prompt the user for action. When the user pressed N, execution resumed from the next script line, that is echo Script ended.

Therefore, all pending statements of Single were skipped, since it is defined on a single line. To be able to handle Ctrl-C from within a function, we need to write the function on multiple lines. We start with the body of the function as a subroutine in the script file:
Code:
:Multi [a]
pause Multi: Press Ctrl-C then do (N)ot cancel batch job... 1>2
echo Multi returns %a
return
then we wrap the subroutine into a function
Code:
REM Define a function on multiple lines
function Multi=`%@execstr[gosub Multi %$]`
and run the script file

Code:
C:\>CancelFunction2.btm
Multi: Press Ctrl-C then do (N)ot cancel batch job...^C

Cancel batch job C:\CancelFunction2.btm ? (Y/N/A) : N
Multi returns 1
Script ended
In this example, Multi returned its value in spite of the pause statement being cancelled by Ctrl-C.

For more information about running functions as subroutines read article Complex Functions.

Single-line functions can still be used effectively with Ctrl-C when it is enough for the script file to detect that the function was interrupted; just use code similar to the following

Code:
REM Show how to deal with Ctrl-C in a single-line function
set return=Single was cancelled
set return=%@Single[1]
echo %return
If Ctrl-C interrupts line set return=%@Single[1], the previous value "Single was cancelled" is not overwritten and can be used to determine that Ctrl-C was hit.

Contributed by: Stefano Piccardi 09:44, 5 January 2007 (CST)

CancelFunction.btm

Code:
@echo off
setlocal

REM Source the definition of a function
function /R "%@path[%_batchname]%@name[%_batchname].fun"

REM Call the function
echo %@Single[1]

REM Define a function on multiple lines
function Multi=`%@execstr[gosub Multi %$]`

REM Call the function
echo %@Multi[1]

REM Show how to deal with Ctrl-C in a single-line function
set return=Single was cancelled
set return=%@Single[1]
echo %return


goto end

:Multi [a]
pause Multi: Press Ctrl-C then do (N)ot cancel batch job... 1>2
echo Multi returns %a
return


:end
echo Script ended
unfunction Single
unfunction Multi
CancelFunction.fun

Code:
: a multi-line function defined on a single line
Single=%@execstr[^
pause Single:Press Ctrl-C then do (N)ot cancel batch job... 1>2 &^
echo Single returns %1^
]