To define your own functions in the macro, use a FUNCTION block or MACRO_FUNCTION block:
Syntax: Use the following syntax to define functions:
FUNCTION block:
%FUNCTION(type) function-name([usage] [datatype] parameter, ...) [RETURNS(return-var)] { executable-statements [report-block] ... [report-block] [message-block] %}
MACRO_ FUNCTION block:
%MACRO_FUNCTION function-name([usage] parameter, ...) [RETURNS(return-var)] { executable-statements report-block ... report-block %}
Where:
You can define multiple FUNCTION or MACRO_FUNCTION blocks with the same name so that they are processed at the same time. Each of the blocks must all have identical parameter lists. When Net.Data calls the function, all FUNCTION blocks with the same name or MACRO_FUNCTION blocks with the same name are executed in the order they are defined in the Net.Data macro.
For FUNCTION blocks, Net.Data replaces all variable references with the variable values, executes all function calls, and replaces the function calls with their resulting values before the executable statements are passed to the language environment. Each language environment processes the statements differently. For more information about specifying executable statements or calling executable programs, see Executable Variables.
For MACRO_FUNCTION blocks, the executable statements are a combination of text and Net.Data macro language constructs. In this case, no language environment is involved because Net.Data acts as the language processor and processes the executable statements.
Define functions outside of any other block and before they are called in the Net.Data macro.
When characters that match Net.Data language constructs syntax are used in the language statements section of a function block as part of syntactically valid embedded program code (such as REXX or Perl), they can be misinterpreted as Net.Data language constructs, causing errors or unpredictable results in a macro.
For example, a Perl function might use the COMMENT block delimiter characters, %{. When the macro is run, the %{ characters are interpreted as the beginning of a COMMENT block. Net.Data then looks for the end of the COMMENT block, which it thinks it finds when it reads the end of the function block. Net.Data then proceeds to look for the end of the function block, and when it can't be found, issues an error.
Use one of the following methods to use COMMENT block delimiter characters, or any other Net.Data special characters as part of your embedded program code, without having them interpreted by Net.Data as special characters:
For example, the following Perl function contains characters representing a COMMENT block delimiter, %{, as part of its Perl language statements:
%FUNCTION(DTW_PERL) func() { ... for $num_words (sort bynumber keys %{ $Rtitles{$num} }) { &make_links($Rtitles{$num}{$num_words}); } ... %}
To ensure that Net.Data interprets the %{ characters as Perl source code rather than as a Net.Data COMMENT block delimiter, rewrite the function in either of the following ways:
%FUNCTION(DTW_PERL) func() { %EXEC{ func.prl %} %}
%define percent_openbrace = "%{" %FUNCTION(DTW_PERL) func() { ... for $num_words (sort by number keys $(percent_openbrace) $Rtitles{$num} } { &make_links($Rtitles{$num}{$num_words}); } ... %}
The MESSAGE block lets you determine how to proceed after a function call, based on the success or failure of the function call, and lets you display information to the caller of the function. When processing a message, Net.Data sets the language environment variable RETURN_CODE for each function call to a FUNCTION block. RETURN_CODE is not set on a function call to a MACRO_FUNCTION block.
A MESSAGE block consists of a series of message statements, each of which specifies a return code value, message text, and an action to take. The syntax of a MESSAGE block is shown in the language constructs chapter of Net.Data Reference.
A MESSAGE block can have a global or a local scope. If the MESSAGE block is defined in a FUNCTION block, its scope is local to that FUNCTION block. If it is specified at the outermost macro layer, the MESSAGE block has global scope and is active for all function calls executed in the Net.Data macro. If you define more than one global MESSAGE block, the last one defined is active.
Net.Data uses these rules to process the value of the RETURN_CODE variable from a function call:
The following example shows part of a Net.Data macro with a global MESSAGE block and a MESSAGE block for a function.
%{ global message block %} %MESSAGE { -100 : "Return code -100 message" : exit 100 : "Return code 100 message" : continue +default : { This is a long message that spans more than one line. You can use HTML tags, including links and forms, in this message. %} : continue %} %{ local message block inside a FUNCTION block %} %FUNCTION(DTW_REXX) my_function() { %EXEC { my_command.mbr %} %MESSAGE { -100 : "Return code -100 message" : exit 100 : "Return code 100 message" : continue -default : { This is a long message that spans more than one line. You can use HTML tags, including links and forms, in this message. %} : exit %}
If my_function() returns with a RETURN_CODE value of 50, Net.Data processes the error in this order:
When Net.Data finds a match, it sends the message text to the Web browser and checks the requested action.
When you specify continue, Net.Data continues to process the Net.Data macro after printing the message text. For example, if a macro calls my_functions() five times and error 100 is found during processing with the MESSAGE block in the example, output from a program can look like this:
. . . 11 May 1997 $245.45 13 May 1997 $623.23 19 May 1997 $ 83.02 return code 100 message 22 May 1997 $ 42.67 Total: $994.37