Next: Expressions, Previous: Special handlers, Up: MFL [Contents][Index]
A function is a named mailfromd
subroutine, which
takes zero or more parameters and optionally returns a certain
value. Depending on the return value, functions can be
subdivided into string functions and number functions.
A function may have mandatory and optional parameters.
When invoked, the function must be supplied exactly as many
actual arguments as the number of its mandatory parameters.
Functions are invoked using the following syntax:
name (args)
where name is the function name and args is a comma-separated list of expressions. For example, the following are valid function calls:
foo(10) interval("1 hour") greylist("/var/my.db", 180)
The number of parameters a function takes and their data types compose the function signature. When actual arguments are passed to the function, they are converted to types of the corresponding formal parameters.
There are two major groups of functions: built-in functions,
that are implemented in the mailfromd
binary, and
user-defined functions, that are written in MFL. The
invocation syntax is the same for both groups.
Mailfromd
is shipped with a rich set of library
functions. These are described in Library. In addition to
these you can define your own functions.
Function definitions can appear anywhere between the handler declarations in a filter program, the only requirement being that the function definition occur before the place where the function is invoked.
The syntax of a function definition is:
[qualifier] func name (param-decl) [returns data-type] do function-body done
where name is the name of the function to define, param-decl is a comma-separated list of parameter declarations. The syntax of the latter is the same as that of variable declarations (see Variable declarations), i.e.:
type name
declares the parameter name having the type type. The
type is string
or number
.
Optional qualifier declares the scope of visibility for that function (see scope of visibility). It is similar to that of variables, except that functions cannot be local (i.e. you cannot declare function within another function).
The public
qualifier declares a function that may be referred
to from any module, whereas the static
qualifier declares a
function that may be called only from the current module
(see Modules). The default scope is ‘public’,
unless specified otherwise in the module declaration (see module structure).
For example, the following declares a function ‘sum’, that takes two numeric arguments and returns a numeric value:
func sum(number x, number y) returns number
Similarly, the following is a declaration of a static function:
static func sum(number x, number y) returns number
Parameters are referenced in the function-body by their name,
the same way as other variables. Similarly, the value of a parameter can be
altered using set
statement.
A function can be declared to take a certain number of optional
arguments. In a function declaration, optional abstract arguments
must be placed after the mandatory ones, and must be separated from
them with a semicolon. The following example is a definition of
function foo
, which takes two mandatory and two optional
arguments:
func foo(string msg, string email; number x, string pfx)
Mandatory parameters are: msg
and email
. Optional
parameters are: x
and pfx
. The actual number of
arguments supplied to the function is returned by a special construct
$#
. In addition, the special construct @arg
evaluates to the ordinal number of variable arg in the list of
formal parameters (the first argument has number ‘0’). These two
constructs can be used to verify whether an argument is supplied to
the function.
When an actual argument for parameter n
is supplied, the number
of actual arguments ($#
) is greater than the ordinal number
of that parameter in the declaration list (@n
). Thus,
the following construct can be used to check if an optional argument
arg is actually supplied:
func foo(string msg, string email; number x, string arg) do if $# > @arg … fi
The default mailfromd
installation provides a special
macro for this purpose: see defined. Using it, the example above
could be rewritten as:
func foo(string msg, string email; number x, string arg) do if defined(arg) … fi
Within a function body, optional arguments are referenced exactly the same way as the mandatory ones. Attempt to dereference an optional argument for which no actual parameter was supplied, results in an undefined value, so be sure to check whether a parameter is passed before dereferencing it.
A function can also take variable number of arguments (such
functions are called variadic). This is
indicated by ellipsis in place of the last abstract parameter name. The
statement below defines a function foo
taking one mandatory, one
optional and any number of additional arguments:
func foo (string a ; string b, string ...)
The data type before the ellipsis indicates the type to promote all
actual arguments to. If it is omitted, string
is assumed, so
the above declaration can also be written as:
func foo (string a ; string b, ...)
To refer to the actual arguments in the function body, the following construct is used:
$(expr)
where expr is any valid MFL expression, evaluating to
a number n. This construct refers to the value of nth
actual parameter from the variable argument list. Parameters are
numbered from ‘1’, so the first variable parameter is $(1)
,
and the last one is $($# - Nm - No)
, where Nm
and No are numbers of mandatory and optional parameters to the
function.
The construct ‘$(n)’ where 1 <= n <= 9 can also be written as ‘$n’.
For example, the function below prints all its arguments:
func pargs (string text, ...) do echo "text=%text" loop for number i 1, while i < $# - @text, set i i + 1 do echo "arg %i=" . $(i) done done
Note how the ordinal number operator is used to compute the upper limit.
As another example, the function below computes the sum of its arguments.
func sum(number ...) do number s 0 loop for number i 1, while i <= $#, set i i + 1 do set s s + $(i) done return s done
Sometimes it is necessary to pass all variable arguments passed to a
variadic function on to another variadic function. To do so, use the
$@
operator. For example:
func y(string x, number ...) do echo "x is " . sum($@) done
Suppose y
is called as y("test", 1, 3, 5)
. Then, it
will call sum
as: sum(1, 3, 5)
.
The $@
can be used with a numeric argument, which indicates
number of arguments to remove from the resulted argument list. This
is similar to shift
statement in other languages. Thus, if
y
in the above example were written as:
func y(string x, ...) do x($@(2)) done
then y("test", "a", "b", "c")
, it will call x
as
follows: x("c")
.
Notice the following important points. First, $@
can be
used only as the last argument in the argument list. Secondly, it
cannot be used to pass mandatory and optional arguments to a function.
In other words, arguments passed via $@
must correspond to
ellipsis in the function declaration. Finally, passing shift count
greater than the actual number of variable arguments results in a
runtime error.
The function-body is any list of valid mailfromd
statements. In addition to the statements discussed below
(see Statements) it can also contain the return
statement,
which is used to return a value from the function. The syntax of the
return statement is
return value
As an example of this, consider the following code snippet that defines the function ‘sum’ to return a sum of its two arguments:
func sum(number x, number y) returns number do return x + y done
The returns
part in the function declaration is optional. A
declaration lacking it defines a procedure, or void
function, i.e. a function that is not supposed to return any value.
Such functions cannot be used in expressions, instead they are
used as statements (see Statements). The following example
shows a function that emits a customized temporary failure notice:
func stdtf() do tempfail 451 4.3.5 "Try again later" done
A function may have several names. An alternative name (or
alias) can be assigned to a function by using alias
keyword, placed after param-decl part, for example:
func foo() alias bar returns string do … done
After this declaration, both foo()
and bar()
will refer
to the same function.
The number of function aliases is unlimited. The following fragment declares a function having three names:
func foo() alias bar alias baz returns string do … done
Although this feature is rarely needed, there are sometimes cases when it may be necessary.
A variable declared within a function becomes a local variable to
this function. Its lexical scope ends with the terminating
done
statement.
Parameters, local variables and global variables are using separate namespaces, so a parameter name can coincide with the name of a global, in which case a parameter is said to shadow the global. All references to its name will refer to the parameter, until the end of its scope is reached, where the global one becomes visible again. Consider the following example:
number x func foo(string x) do echo "foo: %x" done prog envfrom do set x "Global" foo("Local") echo x done
Running mailfromd --test
with this configuration will
display:
foo: Local Global |
• Some Useful Functions |
Next: Expressions, Previous: Special handlers, Up: MFL [Contents][Index]