![]() |
6. Functions
Introduction
- <MvFUNCTION NAME="myfunc"
- PARAMETERS="var1,var2,..."
- STANDARDOUTPUTLEVEL="html,text"
- ERROROUTPUTLEVEL="syntax,expression,runtime">
- ...code...
- <MvFUNCRETURN VALUE="{expression}">
- ...code...
- </MvFUNCTION>
- ...
- myfunc(val1,val2,...)
Defines the function myfunc, whose name is specified with the required attribute NAME. Parameters var1, var2, ..., can optionally be defined with the PARAMETERS attribute. These are assigned the values va11, val2, ..., in the function call. The function can optionally terminate with a return value specified with <MvFUNCRETURN>. Functions can use locally defined variables whose scope is the function body. STANDARDOUTPUTLEVEL and ERROROUTPUTLEVEL are optional and are interpreted in the same way as in the <MIVA> tag. <MvFUNCRETURN> is an empty tag.
Functions are called in expressions. Functions can be forward referenced: Miva Script code can make references to functions that are defined after the reference in question.
Sometimes you will need to carry out the same series of steps at several different locations in your program. If you were to repeat the same lines of code every place they were needed, your program would get long, hard to read, and hard to modify, and the chances of making errors would increase.
Functions enable you to write re-usable code that can be called on to perform operations throughout the program, by calling the function in any valid expression. Even if a function is only called once in your program, moving the code out of the main body of the program and replacing it with a function call still helps to make the program more 'modular' and easy to follow.
Here is an example: a function that returns the greater of two numbers:
- <MvFUNCTION name="greater2" parameters="num1,num2">
- <MvIF EXPR="{num1 GE num2}">
- <MvFUNCRETURN value="{num1}">
- <MvELSE>
- <MvFUNCRETURN value="{num2}">
- </MvIF>
- </MvFUNCTION>
- .
- .
- .
- <MvASSIGN name="older" value="{greater2(age1,age2)}">
This example defines a function called greater2 and shows how it is used in an <MvASSIGN> tag. The point of the <MvASSIGN> is to get the greater of the values in the two variables age1 and age2 and assign that value to the variable older. The value of the <MvASSIGN> is a reference or 'call' to the function greater2. The variables age1 and age2 appear in brackets after the function name; they are called the 'arguments' of the function and are said to be 'passed to' the function.
Now consider the function definition. Functions start with <MvFUNCTION> and end with </MvFUNCTION>. The NAME attribute of <MvFUNCTION> is required, and specifies the name by which the function is called.
Parameters
To understand the PARAMETERS attribute, look again at the call to greater2 in the <MvASSIGN> tag; this call asks greater2 to return the greater of age1 and age2, however, as you can see these two variable names don't appear anywhere inside the definition of greater2. Instead, the values of age1 and age2 are assigned to the 'parameters' of greater2: these are called num1 and num2 and are defined by the PARAMETERS attribute. Parameters are variables whose scope is the body of the function, that is, they are not meaningful anywhere outside the function, unless you pass the variable by reference. (See the following section, "Passing Variables by Reference". When the function is called, the parameters are automatically assigned the values of the arguments that are specified when the function was called. These assignments are done in the order that the arguments appear: in this example, the value of age1 is assigned to num1, and the value of age2 is assigned to num2.
There are two reasons why the function uses parameters instead of using age1 and age2 directly:
You might want to call greater2 with different variables as its arguments; if the function always used just age1 and age2, you would always have to call it with those variables.
Since the function isn't supposed to change the values of age1 and age2 it's safer not to use these variable names in the function. If you unintentionally changed one of these values in the function, it might cause a problem that would be hard to track down later.
Passing Variables by Reference
When defining a function, a parameter may have an optional "VAR" after the variable name, signifying that the parameter would be passed by reference. Any changes to the variable in the function will be reflected in the variable used in calling the function, and any array elements or structure members will be preserved.
- <MvFUNCTION NAME="functionname" PARAMETERS="varname1,varname2 VAR, varname3">
- ...
- </MvFUNCTION>
Function Definition
Let's return to the definition of the function: it consists of a single <MvIF>-<MvELSE>-</MvIF> block. If num1 is greater than or equal to num2, then the first <MvFUNCRETURN> tag is executed. The purpose of this tag is to 'return' or send a value back to the tag that called the function in the first place. This value is said to be the 'value of the function'. In this case, the function was called inside an expression in the VALUE attribute of an <MvASSIGN>; when the function returns a value, it is the same as if that value were substituted for the call to the function. Here is the <MvASSIGN> again:
- <MvASSIGN name="older" value="{greater2(age1,age2)}">
Suppose age1 equals 17 and age2 equals 12. When greater2 returns the value 17, it is the same as if the <MvASSIGN> were:
- <MvASSIGN name="older" value="{17}">
If num2 is greater than num1 when the function is executed, then the second <MvFUNCRETURN> returns a value. Once an <MvFUNCRETURN> is executed, the function immediately stops executing (this includes any loops such as <MvWHILE> and <MvIMPORT>) and the program jumps back to the location of the function call.
Local Variables and Parameters
In addition to parameters defined with the PARAMETERS attribute, you can use 'local' variables that are meaningful only inside the function. These variables must start with the l. or local. prefix.
- <MvFUNCTION name="func1">
- <MvASSIGN name="l.var1" value="1">
- <MvASSIGN name="local.var2" value="10">
- ...
- </MvFUNCTION>
All parameters will automatically become local variables, but you should not use the l. or local. prefix directly in the parameter list:
- <MvCOMMENT> Avoid this! </MvCOMMENT>
- <MvFUNCTION NAME="funk" PARAMETERS="l.foo,l.bar">
- ...
- </MvFUNCTION>
- <MvCOMMENT> Correct usage. </MvCOMMENT>
- <MvFUNCTION NAME="funk" PARAMETERS="foo,bar">
- ...
- ...<MvEVAL EXPR="{l.foo $ l.bar}">...
- ...
- </MvFUNCTION>
Calling Functions
- A function can be called in any expression. The simplest way to call a function is in an <MvEVAL> tag:
- <MvEVAL EXPR="{func1(var_a)}">
Function calls can be combined with other components of an expression:
- <MvEVAL EXPR="{'The answer is: ' $ func1(42)}">
- <MvEVAL EXPR="{square(4) + square(5)}">
The argument(s) of a function can be literal, variable, or any valid expression; an expression inside a list of arguments will be evaluated before the function call takes place, and the function will be called with the resulting value.
- <MvEVAL EXPR="{func1(6)}">
- <MvEVAL EXPR="{func1('xyzzy')}">
- <MvEVAL EXPR="{func1(a + b)}">
- <MvEVAL EXPR="{func1('Dear ' $ customer $ ',')}">
The function is called before EXPR is evaluated, and the function result (the value returned by <MvFUNCRETURN>) is substituted in the expression.
Note: If a function returns a value, but you don't want to display this value in your output, you can use <MvASSIGN> instead.
- <MvASSIGN NAME="do_this" VALUE="{func1(var_a)}">
This calls the function and assigns the return value (if there is one) to the variable do_this. You can just 'throw away' do_this (that is, don't use it for anything). You may find it useful to use the same variable name--do_this, do, junk, or a name of your choice--for this purpose to make it easier to keep track of what this assignment tag is really doing.
Calling Functions from a Form
You can also indirectly call a function via a form submission. That is, you cannot call a function directly in this way, but you can put code in your program that takes the results of a form submission and makes a function call. Consider this example:
- <BODY>
- <H1>This is a test of calling a function</H1>
- <MvIF EXPR = "{ fname }">
- <MvEVAL EXPR = "{ &[ fname ];() }">
- <MvELSE>
- <MvEVAL EXPR = "{ main() }">
- </MvIF>
- <MvFUNCTION NAME="funk">
- ...code...
- </MvFUNCTION>
- ...other function definition code...
- <MvFUNCTION NAME="main">
- ...code...
- <FORM ACTION="&[ documenturl ];fname=funk" METHOD="post">
- ...code...
- </FORM>
- ...code...
- </MvFUNCTION>
- </BODY>
This example has three main parts: a function called main, a section of function definitions (funk is the only one that's shown), and an <MvIF> tag that decides which function will get called when the document is loaded.
As the name suggests, main is the part of the program that controls the other functions. Inside main there is a FORM element; the ACTION attribute of the FORM is a URL that tells the browser what to do when the user submits the form. In this case the ACTION consists of &[documenturl ];fname=funk. documenturl is a special built-in variable that always consists of the URL of the current document, with a plus sign (+) or question mark (?) appended, depending on which flavor of Miva Engine you are using. Suppose the current document's URL is:
- http://www.your_server.com/cgi-bin/miva?testy.mv
The expression '&[ documenturl ];fname=funk' will be equal to:
- http://www.your_server.com/cgi-bin/miva?testy.mv+fname=funk
As Chapter 10, "Passing Data to a Program" shows, you can pass variables to a Miva Script program using name/value pairs in the URL. In this example, the program will be passed the variable fname with the value "funk".
Now look at the <MvIF> tag at the top of the document. This tag tests whether fname has a non-null value. If it does, then the expression {&[ fname ];()} is evaluated. If fname has the value "funk", the expression to be evaluated is {funk()}. As you've seen, this will call the function funk. This mechanism is how you can use a FORM action to call a function. Look also at the other branch of the <MvIF>; if fname is null, then {main()} will be evaluated, that is, the function main will be called. This is so that the first time you load the document, with no arguments at the end of the URL, the "main" part of your program will get executed.
More on Functions
Here are a few more items of which you should be aware:
- Function code is not executed until it is called. When the Miva Script file is processed, the function definitions are read, but not actually executed until there is a function call.
- If you pass a text string as an argument to a variable, it should be in single quotes:
- While defining parameters is often helpful, it is not mandatory. For example, you may want to update a 'global' variable directly.
- An <MvFUNCRETURN> tag is also not always needed; you would use it if you needed to return a value to the place where the function was called.
- In addition to parameters defined with the PARAMETERS attribute, you can use 'local' variables that are meaningful only inside the function. These variables must start with the l. or local. prefix. For example:
- Miva Script supplies a large number of built-in functions to help you carry out time, string, numeric, and file system operations. Built-in functions are used in exactly the same way as user-defined functions, but generally run faster than ordinary Miva Script code.
- A recursive function call occurs when a function calls itself. There is a limit on the number of recursive function calls at run-time. This limit is fixed at 23 for Miva Merchant Mia; the default limit for Miva Merchant Empresa is 23, but this can be changed by the server administrator via the maxfunctiondepth setting in the global configuration file.
Built-in Functions
Miva Script makes a set of built-in functions available to perform standard time oriented calculation, string formatting, string analysis, integer matching, number rounding, exponential multiplication, and file manipulation. Built-in functions tend to run faster than ordinary Miva Script code, so you should try to use of them whenever appropriate.
Calling built-in functions follows the same rules as calling user-defined functions: functions can and must appear in expressions only, and function arguments can consist of any expression:
- <MvEVAL EXPR="{fdelete(filename $ '.dat')}">
- ...
- <MvIF EXPR="{asciivalue(char) GT 32}">
Time Functions
Most of these functions must be called with two arguments, here designated time_t and time_zone. time_t is the number of seconds since the beginning of C.U.T. (Coordinated Universal Time) at 00:00:00 January 1, 1970. This value can be obtained from the system variables time_t and dyn_time_t (time_t is set when the script starts executing; dyn_time_t is updated at the moment that it is used; which one you use depends on what your program does). time_zone is the number of hours before or after GMT; this value can be obtained using the built-in function timezone(). Here is an example of how a time function can be called:
- <MvASSIGN NAME="my_time_zone" VALUE="{timezone()}">
- <MvASSIGN NAME="now" VALUE="{time_t_sec(dyn_time_t,my_time_zone)}">
Note: These functions cannot be used to process dates earlier than January 1, 1970, or later than January 19, 2038.
The following code will perform a "time delay", (also called a "wait" or "sleep") during which the program appears to do nothing. The value of the variable delay is the number of seconds of delay time.
- <MvASSIGN NAME="delay" VALUE="10">
- <MvASSIGN NAME="stop" VALUE="{dyn_time_t+delay}">
- <MvWHILE EXPR="{dyn_time_t LE stop}"
- <MvWHILE>
Text String Functions
Note: Literal strings or characters used as arguments to these functions must be surrounded by single quotes, '...'. For example: isalpha('r2d2'). These functions do not modify their arguments; they return values based on those arguments.
Boolean-valued String Functions
These functions all start with is (for example, isalpha(), isdigit) and return a true (1) or false (0) value depending on the composition of the string. Each of these functions is based on the C language function of the same name, but is applied to the whole string: isdigit(string) will return true if every character in the string is a digit, and false otherwise.
Note: For all functions except isdigit() and isxdigit(), the set of characters understood to be alphabetic is inherited from the setlocale() setting used on the machine running Miva. For this reason, these functions are not guaranteed to return the same results on all machines.
Other String Functions
Note: The asciichar(n) function puts out a single byte whose value is n. It is up to the client application (such as a browser) to render this value as a character. Almost all HTML browsers support the ISO Latin-1 character encoding, and will display asciichar(n) as the character whose ISO Latin-1 (decimal) encoding is n. The rendering of non-printable characters, and values of asciichar(n) where n is not associated with a character in ISO Latin-1, is undefined. In particular, the rendering of asciichar(n) where n is in the decimal range 129-160, is undefined, though many browsers will display the corresponding ANSI character. The rendering of the output of asciichar(n) by an arbitrary application follows the character encoding used by that application, and is in general platform-specific.
Numerical Functions
The arguments of the trigonometric functions sin, cos, tan, sinh, cosh, and tanh should be expressed in radians; the results of asin, acos, atan, and atan2 are expressed in radians. One radian is equivalent to 180/pi degrees, or approximately 57.296; to convert from degrees to radians, divide the number of degrees by 57.296. To convert from radians to degrees, multiply by this value.
Function arguments in radians can be given in the range 0 to 2pi, or -pi to pi: for example (5/4)pi and (-3/4)pi are the same. Function results in radians are always returned in the range -pi to pi: for example the angle equal to 225 degrees will always be returned as (-3/4)pi radians (-2.356) rather than (5/4)pi.
Note: The cotangent, secant, and cosecant values are the reciprocals of the tangent, cosine, and sine respectively.
File System Functions
These functions operate only on files in the Miva data directory (f-functions) and script directory (s-functions). fs- and sf functions operate on both directories. All filenames and paths must be relative to one of these directories. Literal filenames and paths must be surrounded by single quotes. For example:
- <MvIF EXPR="{fexists('mondo.dat')}">
(Filenames and paths can also be represented by variables, which must not be surrounded by quotes.)
On both Windows and UNIX, use forward slashes, '/', (as in UNIX) to separate folders/directories:
- <MvEVAL EXPR="{fsize('templates/bbs/msgs.dbf')}">
Except as indicated, all file system functions return a value of '1' (true) if they succeed, and '0' (false) if they fail. Note that this value will be output if assigned to EXPR by <MvEVAL>. You can avoid this by using <MvASSIGN> instead.
Built-in System Functions
Language Identifiers
See chapter 19. "Localization".
Sources of Additional Information
This manual attempts to cover all of the features of Miva Script but cannot provide information on all Miva Script-related topics. You are encouraged to consult third-party printed and online references as you require. The following sites contain information that may help along the way:
The World Wide Web Consortium (W3C) site at http://www.w3c.org/ contains a wealth of information on Web-related topics, such as HTML, HTTP, and XML.
The HTML 4.0 Sourcebook by Ian Graham has an associated web site (http://www.wiley.com/compbooks/graham/html4ed/) that contains a number of Web references.
| Join Our Mailing List | Privacy Policy | Store Policies | Contact Us |
| © Copyright 2008 Miva Merchant. All Rights Reserved. |