Purpose
The FUNCTION block defines a subroutine that can be invoked from the Net.Data macro. The executable statements in a FUNCTION block can be language statements directly interpreted by a language environment, or they can indicate a call to an external program.
If you use the EXEC statement or block within a function definition, it must be the only executable statement in the FUNCTION block. Before passing the executable statement to the language environment, the file name of the program in the EXEC statement is appended to a path name determined by the EXEC_PATH configuration statement in the initialization file. The resulting string is passed to the language environment to be executed.
The method that the language environment uses to process the EXEC statement depends on the particular language environment. Only the REXX, System, and Perl language environments support the EXEC statement.
Syntax
>>-%function--(--lang_env--)--function_name--| parameter definition |-->
+-;--------------------------------------------+
>--+-| returns spec |--{--| function body |---%}--+------------><
parameter definition
|--(--+----------------------+--)------------------------------|
| +-,--------------+ |
| V | |
+---+-------+-name--+--+
+-IN----+
+-OUT---+
+-INOUT-+
returns spec
|--+----------------------+------------------------------------|
+-RETURNS--(--name--)--+
function body
|--+------------------------+----------------------------------->
| +--------------------+ |
| V | |
+--language statement--+-+
+-exec block-------------+
>--+----------------------------------+------------------------|
+-report block--+----------------+-+
| +-message block--+ |
+-message block--+---------------+-+
+-report block--+
Parameters
Context
Must be outside of blocks and statements in the declaration part of the Net.Data macro.
Restrictions
Can contain these elements:
Examples
The following examples are general and do not cover all language environments. See Net.Data Lanuage Environment Guide for more information about using FUNCTION blocks with a specific language environment.
Example 1: A REXX substring function.
%DEFINE lstring = "longstring"
%FUNCTION(DTW_REXX) substring(IN x, y, z) RETURNS(s) {
s = substr("$(x)", $(y), $(z));
%}
%DEFINE a = {@substring(lstring, "1", "4")%} %{ assigns "long" to a %}
When a is evaluated, the @substring function call is found and the substring FUNCTION block is executed. Variables are substituted in the executable statements in the FUNCTION block, then, the text string
s = substr("longstring", 1, 4)
is passed to the REXX interpreter to execute. Because the RETURNS clause was specified, the value of the @substring function call in the evaluation of a is replaced with "long", the value of s.
Example 2: Invoking an external REXX program.
%FUNCTION(DTW_REXX) my_rexx_pgm(INOUT a, b, IN c, OUT d) {
%EXEC{ mypgm.cmd this is a test %}
%}
%HTML(INPUT) {
<P> Original variable values: $(w) $(x) $(z)
<P> @my_rexx_pgm(w, x, y, z)
<P> Modified variable values: $(w) $(x) $(z)
%}
Variables w and x correspond to the INOUT parameters a and b in the function. Their values and the value of y, which corresponds to the IN parameter c, should be already defined from HTML form input or from a DEFINE statement. Variables a and b are assigned new values when parameters a and b return values. The variable z is defined when the OUT parameter d returns a value.
/* Sample REXX Program for Example 2 */ /* Test arguments */ num_args = arg(); say 'There are' num_args 'arguments'; do i = 1 to num_args; say 'arg' i 'is "'arg(i)'"' end; /* Set variables passed from Net.Data */ d = a || b || c; /* concatenate a, b, and c forming d */ a = ''; /* reset a to null string */ b = ''; /* reset b to null string */ return;
There are 1 arguments arg 1 is "this is a test"
The EXEC statement tells the REXX language environment to tell the REXX interpreter to execute the external REXX program mypgm.cmd. Because the REXX language environment can directly share Net.Data variables with the REXX program, it assigns the REXX variables a, b, and c the values of the Net.Data variables w, x and y before executing mypgm.cmd. Mypgm.cmd can directly use the variables a, b, and c in REXX statements. When the program ends, the REXX variables a, b, and d are retrieved from the REXX program, and their values are assigned to the Net.Data variables w, x, and z. Because the RETURNS clause is not used in the definition of the my_rexx_pgm %FUNCTION block, the value of the @my_rexx_pgm function call is the null string "" (if the return code is 0) or the value of the REXX program return code (if the return code is nonzero).
Example 3: An SQL query and report.
%FUNCTION(DTW_SQL) query_1(IN x, IN y) {
SELECT customer.num, order.num, part.num, status
FROM customer, order, shippingpart
WHERE customer.num = '$(x)'
AND customer.ordernumber = order.num
AND order.num = '$(y)'
AND order.partnumber = part.num
%REPORT{
<P>Here is the status of your order:
<P>$(NLIST)
<UL>
%ROW{
<LI>$(V1) $(V2) $(V3) $(V4)
%}
</UL>
%}
%}
%DEFINE customer_name="IBM"
%DEFINE customer_order="12345"
%HTML(REPORT) {
@query_1(customer_name, customer_order)
%}
The @query_1 function call substitutes "IBM" for $(x) and "12345" for
$(y) in the SELECT statement. Because the definition of the SQL function
query_1 does not identify an output table variable, the default table is used
(see the TABLE variables block for details). The NLIST and Vi variables
referenced in the REPORT block are defined by the default table definition.
The report produced by the REPORT block is placed in the output HTML where the
query_1 function is invoked.
Example 4: A system call to execute a Perl script.
%FUNCTION(DTW_SYSTEM) today() RETURNS(result) {
%exec{ perl "today.prl" %}
%}
%HTML(INPUT) {
@today()
%}
$date = `date`;
chop $date;
open(DTW, "> $ENV{DTWPIPE}") || die "Could not open: $!";
print DTW "result = \"$date\"\n";
The System language environment interprets the executable statements in a FUNCTION block by passing them to the operating system through the C language system() function call. This method does not allow Net.Data variables to be directly passed or retrieved to the executable statements, as the REXX language environment does, so the System language environment passes and retrieves variables as described here:
When the @today function call is encountered, Net.Data performs variable substitution on the executable statements. In this example, there are no Net.Data variables in the executable statements, so no variable substitution is performed. The executable statements and parameters are passed to the System language environment, which creates a named pipe and sets the environment variable DTWPIPE to the name of the pipe.
Then the external program is called with the C system() function call. The external program opens the pipe as write-only and writes to the pipe as if it were a standard stream file. HTML output is written to the STDOUT stream instead when you use Net.Data in CGI mode. In this example, the output of the system date program is assigned to the variable result, which is the variable identified in the RETURNS clause of the FUNCTION block. This value of the result variable replaces the @today() function call in the HTML block.
Example 5: Perl language environment.
%FUNCTION(DTW_PERL) today() RETURNS(result) {
$date = `date`;
chop $date;
open(DTW, "> $ENV{DTWPIPE}") || die "Could not open: $!";
print DTW "result = \"$date\"\n";
%}
%HTML(INPUT) {
@today()
%}
Compare this example with Example 4 to see how the EXEC
statement is used. In example 4, the System language environment does not
understand how to interpret Perl programs, but it does know how to call
external programs. The EXEC statement tells it to call a program called perl
as an external program. The actual Perl language statements are
interpreted by the external Perl program. Example 5 has no EXEC statement
because the Perl language environment is able to directly interpret
Perl language statements.