|
|||||||
|
|
|||||||
Home // Docs // Miva Script Reference |
Miva Script Reference ManualDocument Revision
1.4
Miva Script programsMiva Script programs are HTML documents that also contain tags from the Miva Script programming language. Miva Script is a 'server-side' scripting language that is implemented by Miva Empresa and Miva Mia rather than by the browser (by contrast, a 'client-side' language such as JavaScript is implemented by the browser). Miva Script programs can also be called scripts, active documents, or simply documents. Miva Script tags correspond to typical programming language constructs such as assignment statements, conditional expressions, loops, and input/output statements, as well as Miva Script's special database, mail, and commerce functionality. Miva Script tags are XML-based: they have the same format as HTML tags; the element names (for example, <MvASSIGN>) indicate their function; and the attributes specify values that the tags operate on. Miva Script tags can be freely mixed with HTML tags. We speak of Miva Script programs being interpreted (by the Miva Empresa or Miva Mia pre-processor) and of individual tags being executed. Miva Script programs use the following kinds of auxiliary files:
When a browser requests a Miva Script document, Miva Empresa or Miva Mia will pre-process the document before passing it on to the browser:
Creating URLs for Miva Script programsMiva Script programs should have a distinctive file extension. Unless some other extension has expressly been established on your system, we recommend the .mv extension. The URL that you use to access your documents depends on whether you are using Miva Empresa or Miva Mia, and in the case of Miva Empresa, how the server is configured. Miva EmpresaIf Miva Empresa is running as a CGI application, it will be installed in the cgi-bin directory on your server. Typically Miva Empresa can be accessed by a URL in the following format: http://www.your_isp.com/cgi-bin/miva If in doubt, you should confirm this location with your ISP. If your ISP is providing you with a virtual domain, Miva Empresa can be configured to run with a URL of the following format: http://www.your_domain.com/cgi-bin/miva When Miva Empresa is installed and configured, a specific directory is designated as the Miva Script document directory (with the mivaroot parameter in the Miva Empresa global configuration file). This is the default location for running Miva Script programs on your server. To run programs located in that directory, you would use a URL of the following form: http://www.your_isp.com/cgi-bin/miva?scriptname.mv That is, put a '?' between the Miva Empresa URL and the script name. If you are running a virtual domain, use the other form of the Miva Empresa URL: http://www.your_domain.com/cgi-bin/miva?scriptname.mv If authorized, individual users can also run scripts from their home directories. Miva Empresa designates a subdirectory of the user's home directory as their script directory. By default this is the directory public_html, but Miva Empresa can be configured to use another directory by way of the userdir parameter in the Miva Empresa global configuration file. To run a script called apples.mv in his or her public_html directory, the user jsmith would use the following URL: http://www.your_isp.com/cgi-bin/miva?~jsmith/apples.mv That is, the '?' should be followed by ~username, followed by the script name. The NSAPI (Netscape API) version of Miva Empresa does not require that a Miva Script document be in a particular location; instead, the file name extension .mv triggers Miva Empresa. For example: http://www.your_isp.com/apples.mv Miva MiaIf you are running Miva Mia, there is only one Miva Script document folder, also called the HTML document folder, whose location is indicated in the WWW tab of the Miva Mia properties dialog. The URL for accessing the Miva Mia server is indicated in the Status tab. Typically, a script in your documents folder can be accessed with a URL in one of the following forms: http://host.domain/script.mv http://your_IP_address/script.mv http://localhost/script.mv http://127.0.0.1/script.mv See the Miva Mia Administration page for more information. Data filesData files (external input and output files, database files, database indexes) used by Miva Script programs must be stored in specific locations. For Miva Empresa these locations are set for specific users or groups in the Miva Empresa authorization file. By default, a user's data directory is the directory mivadata in their home directory. Contact your ISP or system administrator to find out the configuration for your server. For Miva Mia the data folder is indicated in the WWW tab of the Miva Mia properties dialog. There is no limit on the length of a filename that can be used by Miva Script, except for any limit that may be imposed by the operating system. Writing a Miva Script programThis section describes a small Miva Script program to get you started. Even if you don't understand everything, you may find it useful to enter the program and open it with your browser, just to get an idea of what Miva Script programming is like and how to run a program. <HTML>
<HEAD>
<TITLE>A simple Miva Script program</TITLE>
</HEAD>
<BODY>
<H2>A simple Miva Script program</H2>
<MvASSIGN NAME="var1" value="5">
<MvASSIGN NAME="var2" value="8">
<P><b>The answer is: <MvEVAL EXPR="{var1 + var2}">.</B></P>
</BODY>
</HTML>
If you save this document in the Miva Script document folder and submit it to your browser, Miva Empresa or Miva Mia will process it and send the results to the browser. The browser should display something like this:
Even though this program is simple, it illustrates several important features of Miva Script programs:
These features are explained further in the sections that follow. TagsAll Miva Script tags (also called elements) consist of a start-tag, such as <MvIF>, and sometimes an end tag, such as </MvIF>, that begins with the '</' characters. End-tags are either required or prohibited: tags that can have end-tags must have them in order for the program to be correct; for all other tags, end-tags are prohibited. Tags for which end-tags are prohibited are called empty tags. Not only do empty elements not have end-tags, you cannot enter any 'content' for these elements, except for attribute values in the start-tag. The <MvIF> tag requires an end-tag: <MvIF EXPR="{age GT 6}">
...some code and/or text...
</MvIF>
<MvEVAL> is an empty tag that has attributes: <MvEVAL EXPR="{age + 1}">
<MvELSE> is an empty tag that has no attributes: <MvELSE> The summary sections in this manual for each tag will indicate an end-tag if one is required. If an element with paired tags is nested inside another element, the tags must be balanced; that is, the innermost element's start- and end-tags must both be between the start- and end-tags of the outermost element. For example: <MvCOMMENT> Incorrect! </MvCOMMENT>
<MvWHILE ...>
<MvIF ...>
...
</MvWHILE>
</MvIF>
<MvCOMMENT> Correct! </MvCOMMENT>
<MvWHILE ....>
<MvIF...>
...
</MvIF>
</MvWHILE>
If you use a context-sensitive editor such as HoTMetaL PRO to create Miva Script code, this kind of problem will not happen. AttributesMost start-tags can contain attributes: these are names that are assigned a value surrounded by double-quotes. Attribute values are data or other instructions that are used by a Miva Script or HTML tag. For example: <MvASSIGN NAME="age" VALUE="10"> This tag has two attributes, NAME and VALUE, with values age and 10, respectively. The <MvASSIGN> tag assigns the value (10) specified with VALUE to the variable (age) specified with NAME. Attribute values must be surrounded by double quotes for SGML and XML conformance. Attribute values are often specified as literal values (text or numbers), as in the example above. Any attribute value can be specified as an expression or macro, however. Before the tag containing the attribute is executed, the expression or macro will be evaluated and the resulting values assigned to the attribute. For example: <MvASSIGN NAME="person1" VALUE="shirley">
<MvASSIGN NAME="&[person1];" VALUE="{5+10}">
In the second <MvASSIGN>, the macro &[person1]; evaluates to 'shirley', and {5+10} evaluates to 15, so this tag is equivalent to: <MvASSIGN NAME="shirley" VALUE="15"> In the tag summary sections of this manual, the expected values given for attributes indicate the values' semantics, that is, what kind of value--filename, mail server, function name, URL, etc. is required. In some cases, the value of an attribute must be one or more variables; otherwise, a literal, expression, or macro can be used to provide the attribute value. (A macro that evaluates to a variable name can also be used in place of a variable name.) Using tags inside tagsMiva does not interpret tags used inside other tags as attribute values. For example, the following tag will not have the (intended) effect of specifying a URL: <A HREF='<MvEVAL EXPR="{guestbook_url}">'>Say hi</A>
Sometimes you can accomplish what you want to do by using a macro. You could rewrite the previous example as follows: <A HREF="&[guestbook_url];">Say hi</A> In general you you cannot use a Miva Script tag as the value of the attribute of an HTML tag, but you can use an HTML tag as the value of the attribute of a Miva Script tag. For example: <MvEVAL EXPR="<INPUT TYPE='text' NAME='speak'>"> Another way to express this is: <MvASSIGN NAME="textbox" VALUE="<INPUT TYPE='text' NAME='speak'>"> &[textbox]; These examples will display a text box in the browser. You can use the same constructions to run other HTML code, such as applets. If you embed a tag containing attributes in an attribute, you must use a different quote character to delimit the attributes of the embedded tag than is used to delimit the attribute in which the tag is embedded. See Using quotes and other special characters in expressions for more information. Putting comments in your program - MvCOMMENTA comment is a piece of code that is not executed or displayed, but is present to indicate what the program is for and what individual pieces of code do. Comments are invaluable to someone unfamiliar with the program who is trying to understand it, or even to the program's author, who may be reading it again several weeks or months after writing it. Comments are also useful when you are developing, debugging , and testing your program: you can surround with comments lines of code that you think may have problems, to make sure they do not get processed, and then observe the results when the program is run. Comments start with <MvCOMMENT> and end with </MvCOMMENT> : <MvCOMMENT> this is a comment </MvCOMMENT> <MvCOMMENT> This is a comment too, because comments can span multiple lines. </MvCOMMENT> Text or code placed between <MvCOMMENT> and </MvCOMMENT> tags will not be passed on to the Miva Engine or the browser--it is completely ignored. . You can also use ordinary HTML comments; these are passed to the browser but are not displayed. For example: <!-- I am a comment. --> Miva Script variablesA variable is a name that is associated with a value. For example, the name x could have the value 10, or, since it's helpful to use names that indicate what they're used for, age could have the value 10. In Miva Script, a variable name can consist of the letters a through z (upper and lower case), the underscore, '_', and the digits 0 through 9. Other characters are permitted if they are 'escaped' with a backslash. For example: <MvEVAL EXPR="{age\-old}">
This evaluates the variable age-old; without the backslash, this expression would be interpreted as the value of age minus the value of old. The backslash is not required if the variable is used in a macro. The period (dot), '.', character can appear in variable names, but only when following a prefix that indicates the scope in which the variable is understood. If the variable will be used in an expression, the variable name must start with a letter or an underscore. Variables that start with numbers are not supported in expressions unless they start with a scope prefix (g., l., s., or d.). Variables used in macros are permitted to start with a number. It is recommended that you avoid using variable names that start with numbers or contain 'escaped' characters, unless they are required because they correspond to the names of fields in an HTML form, and no alternative names can be used. Miva Script variable names are not case-sensitive: the variable age is the same as AGE and Age. Here are some examples of valid and invalid usage: <MvCOMMENT>Valid</MvCOMMENT>
<MvEVAL EXPR="{_13user}">
<MvEVAL EXPR="{user_13}">
<MvEVAL EXPR="{g.user_13}>
<MvEVAL EXPR="{g.13_user}">
&[13_user];
&[g.13_user];
<MvCOMMENT>Invalid</MvCOMMENT>
<MvEVAL EXPR="{13_user}">
<MvEVAL EXPR="{g.user.13}">
Unlike in some programming languages, you do not need to declare or define variables--you can just go ahead and use them. Using a variable in an expression without first assigning it a value also does not cause an error (although it may, of course, be responsible for a logic error in your program). Miva Script variables are typeless: the same variable can be assigned a numerical, text string, or boolean (true/false) value. You can give a variable a value in two ways:
To display the value of a variable, use the <MvEVAL> tag or a macro: <MvEVAL EXPR="{var}">
&[var];Using <MvASSIGN>
The simplest way to assign a variable a value is with the <MvASSIGN> tag. For example: <MvASSIGN NAME="age" VALUE="10"> This gives the variable age the value 10. <MvASSIGN> has two attributes, NAME and VALUE, which specify the variable name and value, respectively. Both the name and value can be specific values, such as age and 10 in the previous example, or they can be expressions, which are evaluated only when the program is run. For example: <MvASSIGN NAME="age" VALUE="{2 + 8}">
<MvASSIGN NAME="age" VALUE="{age + 2}">
<MvASSIGN NAME="age" VALUE="{thisyear - birthyear}">
These examples show three different kinds of expressions (the expressions start with '{' and end with '}'). The first expression consists of two numbers added together. The second expression adds 2 to whatever the current value of age is (this value then becomes the new value of age). The third expression uses two other variables (birthyear and thisyear) and subtracts them to calculate the new value of age. Although these examples use expressions only in the value of the VALUE attribute, the NAME attribute can also have an expression as its value.
Assigning variables in HTML formsA variable can be created and assigned a value in an HTML form. Since HTML forms are the primary way of obtaining input from users, you will often be assigning values to variables using this method. In an HTML form, each button, text box, pull-down menu, and scrolling list has a name attribute. For each such object, Miva Script creates a global variable whose name is the same as the value of the object's NAME attribute. When the form is submitted, the values entered for each object in the form are assigned to the corresponding variables. For example, the following markup creates a text box with the name speak: <INPUT TYPE="TEXT" NAME="speak"> Based on this, Miva Script will create a variable called speak; it will be assigned a value if a user enters a value in the text box and submits the form to the Miva Script program, and can then be manipulated and operated upon by the receiving program. For text boxes and text areas, the value of the variable is whatever text the user enters. Check boxes, radio buttons, scrolling lists, and pull-down menus are defined with a fixed set of one or more possible values, specified by the object's VALUE attribute. The Miva Script variables corresponding to these form objects can have one of these fixed values when the form is submitted, but can be given other, arbitrary values later in the Miva Script code. For example: <INPUT TYPE="CHECKBOX" NAME="send_info" VALUE="yes"> If this checkbox is turned on when the form is submitted, the variable send_info will have the value yes. Here is another example, using radio buttons: <B>Language/langue:</B><BR> <INPUT TYPE="RADIO" NAME="language" VALUE="english">English<BR> <INPUT TYPE="RADIO" NAME="language" VALUE="french">Français<BR> In this example, the variable language can have the value english or french (depending on which button is selected) when the form is submitted.
See the section Multiple passes through a program for more information on using variables set in forms. Variable scopeThe scope of a variable is the context in which it exists and has meaning. There are two aspects of variable scope: the a variable's scope inside the currently running program, and its scope in another program called by the current program. By default, the maximum scope of any variable is the currently running program instance; if this program calls another program (or calls the same program a second time), the values of variables in the current program are not automatically available in the second program. There are several methods for passing variables and other data to a program: see Passing data to a program below. Prefixes in the variable name define its scope in the current program. The variable scopes available in Miva Script are:
A global variable and a local variable with the same primary name can be used as two different variables if they're prepended with the appropriate prefixes (for example, g.counter and l.counter). If a variable var without a prefix is encountered, the Miva pre-processor carries out the following steps in order until one of them succeeds:
The built-in function miva_getvarlist(scope) returns a comma-separated list of the names of all currently defined variables with the given scope. scope must be a literal string: 'l', 'local', 'g', 'global', 's', 'system'.
The following detailed example illustrates these rules (for simplicity, only global and local variables are contrasted here). <BODY>
<MvFUNCTION NAME="f1">
E: <MvEVAL EXPR="{new1}"><BR>
F: <MvASSIGN NAME="new1" VALUE="20"><BR>
G: <MvEVAL EXPR="{g.new1}"><BR>
H: <MvASSIGN NAME="l.new1" VALUE="30"><BR>
I: <MvEVAL EXPR="{new1}"><BR>
J: <MvEVAL EXPR="{g.new1}"><BR>
K: <MvASSIGN NAME="new1" VALUE="40"><BR>
L: <MvEVAL EXPR="{l.new1}"><BR>
M: <MvEVAL EXPR="{g.new1}"><BR>
</MvFUNCTION>
A: <MvASSIGN NAME="new1" VALUE="10"><BR>
B: <MvEVAL EXPR="{new1}"><BR>
C: <MvEVAL EXPR="{g.new1}"><BR>
D: <MvASSIGN NAME="junk" VALUE="{f1()}"><BR>
N: <MvEVAL EXPR="{new1}"><BR>
...
</BODY>
The output from this program is: A: B: 10 C: 10 D: E: 10 F: G: 20 H: I: 30 J: 20 K: L: 40 M: 20 N: 20 It is worth analyzing this output in detail:
Site variablesSystem administrators of servers running Miva Empresa can maintain a file called the site variables file that contains definitions for variables (but not functions) that are accessible to all Miva Script programs running on the server. The Miva Mia users can maintain site variables files on their PCs. A variable in the site variables file can be used in the same way as any other global variable. Variables in a the site variables file are intended to be assigned string values only; the results of assigning Miva tags to variables are undefined. Expressions and literalsAn expression is a formula that can be evaluated to give a result. Expressions always occur in attribute values and must be enclosed in curly brackets, '{' and '}'. Expressions can contain variables, literal values (text or numbers), and operators, which indicate how the other components in the expression are to be evaluated. In general, Miva Script expressions can be used in two ways:
A literal is a number or a string of characters that is not meant to be evaluated: for example: 23 and 'hi there'. Literals don't have to be enclosed in curly brackets. In general, if an attribute value (except for a macro) needs to be evaluated, it must be enclosed in curly brackets. When an value surrounded by curly brackets is used in an attribute value, the open bracket must immediately follow the double-quote character that starts the attribute value (that is, there must be no spaces between them; similarly, the closed bracket must immediately precede the double-quote that terminates the attribute value. If you don't do this, the expression will be treated like a literal string. For example: <MvCOMMENT> Wrong! </MvCOMMENT>
<MvEVAL EXPR=" {a + b} ">
<MvCOMMENT> Right! </MvCOMMENT>
<MvEVAL EXPR="{a + b}">
Here are some examples of expressions: {age}
{age + 1}
{age GE 17}
{x * (y / z)}
{'a' IN name}
These examples contain:
Notice also that a single variable name can be an expression. Conversely, an expression can have as many components as are required. Inside an expression, spaces are not significant (that is, they do not affect how the expression is evaluated) except in the following ways:
One use for expressions that you've seen already is in a variable assignment: <MvASSIGN NAME="age" VALUE="{age + 10}">
Expressions are also used in conditionals, which test some condition and (usually) take an action based on the results of the test. Here is an example: <MvIF EXPR="{age GE 17}">
<p><b>This person is eligible to drive a motor vehicle.</b></p>
</MvIF>
This <MvIF> tag tests the expression '{age GE 17}' ("Is the age greater than or equal to 17?") and if that expression is true (which depends on the current value of age), it prints some text. An expression consisting only of a literal string does not require curly brackets. If a literal string is inside curly brackets, it must be surrounded by single quotes (that is, the apostrophe or front quote character, '...'). The following tags are equivalent: <MvASSIGN NAME="person" VALUE="Moira">
<MvASSIGN NAME="person" VALUE="{'Moira'}">
If you want to put a literal string of text in an expression that contains operators or variables, surround the literal with single quotes . For example: <MvASSIGN NAME="boss" VALUE="{'Fred ' $ 'Flintstone')">
Here the literals Fred and Flintstone are surrounded by double quotes. You should represent a null string in an expression as two single quotes (''): <MvIF EXPR="{entry EQ ''}">
The Miva Script comparison or logical operators (such as GE and AND) always produce a result of 0 (false) or 1 (true).
Using quotes and other special characters in expressionsSince expressions have to be surrounded by double quotes, you have to use special techniques if you want to put double quotes in expressions. There are two ways to handle this:
If you want to assign a string of HTML (but not Miva Script) code to a variable, you can use single quotes instead of double quotes to surround attribute values. The code in the variable can then be passed to the browser using <MvEVAL>. Since the browser cannot execute Miva Script code, you should pass only HTML code to the browser in this way. <MvASSIGN
NAME="input1"
VALUE = "Address: <INPUT TYPE='text' NAME='address'>">
<FORM
ACTION = "http://www.sq.com/cgi-bin/quagmire"
METHOD = "post">
<MvEVAL EXPR = "{input1}">
</FORM>
This displays: The code in this example assigns a string to a variable named input1. The value of input1 is HTML code that generates a text box with the label "Address:". Miva will evaluate input1 to send the HTML code to the browser; it also creates a Miva Script global variable called address (or g.address). If you really have to use double quotes, you can use the built-in function asciichar(n) to represent the double quotes. asciichar(n) is equivalent to the character whose ASCII code is n. The code for a double quote happens to be 34. You will also need to use the concatenation operator, $, to join this character to the rest of your text. For example: <MvASSIGN
NAME="banner"
VALUE="'Home of '$asciichar(34)'The Best
Wings in Town'$asciichar(34)'!'">
<MvEVAL EXPR="{banner}">
This displays: Home of "The Best Wings in Town"! Notice that the literal parts of the expression have to be surrounded by single quotes. Other special charactersYou can use the asciichar(n) function to represent other characters that you cannot use literally in an expression, for example, carriage return and line feed. If you will be using these characters often you can assign asciichar(n) to a variable and use the variable instead. For example: <MvASSIGN NAME="dq" VALUE="{asciichar(34)}">
<MvASSIGN NAME="cr" VALUE="{asciichar(13)}">
<MvASSIGN NAME="lf" VALUE="{asciichar(10)}">
<MvASSIGN NAME="crlf" VALUE="{asciichar(13)$asciichar(10)}">
<MvEVAL EXPR="{'Dear User,'$crlf$'Thank you for your interest.'}">Displaying the result of an expression - MvEVAL
There are many ways of evaluating an expression, but if you want to display the result in the browser, you should use the <MvEVAL> tag. For example: <p><b>The final amount is: <MvEVAL EXPR="{price*units}">.</b><p>
Another way to think about the <MvEVAL> tag is that it is replaced, in an HTML document, with the result of an expression. The <MvEVAL> tag has one attribute, EXPR, whose content can be an expression to be evaluated, or a literal string or number. If the content is an expression it must be enclosed in curly brackets, or it will be treated like a literal and not evaluated. Normally, if you want to display a literal you would just enter it directly in the HTML file, rather than using an <MvEVAL>. When multiple fields in a form are given the same name (e.g. "name"), return values will be comma delimited. For example, the following: name1<INPUT TYPE="text" NAME="name"><BR> name2<INPUT TYPE="text" NAME="name"><BR> name3<INPUT TYPE="text" NAME="name"><BR> name4<INPUT TYPE="text" NAME="name"> <INPUT TYPE="submit VALUE="Submit Query"> The results of "<MvEVAL EXPR="{ name }">" ...will be "1,2,,4" See also the section on macros. Miva Script operatorsAn operator in a Miva Script expression indicates how the data it acts on are to be processed: added, subtracted, compared, joined, bit-shifted, and so forth. In the expressions {age + 10} and {age GT 16}, '+' and 'GT' are operators. The components on each side of the operator are sometimes called operands. Miva Script operators have a built-in precedence that determines which operator gets interpreted first if there are two or more operators in an expression. You can also override the built-in precedence by surrounding sub-expressions with parentheses, `(' and ')'. Miva Script provides the following types of operators:
Arithmetical operatorsThese operators are used with numbers or numeric expressions. Miva Script also supports a number of built-in numerical functions.
Comparison operatorsThese operators are used to compare two numbers or two text strings. In text string comparisons, lowercase letters are considered to be greater than uppercase letters. Two strings are equal only if the case (upper or lower) matches letter-by-letter. These operators all give a value of 1 (true) or 0 (false).
Logical operatorsThese operators are used with 'true' or 'false' expressions. For example: <MvIF EXPR="{age GE 17 AND age LT 80}">
This expression is true if both of the expressions '{age GE 17}' and '{age LT 80}' are true.
Text string operatorsThese operators are used with text strings or text string expressions. Miva Script also supports a number of built-in string functions.
Bitwise operatorsThese operators act on numbers at the binary or 'bit' level. For example, BITAND compares the bits of two numbers, and returns a third number whose bits are equal to 1 (turned on) only if the same bits are equal to 1 in both the original numbers. That is, it performs a logical AND on corresponding bits. The expression '{27 BITAND 13}' is evaluated as follows: 27 has the binary (base 2) form '00011011'; 13 has the binary form '00001101'. The only bits that are equal to 1 in both numbers are the first and fourth (counting from the right); therefore, the result is the number that has those bits equal to one, and all others equal to 0: 00001001, or 9 in decimal form.
Order of precedence for operatorsSometimes an expression can be interpreted in more than one way, depending on which operators are executed first. For example, {2 + 3 * 4} could be evaluated as 14 or 20, depending on whether the + or the * was evaluated first. In order to make the expected results unambiguous, Miva Script follows three rules:
The order of precedence for Miva Script operators, from highest to lowest, is as follows:
According to these rules, {2 + 3 * 4} is evaluated to 14, because '*' has a higher precedence than '+'. If you really want the '+' to be evaluated first, you can use parentheses: {(2 + 3) * 4}. In the expression {2 / 4 * 5}, both operators have the same precedence, so the leftmost one (/) is evaluated first, and the result of the whole expression is 2.5. MacrosSo far you have seen <MvEVAL> used to obtain (and display) the value of variables and expressions. Sometimes you will want to obtain and use a variable value in contexts where <MvEVAL> is not appropriate. For example, you cannot assign the value of a variable to an HTML attribute using <MvEVAL> or a Miva Script expression. One way to use a variable value is by using it in a macro expression. This allows you to use the contents of a variable as in-line HTML or Miva Script code. The syntax of a macro is: &[ variable_name ]; When a Miva Script tag is processed, any variables found inside '&[ ...];' will be evaluated before the rest of the tag is parsed and or executed.
For example, suppose the variable server_name has the value www.sq.com. The following code uses the value of server name to create a URL: <A HREF="http://&[server_name];/index.html">Home Page</A> In this example, the value of server_name will be substituted for the '&[...];'. The tag above is equivalent to: <A HREF="http://www.sq.com/index.html">Home Page</A> The characters '&' will also function as the start of a macro: &[var1]; and &[var1]; are equivalent. The semi-colon at the end of a macro is optional, but, if you want a semi-colon to be displayed after a macro, you will have to enter it twice (for example, &[var];;). To summarize, the following four forms are equivalent: &[variable]; &[variable] &[variable]; &[variable] The variable used in a macro can also stand for executable code. The current implementation of Miva Script does not support macros that stand for Miva Script code that involves a loop or other jump. For example:
Macros provide the capability for "indirection" and self-generating code: <MvASSIGN NAME="var_a" VALUE="var_b">
<MvASSIGN NAME="var_b" VALUE="burrito">
<MvEVAL EXPR="{&[var_a];}">
'<MvEVAL EXPR="{&[var_a];}">' will display the value burrito. This may seem surprising at first, but you should consider the order in which the Miva Script code is evaluated. First, the macro substitution takes place: in this step, the expression '&[var_a];' is replaced by the current value of var_a. This is the string, not the variable, 'var_b'. The <MvEVAL...> tag becomes, in effect: <MvEVAL EXPR="{var_b}">
Then the resulting <MvEVAL...> is executed. The EXPR '{var_b}' is evaluated, and its value, the string 'burrito', is displayed. Many of the functions of macros can also be carried out using the string concatenation operator, '$'. For example: <MvASSIGN name="firstname" value="Alex">
<MvASSIGN name="lastname" value="DeLarge">
<MvEVAL expr="&[lastname];, &[firstname];">
<MvEVAL expr="{lastname $ ', ' $ firstname"}>
The two <MvEVAL> tags in this example each display the same thing: 'DeLarge, Alex'.
Security issues with macrosBecause Miva Script macros can be used to insert executable Miva Script code directly into a script, a potential security problem exists. If user input is displayed using a macro, and that input contains executable Miva Script code (such as calls to built-in file manipulation functions) then unexpected and undesirable results may occur. However, good programming practices can prevent this from happening.
Macro encodingThe value of a macro can be URL- or entity-encoded before it is put out. This can be used to make the macro output secure. Entity-encodingThe following construction converts all characters in the macro output that have HTML entity equivalents to those entities (this is equivalent to applying the encodeentities() function): &[var:entities]; For example: <MvASSIGN NAME="Step1" VALUE="Press <Enter>"> &[Step1];<BR> &[Step1:entities]; This code will display: Press Press <Enter> When &[Step1]; is evaluated, the string <Enter> is passed to the browser; since this is an unknown tag, it is not displayed. When &[Step1:entities]; is evaluated, the '<' and '>' characters are converted to entities: Press <Enter>. This string is displayed as intended in the browser. URL-encodingA string that results from a macro evaluation can be URL-encoded to make it safe to use as a name or value in a URL query string (that is, the part of a URL to the right of the '?', if there is one). In this encoding, special characters such as +, %, &, =, and space are replaced by safe equivalents. Note that encoding query strings is not identical to encoding the 'document' part of the URL (the part to the left of the '?'): for example, a space in a query string is encoded as '+', whereas in a document URL it is encoded as '%20'. The following construction URL-encodes the macro output; this is equivalent to applying the encodeattribute() function. &[var:attribute]; For example, if var has the value 'R&D', &[var:attribute]; produces 'R%26D'. You should use this form of the macro if you are using the macro output as a name or value in a query string. Do not encode an entire query string: if you do, the '=' between names and values, and the '&' between pairs will be encoded and thus lose their special meanings. Configuring the Miva processor
You can use as many <MIVA> tags as you need, to turn various features on and off as needed throughout your program. Each <MIVA> tag can specify one or more attributes. The STANDARDOUTPUTLEVEL and ERROROUTPUTLEVEL attributes can also be specified for individual user-defined functions. When any <MIVA> attribute is omitted, its default setting is assumed. The 'STANDARDOUTPUTLEVEL' attribute has an additional option. This is the 'compresswhitespace' option. When enabled, it will cause the Miva Engine to eliminate any extra whitespace in the output of Miva Script code. Configuring Miva Script code interpretationThe Miva Script code in a program typically consists of Miva Script tags and macros. You can use the INTERPRET attribute of <MIVA> to specify whether the Miva interpreter will execute tags, macros, or both. By default (that is, if you don't have an explicit setting for INTERPRET) both are interpreted. The possible INTERPRET values are:
Configuring the outputA Miva Script program typically consists of Miva Script tags, Miva Script macros, HTML tags, and text (this includes white space such as newlines between tags). The Miva interpreter always sends the results of any Miva Script tags it interprets to the browser; you can use the STANDARDOUTPUTLEVEL attribute of <MIVA> to indicate whether or not you want the Miva processor to pass HTML tags and text to the browser. By default (that is, if you don't have an explicit setting for STANDARDOUTPUTLEVEL) both are passed to the browser.
The possible STANDARDOUTPUTLEVEL values are:
For example, this setting will cause only tags to be sent to the browser: <MIVA STANDARDOUTPUTLEVEL="html"> One of the most common uses of STANDARDOUTPUTLEVEL is preventing unnecessary and excessive white space in the output of the program: when a line of Miva Script code is executed, any spaces, tabs, or newlines on that line are passed to the browser. To avoid this (and thereby possibly speed up your output), you can set STANDARDOUTPUTLEVEL to html only. This causes all literal text in the document to be suppressed, so if there is some text that you want to display anyway, you must use an <MvEVAL> tag to display it. The output of <MvEVAL> is always passed to the browser, no matter what the value of STANDARDOUTPUTLEVEL is. Default macro encodingThe Miva Script DEFAULTMACROENCODING attribute will assign the default encoding type to all macros. There are three values that can be assigned to the attribute:
Configuring error reportingMiva Script can report three kinds of errors:
The ERROROUTPUTLEVEL attribute of <MIVA> enables you to specify which kinds of errors Miva Script will report. By default (that is, if you don't have an explicit setting for ERROROUTPUTLEVEL) all three types of errors are reported. The possible values are any combination of syntax, expression, and runtime, comma-separated. For example, to have only syntax and expression error messages displayed, you would use: <MIVA ERROROUTPUTLEVEL="syntax,expression"> To turn off all error reporting: <MIVA ERROROUTPUTLEVEL=""> You can specify a default error message that will be displayed before other, standard error messages. To do this, specify a value for the ERRORMESSAGE attribute of <MIVA>. The default is the null string. Here is an example: <MIVA ERROROUTPUTLEVEL="runtime"
ERRORMESSAGE="Now look what you've done! :-)">
If specified, this message will be displayed even if all forms of error reporting are turned off. For more information on Miva Script error messages, see Configuring runtime error handling. Configuring runtime error handlingWhenever executing a Miva Script tag results in an error, the text of the error message is assigned to a variable that has the same name as the tag, but with the _error suffix added. This text is identical to the error message that the script displays by default in the browser window. For example, errors from <MvIMPORT> will be assigned to the variable mvimport_error. Your script can test the contents of these variables and take some action based on the results of this test. For example: <MvIMPORT FILE="bogus.dat" FIELDS="v1,v2,v3" DELIMITER=",">
....
</MvIMPORT>
<MvIF EXPR="{'cannot find the file' CIN mvimport_error}">
<PRE>File not found.</PRE>
</MvIF>
Make sure to put the <MvIF> somewhere that it will be executed--if you were to put it inside the <MvIMPORT>...</MvIMPORT> tags, it wouldn't get executed since the <MvIMPORT> loop is not entered if the input file is not found. This technique can be used to test the results of database operations such as <MvSKIP>, <MvFIND>, and <MvGO>. If you want to suppress the default Miva Script error messages from being displayed in the browser window, you can use the <MIVA> tag as follows: <MIVA ERROROUTPUTLEVEL="syntax,expression"> This setting leaves out the value 'runtime', thereby turning off runtime error messages. You can control how Miva Script handles errors for specific tags. For each tag, <MIVA> has an attribute TAGNAME_ERROR (for example, MvIMPORT_ERROR). These attributes can have the following values:
For example: <MIVA MvIMPORT_ERROR="nonfatal,nodisplay"> This will cause <MvIMPORT> runtime errors to not terminate the script or be displayed.
Using JavaScript with Miva ScriptJavaScript and Miva Script cannot interact directly, because they are processed at different points in the document-processing cycle: Miva Script code is pre-processed, before the document gets to the browser, whereas JavaScript is processed in the browser after the browser receives the document (which has already been processed by Miva). However, some interactions are possible since JavaScript code can be embedded in Miva Script documents (for example, in a <SCRIPT> tag, or as the target of a URL), just as it can be in regular HTML documents. Therefore:
Keep in mind, though, that the JavaScript code can interact directly only with the HTML code in your document, not the Miva Script code. Flow controlMost of the Miva Script code that you have seen so far has consisted of a series of tags that were executed in a straightforward, top-to-bottom manner. In fact, though, most programs have a more complex structure, or 'flow of control'. Program structures typically involve: Decision-making - MvIF
The <MvIF> tag lets the program test a condition and then take an action (or no action) depending on whether the condition is true or false. Here is an example that you saw in the section on expressions: <MvIF EXPR="{age GE 17}">
<p><b>This person is eligible to drive a motor vehicle.</b></p>
</MvIF>
In this example, the <MvIF> tests the condition '{age GE 17}' (that is, "is the value of the variable age greater than or equal to 17?"). If the condition is true, the HTML tags and text between the <MvIF> and the corresponding </MvIF> end-tag are displayed by the browser. If the condition is not true, no action is taken. <MvIF> has one attribute, EXPR, whose value is interpreted as a conditional expression, typically one involving a comparison, string, or logical operator. The action--text, HTML, or Miva Script code that you want processed if the condition is true--must follow the <MvIF> tag. You can put as many lines as you need here. Finally, an <MvIF> tag must have a corresponding </MvIF> end tag; this comes at the end of the action. You can nest <MvIF> tags--that is, enclose one inside another. You must make sure that each <MvIF> tag has a corresponding </MvIF> end-tag. Here is an example of nesting: <MvIF EXPR="{age GE 17}">
<p><b>This person may be eligible to drive a
motor vehicle.</b></p>
<MvIF EXPR="{age GT 80}">
<p><b>This person requires a re-examination.</b></p>
</MvIF>
<p><b>The license fee is $40.75.</b></p>
</MvIF>
In this example, if the value of age is 45, the code will be executed as follows:
The result will be:
Either-or decisions - MvELSEWith the simple <MvIF> described above, the program can choose whether to carry out an action. Often, though, there will be two possible actions that you might want the program to take, one if a condition is true, and another if the condition is false. In this situation, you would use the <MvELSE> tag. For example: <MvIF EXPR="{age GE 17}">
<p><b>This person is eligible to drive a motor vehicle.</b></p>
<MvELSE>
<p><b>This person is too young to drive a motor vehicle.</b></p>
</MvIF>
In this example, if age is greater than or equal to 17, the first paragraph will be displayed. If age is less than 17, the second paragraph will be displayed. <MvELSE> consists of a single tag, with no attributes. It divides the <MvIF> into two 'branches'--the code to execute if the condition is true, and the code to execute if the condition is false. If the condition is true, the code between the <MvIF> and the <MvELSE> is executed; otherwise, the code between the <MvELSE> and the </MvIF> is executed. The syntax for using <MvELSE> is: <MvIF EXPR="{expr}">
...actions for "true" case...
<MvELSE>
...actions for "false" case...
</MvIF>
Multiple decisionsSometimes the possibilities that a program has to deal with cannot be described in either/or terms--there may be three, four, or more possible situations, each requiring a different action. In Miva Script code this kind of decision making is represented with multiple, nested <MvIF>-<MvELSE>-</MvIF> tags. Here is an example: <MvIF expr="{age LT 17}">
<p>This person is too young to drive a motor vehicle.</p>
<MvELSE>
<MvIF expr="{age GE 17 AND age LE 114}">
<p>This person is eligible to drive a motor vehicle.</p>
<MvELSE>
<p>This person is too old to drive a motor vehicle.</p>
</MvIF>
</MvIF>
Here there are three cases that the program has to deal with:
The first case is covered by the first 'branch' of the first <MvIF>. If age is not less than 17, the program jumps to the second (<MvELSE>) branch of the <MvIF>. The code in this branch is another <MvIF>, which covers the other two cases. If age is between 17 and 114, the first branch is executed, otherwise, the second branch of the second <MvIF> is executed. You can nest <MvIF>-<MvELSE>-</MvIF> tags to as many levels as you like, as long as you match up the <MvIF> and </MvIF> tags properly. Repetition - MvWHILE
Many programming tasks require a series of steps to be repeated several times. Sometimes the number of repetitions is known in advance; other times the repetitions continue until a particular condition is true. This activity is called a loop; in Miva Script, general-purpose loops are carried out with <MvWHILE>...</MvWHILE> tags. (Some other tags, such as <MvIMPORT> and <MvCALL>, also loop through their input.) <MvWHILE> has one attribute, EXPR, whose value will be interpreted as a condition. The code (text, HTML, and Miva Script tags) between <MvWHILE> and </MvWHILE> will be repeated as long as the condition expr is true. You can put as many lines of code as you need here. Repeating a fixed number of timesHere is an example that displays the first five positive 'square' integers: <MvASSIGN name="num" value="1">
<MvWHILE EXPR="{num LE 5}">
<MvEVAL EXPR="{num * num}"><br>
<MvASSIGN name="num" value="{num + 1}">
</MvWHILE>
This code displays:
This code starts by assigning an initial value for the variable num. In this context num functions as a counter, a variable that is used to count how many times the loop repeats. Since we know exactly how many times to repeat, we can construct a condition to reflect that. In this case we use the condition '{num LE 5}', that is, the loop will repeat while num is less than or equal to 5. The <MvEVAL> tag evaluates and displays the square of num (num multiplied by itself). Then, since we are counting loop repetitions, the value of num is increased by 1 using <MvASSIGN>. The program then jumps back to the <MvWHILE> tag and tests the condition again. As long as num is less than or equal to 5, the loop repeats. These steps are carried out 5 times; at that point the value of num is 6, so the next time the condition is tested, it is found to be false, and the loop is not repeated. The program then jumps to the next line after the </MvWHILE> tag. This example uses a common programming technique--setting up a counter that is incremented each time the loop is repeated, and then testing that counter to decide whether the loop should keep on repeating. Common programming mistakes are forgetting to increment the counter inside the loop, and not setting it to the correct initial value before the loop starts. Note that in this case the value of the counter is used in other calculations inside the loop; this is not always the case. Repeating a non-fixed number of timesThe 'counter' technique can be used if you know exactly how many times you want the loop to repeat. Often you do not know this--the number of repetitions depends on some condition that will not be achieved in a predictable (or easily predictable) number of steps. For example, it may depend on input from a user or from a data file. In this case you have to set up your loop condition as described above, but now the condition depends on something other than a counter. You have to make sure that which ever variable(s) the loop condition tests are ones that are affected by the code inside the loop. A common programming mistake is to set up a loop condition that is always true because that condition is never affected by what goes on inside the loop. Terminating a loop with <MvWHILESTOP>
Processing can be halted inside an <MvWHILE> ...</MvWHILE> loop by using the <MvWHILESTOP> tag. This will stop execution of the code inside the loop. The program then jumps to the first line after the </MvWHILE> <MvASSIGN NAME="num" VALUE="0">
<BLOCKQUOTE>
<MvWHILE EXPR="{num LE 5}">
<MvASSIGN NAME="num" VALUE="{num + 1}">
This loop has executed
<MvEVAL EXPR="{num}"> times.<BR>
<MvIF EXPR="{num GE 3}">
<MvWHILESTOP>
</MvIF>
</MvWHILE>
<B>Finished</B>
</BLOCKQUOTE>
Since the condition governing this loop is '{num LE 5}' you might expect the loop to be repeated five times. In fact, though, the loop repeats only three times because when the condition '{num GE 3}' is met, the <MvWHILESTOP> is executed, and the loop terminates. Exiting from a program - MvEXIT
Passing data to a programThere are several ways to pass data to a Miva Script program, or from one Miva Script program to another:
Data passed in this way are referred to as arguments. Miva Script will use both conventions to interpret any data passed to a program; we recommend that you choose one or the other for each program and use it consistently within that program.
Data passed using these methods are always passed as name/value pairs. You can also pass data:
Name/value pairsData passed on the URL command line are referred to as arguments. Miva will interpret any data passed to it in this way as both name/value pairs and as an value list. In general it is not a good idea to code the program so that it uses both conventions: we recommend that you choose one or the other for each program and use it consistently within that program. You can pass data to a Miva Script program using the same syntax that a browser uses to submit a FORM with a METHOD of GET. Here is an example using the CGI version of Miva Empresa: http://www.server.com/cgi-bin/miva?fruit.mv+fruit1=black+cherries&fruit2=oranges Here is an example using the NSAPI version of Miva Empresa: http://www.server.com/fruit.mv?fruit1=black+cherries&fruit2=oranges With Miva Mia, this would be: http://127.0.01/fruit.mv?fruit1=black+cherries&fruit2=oranges These examples pass two variable values to the program fruit.mv: fruit1 has the value "black cherries", and fruit2 has the value "oranges". The fruit.mv program can use these variables with the values specified. Using this syntax, each variable name and its corresponding value must be separated by an equal, '=', sign. Each name/value pair is separated by an ampersand, '&'. Spaces are replaced by a '+' sign, and some special characters (notably newline, '=', and '&') are replaced by '%nn', where the ns are digits from 0-9 and/or letters between 'A' and 'F'. This method of receiving arguments allows a Miva Script program to process an HTML form submitted with a METHOD of GET. If a variable name is submitted without a value, the value will default to the name itself. Some characters cannot be used safely in arguments passed as a list of name/value pairs, but you can replace them by their URL-encoding. These are the most common such characters:
Value listArguments can also be passed as a simple list of values, separated by plus signs. Miva Empresa will automatically generate variable names corresponding to these values. Here is an example of calling a program with arguments using the CGI version of Miva Empresa: http://www.server.com/cgi-bin/miva?fruit.mv+black%20cherries+oranges Here is an example using the NSAPI version of Miva Empresa: http://www.server.com/fruit.mv?black%20cherries+oranges With Miva Mia, this would be: http://127.0.01/fruit.mv?black%20cherries+oranges With Miva Empresa (CGI) arguments are passed using the convention file.mv+arg2+arg3+arg4...; that is, arguments follow the filename and are separated by plus signs (+). With Miva Empresa (NSAPI) and Miva Mia the convention is file.mv?arg2+arg3+arg4...; arguments are separated from the filename by '?' and after that and are separated from each other by plus signs (+). In this example, the arguments are black%20cherries and oranges. The notation '%20' is used to represent a space character, because spaces cannot appear explicitly in URLs (see below). The model given above starts with arg2 because of the way Miva Script counts its arguments. The Miva processor automatically creates two types of variables from these arguments. A single variable, with a numerical value, called nargs is created: this variable contains the number of arguments passed to the program. Secondly, a series of variables called arg1, arg2, ..., argN (where N equals nargs, the number of arguments) is created. Each of these will contain the value of the corresponding argument passed to the program in the URL. arg1 is always the name of the program itself (and therefore nargs is always at least 1). The actual arguments start at arg2. Your program code can then do whatever you need with these arguments. In the example above:
The following characters cannot be used safely in arguments passed as a value list, but you can replace them by their hexadecimal equivalents, as indicated:
For example: http://127.0.0.1/fruit.mv?granny%20smith%20apples+oranges
If a Miva Script program is the target of a FORM's ACTION, the values of fields used in the form will be converted into Miva Script variables with the same names as the fields. Passing variables - MvHIDE
By default, when a Miva Script program calls another Miva Script program (which could be a re-invocation of the same program) the values assigned to variables in the currently running program are not available in the program that is called. Another way of expressing this is to say that the scope of a variable is the currently running program. As described above, one way to pass variables to a Miva Script program is to include them as name/value pairs on the URL by which the program is called. This isn't always convenient, since you may not know when you construct the URL which values and variables you want to pass. Miva Script provides the <MvHIDE> mechanism to make it easy for programs to pass variables to other Miva Script programs. Recall that if a Miva Script program is the target of a FORM's ACTION, the values of fields used in the form will be converted into Miva Script variables with the same names as the fields, and these variables and their values will be available in the target program. Normally these fields are visible objects such as text boxes and radio buttons, whose values are entered by the user. HTML also provides so-called 'hidden' form fields: these fields have a name and value like other form fields, but have no visual representation in the browser. Hidden fields can be used to pass variable values to a Miva Script program; <MvHIDE> provides a convenient method of generating hidden fields 'on the fly', when the form is submitted. In general, if you have variables v1, v2, v3, ..., vN whose literal values are x1, x2, x3, ..., xN, then an <MvHIDE> tag of the form <MvHIDE FIELDS="v1,v2,v3,...,vN"> will be converted to the following when the form is submitted: <INPUT TYPE="hidden" NAME="v1" VALUE="x1"> <INPUT TYPE="hidden" NAME="v2" VALUE="x2"> <INPUT TYPE="hidden" NAME="v3" VALUE="x3"> ... <INPUT TYPE="hidden" NAME="vN" VALUE="xN"> For example, if v1 has the value 6, v2 the value 8, and v3 the value 10, then: <MvHIDE FIELDS="v1,v2,v3"> Is converted to: <INPUT TYPE="hidden" NAME="v1" VALUE="6"> <INPUT TYPE="hidden" NAME="v2" VALUE="8"> <INPUT TYPE="hidden" NAME="v3" VALUE="10"> The variables do not have to be originally specified as literals: Miva Script resolves the literal value when it processes the <MvHIDE> tag. <MvHIDE> has no useful effect if it occurs outside a form.
Using cookiesEach time a cookie-enabled browser accesses a Miva Script document, Miva Script creates a 32-character cookie, with the name htscallerid, that is unique to that browser and URL. The cookie lasts for one year after being set. Cookies can be turned off in the Miva Empresa configuration file; contact your server administrator. The content of the cookie are available in the callerid system variable. If you want to create your own cookies, you can use the <META> tag (Miva Script does not let you modify the HTTP headers sent with your document). For example: <META HTTP-EQUIV="Set-Cookie"
CONTENT="id=MyCo; expires=Thu, 26 Nov 1998 16:00:00 GMT;
domain=.sq.com path=/; secure">
The HTTP-EQUIV attribute must have the value Set-Cookie, to indicate that the <META> is simulating the Set-Cookie HTTP header. CONTENT specifies the content of the cookie. This can have five parts, separated by semi-colons (;).
All of the cookies for this document are available in the http_cookie system variable. Functions
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. 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. 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:
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 parametersIn 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: <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 functionsA 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.
Calling functions from a formYou 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 you saw in the section Passing data to a program, 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. Further information on functionsHere are a few more things you should be aware of:
Including and running external files
<MvDO> works in two somewhat different ways, depending on whether NAME and VALUE are present. If they are, then the specified function is the only code in the external file that gets executed. Any other Miva Script and HTML code is ignored. If NAME and VALUE are omitted, everything in the external file is executed, and the results of all <MvASSIGN> tags are available to subsequent code in the current file; however, any function definitions in the external file are not available after the <MvDO> has been processed. All system and global variables, and all open databases, are available to the code in the external file.
<MvDO> tags can be nested in the sense that the file filename specified by the <MvDO> can itself contain an <MvDO>. The filename path specified by the "nested" <MvDO> is relative to the location of the file containing that <MvDO> (unless it starts with a forward slash, it which case it is relative to the Miva Script document root directory).
Miva does not interpret server-side includes (SSI). <MvDO> can simulate the effect of an SSI of the type used to include another document in the current document. For example: <!--#include file="external.html"--> This can be replaced by: <MvDO FILE="external.html"> Similarly: <!--#include virtual="/external.html"--> Can be replaced by: <MvDO FILE="/external.html"> Multiple passes through a programIf your program reads user input, you will have to re-submit the document to the browser in order for this data to be processed by the program. In the section on calling functions you saw how this can be done by specifying a function call in a form action. Another technique is to test the value of a variable passed from the form. Here is an example: <body>
<h1>Say anything</h1>
<MvIF EXPR = "{ speak EQ '' }">
<FORM METHOD="POST">
<p><b>I say: <input type="text" name="speak"></b></p>
<input type="submit" name="foo" value="Send">
</FORM>
<MvELSE>
<p><b>You said: <MvEVAL EXPR="{speak}"></b></p>
</MvIF>
</body>
In this example the variable speak controls the flow of the program. The first time the document is opened, speak will have no value, so the condition '{speak EQ ' '}' will be true and the following form will be displayed: If the user enters 'My word' into the text box (which has the name speak) this text will be assigned to the variable speak when the form is submitted. On the next pass through the program, the condition '{speak EQ ' '}' will be false, and the second branch of the <MvIF> will be executed, displaying:
The METHOD attribute of FORM must have the value POST. Since you are not calling a specific function, it is not necessary in this case to specify an ACTION for the FORM. Using external data filesMiva Script provides tags that enable programs to read from and write to external text data files. Any external files that you read or write must be located in your data directory. Data files can have any file extension, though .dat is the most common. Reading from external files - MvIMPORT
In addition to taking input from users via forms, programs can read from data files. Suppose you have a data file called movies.dat that is in the following format: Cape Fear|Martin Scorsese|1991 The Trouble With Harry|Alfred Hitchcock|1955 Dr Strangelove|Stanley Kubrick|1963 Strange Days|Kathryn Bigelow|1995 Clerks|Kevin Smith|1994 This is a simple text file in which each line (sometimes called a record) contains a film title, the director, and the year of release. Each piece of data is called a field; the fields on each line are separated by delimiters--in this example the delimiter is the '|' (vertical bar) character. The <MvIMPORT> tag can be used to read in this file, line by line, and process the data in some way--for example, displaying it in a table. <TABLE>
<TR><TH></TH>
<TH>Title</TH>
<TH>Director</TH>
<TH>Year</TH></TR>
<MvIMPORT
FILE="movies.dat"
FIELDS="title,director,year"
DELIMITER="|">
<TR><TD><MvEVAL EXPR="{recno}">.</TD>
<TD><MvEVAL EXPR="{title}"></TD>
<TD><MvEVAL EXPR="{director}"></TD>
<TD><MvEVAL EXPR="{year}"></TD>
</TR>
</MvIMPORT>
</TABLE>
This code will generate a table, row by row, and fill each row with data from a line of the data file. There are certain parts of the table code that should appear only once, so these are placed outside the <MvIMPORT>...</MvIMPORT> loop. The <TABLE> and </TABLE> tags, and the first table row (<TR>), which displays the table header, are in this category. The attributes of the <MvIMPORT> tag tell it to do the following:
If this code were reading from the sample data shown above, the variables would have the following values after the first line of data was read:
The next line of code inserts these values into a table row by displaying the values of the variables title, director, and year. The automatically-created variable recno will contain the current record (line) number, 1. The table row produced by the resulting HTML code will look something like this:
Since the <MvIMPORT>...</MvIMPORT> block is, in effect, a loop, it will repeat this process for every line of data in the file, stopping when it reads the last line of data. The final table will look like this:
Filtering the inputSometimes you might be interested only in input data that satisfies a particular condition. In the previous example, you might be interested only in movies from 1995. Using the FILTER attribute, you can specify a condition that the input data must meet in order for <MvIMPORT> to pass it on to the program. You could modify the previous <MvIMPORT> as follows: <MvIMPORT
FILE="movies.dat"
FIELDS="title,director,year"
DELIMITER="|"
FILTER="{year EQ '1995'}">
When <MvIMPORT> reads a line of data, it will now check that the value assigned to the variable year equals '1995'. If it doesn't, the data is discarded and <MvIMPORT> reads the next line. No processing is done on the discarded data. The result of this <MvIMPORT> with the data file movies.dat would be:
Terminating the importImporting can be halted explicitly inside an <MvIMPORT> loop using the <MvIMPORTSTOP> tag. The program jumps to the code following the </MvIMPORT> tag, without reading any more input from the data file. Using the record number (recno)The variable recno, containing to the current line number in the file being read, is generated automatically by <MvIMPORT>. A variable named recno is also generated and updated when the program is navigating in a database, and refers to the current record number in that database. If you are using both <MvIMPORT> and a database at the same time, you should disambiguate the two recno variables by using g.recno to refer to the <MvIMPORT> recno, and db_alias.d.recno (where db_alias is the database alias) to refer to the database recno. Nested importsIt is possible in Miva Script to nest <MvIMPORT> tags. For example, you could have an 'outer' <MvIMPORT> that reads in a list of data file names from a 'master' data file, and an 'inner' <MvIMPORT> that, for each iteration of the outer <MvIMPORT>, reads the records of the data file whose name was read. The value of recno always refers to the record number in the current nesting level. Writing to external files - MvEXPORT
The <MvEXPORT> tag writes a single line of data to an external output file. For example: <MvEXPORT
FILE="workers.dat"
FIELDS="name,title,dept,salary"
DELIMITER="##">
This tag will write a line such as the following to the file workers.dat: Frank Flash##V.P. of Silence##Admin##120000 When <MvEXPORT> writes a line of data, it always adds it to the end of the output file, and it always starts on a new line. Unlike <MvIMPORT>, <MvEXPORT> does not loop automatically. If you want to write multiple output lines, you will have to put the <MvEXPORT> tag inside an <MvWHILE> loop. If the data file named by the FILE attribute does not exist, then it is created when the <MvEXPORT> tag is executed. File locking - <MvLOCKFILE>
<MvLOCKFILE> provides a method for the currently running program to indicate to other processes (which could be other running programs, or other instances of the same program) that it has requested exclusive access to a file. It is important to understand that a single <MvLOCKFILE> by itself does not cause the file to be locked: rather, if two processes are using <MvLOCKFILE>, and one process requests a lock, and then the second process requests a lock on the same file, then the second process is prevented from continuing until the first process's lock request is removed. However, if the second process does not issue an <MvLOCKFILE> before attempting to access the file in question, there is nothing to prevent this access from taking place. For this reason, we refer to the action of <MvLOCKFILE> as a lock request, rather than a lock: it is a request to other Miva Script processes that they 'respect' the current process's request for exclusive access. Another way of looking at this is: <MvLOCKFILE> does not interact with any other Miva Script tag, only other <MvLOCKFILE>s. Even though <MvLOCKFILE> does not provide absolute security against a file being accessed by another process, it is still a useful technique: if you code an application properly <MvLOCKFILE> will provide protection against other instances of the same application accessing a file simultaneously. Typically you would not have a lock request in place during the entire execution of your program, as this might unnecessarily block other processes from accessing the file in question. You need to identify blocks of code during whose execution it would be desirable to have a lock request in place. Then you surround the blocks of code with <MvLOCKFILE> and </MvLOCKFILE> tags. For example: <MvLOCKFILE FILE="workers.txt"> <MvEXPORT FILE="workers.txt" ...> </MvLOCKFILE> In this example, the program requests a lock on the text file workers.txt while an <MvEXPORT> is performed. If a lock request exists on a file, and another process requests a lock on that file (with <MvLOCKFILE>), then the second lock request is queued until the first lock request is removed. When the lock request is removed, the second process's lock request becomes the 'primary' one. While the second process is waiting, its execution stops; if the process has to wait a long time, this could cause it to time out. Several lock requests can be queued at once.
Nesting <MvLOCKFILE>sYou can nest two more <MvLOCKFILE>...</MvLOCKFILE> tag pairs if you need to lock two different files at the same time. For example: <MvLOCKFILE FILE="input.dat"> <MvLOCKFILE FILE="output.dat"> ... </MvLOCKFILE> </MvLOCKFILE> The <MvLOCKFILE> and </MvLOCKFILE> tags are paired: the innermost </MvLOCKFILE> removes the lock request created by the innermost <MvLOCKFILE> (in this example, the lock request on output.dat). You should take care to avoid the situation known as a "deadly embrace": this occurs when a process makes a lock request on a file for which the same process already has a lock request in place. For example: <MvLOCKFILE FILE="foo.dat"> ... <MvLOCKFILE FILE="foo.dat"> ... </MvLOCKFILE> ... </MvLOCKFILE> When the second <MvLOCKFILE> is executed, the process stops executing while it waits for the lock request on foo.dat to be removed; however, this will never happen, precisely because the current process, which is also the process that issued the first lock request, is now stopped! The process will wait until it eventually times out.
Database lockingAs indicated in the database sections below, when you are adding (<MvADD>) or updating (<MvUPDATE>) a database record, Miva automatically prevents the same record from being updated by more than one process at the same time. This is true locking: no other Miva Script process can access a record while it is locked. <MvLOCKFILE> is neither required nor desirable in order to provide record-level locking. Other database operations--<MvPACK>, <MvMAKEINDEX>, and <MvREINDEX>--do not perform automatic locking. You may wish to use <MvLOCKFILE> to provide these tags with added data integrity (you should lock both the database and index files in question); however, since each of these tags tend to be time-consuming, we recommend that you use them 'off-line', thereby avoiding both data integrity issues and excessive resource consumption on your server. Communicating with an HTTP server - MvCALL
Requesting a document with <MvCALL>To request a document using <MvCALL>, set the ACTION attribute to the URL of the document that you want to obtain, and set the METHOD attribute to 'GET'. The FIELDS attribute is not required. For example: <MvCALL
ACTION="http://www.your_server.com/company/contact.html"
METHOD="GET">
<MvCALL> retrieves the document as a sequence of tags and text blocks. <MvCALL> passes the document to the program one object at a time; the <MvCALL>...</MvCALL> loop is executed once for each object. Consider the following HTML code: <P>When in <B>Rome</B> do as the <I>Romans</I> do.</p> <MvCALL> will split this code into 11 objects:
Each time <MvCALL> returns an object, it sets the value of the special variable callobjecttype. callobjecttype has the value 'tag' if the object is a start- or end-tag, and 'text' if the object consists of text. Your program can use this value inside the <MvCALL> loop to decide how to process the object. The variable callvalue contains the text or tag object itself. TagsThe variable callobjecttype has the value 'tag' if the object returned by <MvCALL> is a start- or end-tag. If the tag is a start-tag, <MvCALL> then further separates the tag into attribute/value pairs. The following special variables are set for each tag:
Consider the following example: <IMG SRC="donkeys.gif" ALT="The Donkey Farm" HEIGHT="100" WIDTH="200"> <MvCALL> will set the following variables for this 'tag' object:
All values, string and numeric, are returned without quotes. Sometimes an attribute will be specified without an attribute name, as in: <TABLE BORDER> In this case, the attribute name and the attribute value are considered to be the same. In this example, callobjectattribute1 and callobjectvalue1 will each have the value BORDER.
TextThe variable callobjecttype has the value 'text' if the object returned by <MvCALL> consists of text. The variable callvalue will contain the actual string of text and white space.
HeadersWhen it retrieves a document, <MvCALL> also receives HTTP header information sent by the server. This information is stored in the following variables:
Here is an example of header data:
MvCALL examplesThe following code will retrieve and display an HTML page: <MvCALL ACTION="http://..." METHOD="GET">
<MvEVAL EXPR="{callvalue}">
</MvCALL>
This will display the page as if its URL had been accessed directly by the browser, except that any relative links (to images, for example) will not be resolved. One workaround for this is to put a <BASE> tag in the page being accessed, giving its absolute URL. Another is to put the appropriate <BASE> tag in the output stream that Miva sends to the browser: <MvASSIGN NAME="url" VALUE="http://...">
<MvCALL ACTION="&[url];" METHOD="GET">
<MvIF EXPR="{callobjecttype EQ 'tag' AND toupper(callobjectelement) EQ '/HEAD'}">
<MvEVAL EXPR="<BASE HREF='&[url];'>">
</MvIF>
<MvEVAL EXPR="{callvalue}">
</MvCALL>
To display the page in its 'raw' HTML form, use: <PRE>
<MvCALL ACTION="http://..." METHOD="GET">
<MvEVAL EXPR="{encodeentities(callvalue)}">
</MvCALL>
</PRE>
Here is another simple <MvCALL> example: <MvCALL METHOD="GET" ACTION="http://...">
<MvIF EXPR="{ callobjecttype EQ 'tag' }">
<p>Tag name: <MvEVAL EXPR="{callobjectelement}"></p>
<p>Number of attributes: <MvEVAL EXPR="{callobjectnumattributes}"></p>
<MvELSE>
<p>Text: ==<MvEVAL EXPR="{callvalue}">==</p>
</MvIF>
<HR>
</MvCALL>
This program gets objects from the specified URL. If the object is a tag, the tag's name and the number of attributes are displayed. If the object is text, the text is displayed. The output from this program will look like this:
Limitations<MvCALL> does not provide a true HTML, SGML, or XML parser, so it has some limitations :
Nevertheless, <MvCALL> is a useful tool for processing structured documents, particularly those that are valid and well-formed.
Submitting data with <MvCALL>There are two ways to use <MvCALL> to submit data to a CGI program on a server. These are the GET and POST methods, and are used in the same way as with an HTML form. The receiving program must know which method is being used and be set up to process data accordingly.
Using GETTo use the GET method to submit data with <MvCALL>, set the METHOD attribute to 'GET'. The data that is submitted must be appended to the URL specified by ACTION. It is separated from the URL by a '?' character, and consists of a sequence of 'name=value' pairs separated by ampersands, '&'. For example: http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur If the data contains any special characters, such as space, '=', '~', '&', and '+', it must be URL-encoded. The submitted data will be available to the receiving program via the QUERY_STRING CGI environment variable. Here is an example using GET: <MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur"
METHOD="GET">
...
</MvCALL>
Using POSTIf you use the POST method to submit data, the data is not sent to the server appended to the URL, but rather in the HTTP headers. The format in which the data is received is the same as when GET is used. That is, a sequence of 'name=value' pairs separated by ampersands, '&'. Instead of obtaining the data from the QUERY_STRING variable, the program receiving the data must read it from its standard input. To use this method, set the METHOD attribute of <MvCALL> to 'POST'. The FIELDS attribute should contain a list of variables whose names, together with their values, are sent to the URL specified with the ACTION attribute. Here is an example: <MvASSIGN NAME="animal1" VALUE="fish">
<MvASSIGN NAME="animal2" VALUE="dinosaur">
<MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog2"
METHOD="POST"
FIELDS="animal1,animal2">
...
</MvCALL>
Processing the responseSince CGI programs generally send a response back to the client that sent it data, the <MvCALL> loop can and should be prepared to deal with the document that is sent back. For example: <MvCALL
ACTION="http://www.my_isp.com/cgi-bin/prog1?animal1=fish&animal2=dinosaur"
METHOD="GET">
<MvEVAL EXPR="{callvalue}">
</MvCALL>
This very basic code simply displays the document that the CGI program sends back. Calling Miva Script (and other) programs with <MvCALL>You can use <MvCALL> to call another Miva Script program and pass data to it. To do this, use GET or POST as explained in the previous section, and specify a Miva Script program with the ACTION attribute. For example: <MvCOMMENT>Using GET</MvCOMMENT>
<MvCALL
ACTION="http://www.my_isp.com/prog1.mv?animal1=fish&animal2=dinosaur"
METHOD="GET">
...
</MvCALL><MvCOMMENT>Using POST</MvCOMMENT>
<MvASSIGN NAME="animal1" VALUE="fish">
<MvASSIGN NAME="animal2" VALUE="dinosaur">
<MvCALL
ACTION="http://www.my_isp.com/prog2.mv"
METHOD="POST"
FIELDS="animal1,animal2">
...
</MvCALL>
In the two examples above, the Miva Script program that is being called can access the variables animal1 and animal2 with the values provided. <MvCALL> can also call any CGI program (such as a Perl script), using the same constructions; in the ACTION attribute, just substitute the URL of the CGI program being called. With GET, you can also use the value list syntax for passing arguments to a program: <MvCOMMENT>Using GET</MvCOMMENT>
<MvCALL
ACTION="http://www.my_isp.com/prog3.mv?fish+dinosaur"
METHOD="GET">
...
</MvCALL>
In this case, the Miva Script program that is being called can access the submitted values via the arg2 and arg3 variables. Running system commandsMiva adheres to the principle of 'site sandboxing', which means that it will not interfere with the server or other users on the server. For this reason Miva does not allow system commands (such as UNIX shell commands) to be run directly from Miva. If you need to run system commands, you may be able to write a CGI program (using Perl, shell, or another language) that can execute system commands, and use <MvCALL> to call that CGI program. File uploadingMiva supports two forms of file uploading: sending a file from one host to another, and receiving a file from an end-user.
Authenticating the uploadFiles can be uploaded to any CGI script that supports file upload. For security reasons--in order to protect hosts that do not want to receive uploaded files from receiving them--if the script at the receiving end is a Miva Script program, it must contain two user-defined functions: one to validate the upload, and the other to process the uploaded file. If either of these scripts are missing, or have the wrong number of parameters, the upload will fail. Validating the uploadThe recipient script must contain the following function, which validates the upload: <MvFUNCTION NAME="Miva_ValidateFileUpload"
PARAMETERS="field,filename,content_type">
...
<MvFUNCRETURN VALUE="{return_code}">
...
</MvFUNCTION>
This function will be called automatically by the Miva processor (your program does not need an explicit call to this function). It will be called with three arguments, the name of the Miva variable (field) that contains the name of the uploaded file, the filename itself, and the MIME type (content_type) of the file on the uploading server. The actions of this function can be whatever you want, but the function must eventually return one of three values:
How you arrive at this return value is up to you: for example, if you want to upload all files in their entirety, the body of the function could consist of only: <MvFUNCRETURN VALUE="0"> To skip GIF images but upload all other files: <MvIF EXPR="{content_type EQ 'image/gif'}">
<MvFUNCRETURN VALUE="-1">
<MvELSE>
<MvFUNCRETURN VALUE="0">
</MvIF>
To upload only up to 1000 bytes of any file: <MvFUNCRETURN VALUE="1000"> Processing the uploadThe recipient script must contain the following function, which processes the upload: <MvFUNCTION NAME="Miva_ProcessFileUpload"
PARAMETERS="field,filename,status,tempfile,content_type,size">
...
</MvFUNCTION>
This function will be called by the Miva processor with certain information about the file being uploaded (your program does not need an explicit call to this function):
The actions of this function can be whatever you want, but probably the most important thing you would do in this function would be to make a copy of the temporary file (tempfile), since it will be deleted when the function terminates. For example: <MvASSIGN NAME="save_it" VALUE="{frename(tempfile,permfile)}">Sending filesTo send a file to another server, use an <MvCALL> in the following manner: <MvASSIGN NAME="f1" VALUE="file1.txt">
<MvASSIGN NAME="f2" VALUE="file2.htm">
<MvCALL ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
FILES="f1,f2">
The FILES attribute specifies a list of one or more variables whose values are the names of files to be uploaded; these filenames must be relative to your Miva data directory. The METHOD must be POST (or PUT, which will generally be implemented as POST). The files are uploaded to the server specified by ACTION, but the results of the upload process depend on how the specified script (uploadscript.mv in this example) processes the data it receives. If this script is a Miva Script program, it must contain definitions for the two functions Miva_ValidateFileUpload() and Miva_ProcessFileUpload(), described above; both of these functions will be called once for each uploaded file, and can skip the file, upload it in its entirety, or upload it partially, and then can save the file, allow it to be deleted without saving, and perform any other desired processing.
Receiving files from end-usersTo enable users of your script to send files to your server (or another server), use an HTML FORM in the following manner: <FORM ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
ENCTYPE="multipart/form-data">
<INPUT TYPE="FILE" NAME="some_name">
<INPUT TYPE="SUBMIT">
</FORM>
The METHOD must be POST (or PUT, which will generally be implemented as POST), and the ENCTYPE attribute must be set to 'multipart/form-data'. The <INPUT TYPE="FILE"> element creates a form object such as the following: The user browsing a page containing this object can use it to enter or choose a file on the local network. When the form is submitted, the file is uploaded to the server specified by the ACTION, but the results of the upload process depend on how the specified script (uploadscript.mv in this example) processes the data it receives. This script must contain definitions for the two functions Miva_ValidateFileUpload() and Miva_ProcessFileUpload(), described above; both of these functions will be called once for each uploaded file, and can skip the file, upload it in its entirety, or upload it partially, and then can save the file, allow it to be deleted without saving, and perform any other desired processing.
ArraysAn array is a data structure in which many values are associated with the same variable name, but each value has its own 'subscript' or 'index value' to distinguish it from the others. For example, a series of names could be stored in variables name_1, name_2, name_3, and so forth. In this case we could say that the names are stored in an array called names. Data stored in this way is much easier for a program to manage than data stored in completely unrelated variable names. Miva Script does not have built-in support for arrays, but it is easy to simulate arrays by using macros. The array subscripts can be generated by a value referred to by a macro. Here is an example that reads a list of values from a data file and stores each one in a different element of an array: <MvASSIGN name="counter" value="1">
<MvIMPORT
FILE="workers.dat"
FIELDS="worker,amount"
DELIMITER="|">
<MvASSIGN name="person_&[counter];" value="{worker}">
<MvASSIGN name="salary_&[counter];" value="{amount}">
<MvASSIGN name="counter" value="{counter+1}">
</MvIMPORT>
This example actually uses two arrays, one whose variables start with person_, and another whose variables start with salary_. When a line of data is read from the data file, values are stored in the variables worker and amount. The first time a line of data is read, the value of the variable counter is 1. Now remember that macros are evaluated before a line of code is executed, so the first two <MvASSIGN> tags after the <MvIMPORT> effectively become: <MvASSIGN name="person_1" value="{worker}">
<MvASSIGN name="salary_1" value="{amount}">
Then the variables person_1 and salary_1 are assigned the current values of worker and amount, respectively. Next, the value of counter is increased by one. Therefore, the next time through the loop, the variables person_2 and salary_2 are created and assigned values. When all of the data has been read in, two series of variables person_1, person_2,...,person_N and salary_1, salary_2,...,salary_N have been created and assigned values. One advantage of storing data in this way is that elsewhere in the program it would be very easy to implement a loop that reads through the entire array; another is that if you know the array subscript associated with a particular person, it is easy to access both the name and salary values for that person. Sending and receiving emailMiva Script provides tags that can send and receive email. SMTP is used to send mail from any valid mail server, and Miva Script documents can receive email by becoming POP3 clients. Sending mail - <MvSMTP>
Here is an example of sending email with <MvSMTP>: <MvSMTP
TO="les@some_isp.com,janice@some_isp.com"
FROM="royc@my_isp.com"
MAILHOST="my_isp.com"
CC="leanne@some_isp.com,toyah@some_isp.com"
SUBJECT="Weatherfield Alien Abduction Society">
Friends: the next meeting of the Society will be
on April 16, 1998.
</MvSMTP>
A value for TO is mandatory and indicates that the mail is outgoing. TO can contain a single email address or a comma-separated list of email addresses. FROM is mandatory and contains the email address of the person sending the message. MAILHOST is mandatory and must contain the domain name or IP address of your mail host (a host that understands SMTP). If you don't know this value, check with your ISP or system administrator. SUBJECT is optional and can contain text that will be used as the message's Subject line. If no subject is specified, then the text 'no subject' is is used as the default subject. CC is optional and can contain a single email address or a comma-separated list of email addresses. Mail headers, if present, must be placed on the line directly after the <MvSMTP> tag. Whether or not there are mail headers, the line before the message contents must be left blank. Enter the text of your message between the blank line and the </MvSMTP> tag. The message can also be generated by other Miva Script tags between the <MvSMTP> and </MvSMTP> tags; for example, an <MvCALL> tag could be used to obtain a text file. Address formatsMost SMTP hosts are very flexible as to the formats the allow for e-mail addresses (as specified with FROM, TO, and CC). For example, you may wish to specify "real names": <MvSMTP TO="Roy Cropper <royc@my_isp.com>" ...> If you include a name with the address, surround the address with '<' and '>', as in the example. You must not put a comma in the name. Some servers do not allow this form of address, so before you "go live" with a script you should test this format on the server you intend to use. By contrast, some SMTP servers require that addresses be surrounded by '<' and '>'. In all cases, you should perform tests with your server, and ensure that the values you provide for FROM, TO, and CC meet your server's requirements. Mail headersIn addition to ordinary content, mail messages can contain mail headers: for example, Reply-To, Return-Path, and Sender. Mail headers, if present, must be placed on the line directly after the <MvSMTP> tag. Whether or not there are mail headers, the line before the message contents must be left blank. For example: <MvSMTP
TO="les@some_isp.com,janice@some_isp.com"
FROM="royc@my_isp.com"
MAILHOST="my_isp.com"
CC="leanne@some_isp.com,toyah@some_isp.com"
SUBJECT="Weatherfield Alien Abduction Society">
Reply-To: roy.cropper@my_isp.co.uk
Friends: the next meeting of the Society will be
on April 16, 1998.
</MvSMTP>
This adds the Reply-To header to the message. To understand how <MvSMTP> handles headers, you need to understand something about how mail messages are handled generally. The basic situation is that a user uses a program called a mail client to create a mail message, and send it to another program called a mail server, which communicates with the network. Because there are many different implementations of mail clients and mail servers, the specific tasks that each one carries out will differ from program to program. In particular, some mail clients and some mail servers will interpret various mail headers, and some won't. Miva, acting as a mail client when it encounters an <MvSMTP> tag, interprets only the data passed to it with the TO, FROM, CC, and SUBJECT attributes, and generates the appropriate headers and SMTP codes for this data. Any other headers are passed to the mail server unchanged. These then become the responsibility of the server; how they are processed (if at all) depends on the server configuration. For this reason, headers such as Bcc, which require extra processing, are not guaranteed to have the expected effect. You should test with the specified MAILHOST any such headers that you intend to use. Some useful references are: RFC 822 (http://www.sendmail.org/rfc/0822.html), the Standard for Internet Text Messages, for more information on mail headers; RFC 821 (http://www.sendmail.org/rfc/0821.html) for information on SMTP; and RFC 1123 (http://www.sendmail.org/rfc/1123.html) for information on Internet hosting in general. Reading mail - MvPOP
Here is an example of reading mail with <MvPOP>: <MvPOP
MAILHOST="mail.my_isp.com"
LOGIN="my_userid"
PASSWORD="pa55w0rd"
DIRECTORY="mymail">
<p>You received mail from: <MvEVAL EXPR="{messagesender}">.<br>
This mail is about: <MvEVAL EXPR="{messagesubject}">.<br>
This mail was sent on: <MvEVAL EXPR="{messagedate}">.<br>
I stored this mail in the file: <MvEVAL EXPR="{messagebody}">.<br>
You can reply to: <MvEVAL EXPR="{messagereplyto}">.
</p>
</MvPOP>
This code reads incoming email messages belonging to the user my_userid, who has the password pa55w0rd, on the mail server mail.my_isp.com; these messages are stored in a directory called mymail. Note: The storage directory should be specified as a directory relative to the data directory of the owner of the active document if Miva Empresa is running in server-safe (multi-user) mode; it can be a relative or absolute path if Miva Empresa is running in standard mode. When <MvPOP> retrieves an email message, it stores information about the message in several special variables:
Some or all of the first four values in the list may be unavailable if the message header is missing or truncated. Some sample output would be:
If there is more than one incoming message, <MvPOP> will iterate through them and print these fields for each message. Deleting an email messageBy default, <MvPOP> does not remove email messages from the POP3 server. If you want to remove a message, you need to execute an <MvPOPDELETE> tag inside the <MvPOP> loop. This deletes the current email message on the server. The message will still be processed by the application in this iteration of the <MvPOP> loop. Using databasesMiva Script supports two kinds of databases: xbase3 (dBaseIII compatible) databases, which are supported on all platforms, and ODBC databases which are supported only on Microsoft Windows. Miva Script has tags that let you perform database operations, such as: creating, opening, and closing a database; adding, deleting, and updating records; searching for records; and creating and using database indexes. Any database files or database indexes that you use must be located in your data directory. The full Miva database feature set is currently supported only for xbase3 databases. Access to ODBC datasources is currently supported only with Miva Mia.
Using xbase3 databasesWith the exception of <MvOPEN>, <MvSKIP> and <MvGO>, the Miva Script database tags described below are supported only for xbase3 databases. The optional attribute VIEW, available with several database tags, is currently supported only when accessing ODBC databases with <MvSKIP> and <MvGO>. Introduction to databasesMiva xbase3 databases organize data into a simple tabular format that consists of records (which you can think of as the rows of the table) that each have one or (usually) more fields (which you can think of as the columns of the table). Note that when we refer to a 'table' here, we don't mean an HTML table (although it is very easy to extract data from a database an put it in such a table). Here 'table' refers to the ordering of the data--the way that the Miva Script language enables you to manipulate the data. Here is a small example:
This example is from an employee database. Each employee is represented by a record (a row), that has fields for data such as name, title, salary, start date, status, and comments. Summary of database operationsDatabases are flexible enough that it is not really possible to give a simple set of steps for using them. However, here are some database operations that apply to almost every database.
Creating a database - MvCREATE
A database must be created before it can be used. When you create a database, you are just defining its structure; a database file is created on your system, but it doesn't contain any data yet. This step needs to be done only once for each database. Example databaseHere is an example that creates a database; this database will be used in other examples below. <MvCREATE
NAME="worker_db"
DATABASE="hr/dbs/workers.dbf"
FIELDS="employee CHAR(40),
title CHAR(20),
salary NUMBER(7.2),
started DATE,
fulltime BOOL,
comments MEMO">
Identifying the databaseThe NAME attribute specifies an alias for the database. An alias is simply a name that you assign to the database when you open it. Databases are almost always referred to in Miva Script tags using a database alias, rather than the actual physical filename of the database. The same database file can be open twice or more simultaneously with different aliases. The alias in the example above is 'worker_db'. If you want, you can use a different alias for the database the next time you open it. The DATABASE attribute contains the actual filename of the new database to be created, possibly prepended with a directory path. This location is relative to the data directory for the current user. If you are creating the database in a subdirectory of the data directory, you must create the subdirectory first, using the fmkdir built-in function or explicitly through your operating system. You can use any file extension for the database file, but .dbf is recommended. The database file in the example above is hr/dbs/workers.dbf. Defining database fieldsThe FIELDS attribute contains a comma-separated list of field names with their data types and parameters. Database field names can be up to 10 characters in length. Fields can be assigned one of five different data types: CHAR (character), NUMBER, DATE, BOOL (boolean/logical), and MEMO (dynamic length).
The example above creates five fields: two CHAR fields named employee and title with maximum lengths of 40 and 20 characters, respectively; a NUMBER field called salary whose values can have 7 digits before the decimal and 2 after; a DATE field called started; a BOOL field called fulltime; and a MEMO field called comments. Specifying the primary database alias - MvPRIMARY
Accessing fields in a recordWhen you are working with a database, Miva Script maintains the notion of a current record, or of a record pointer that points at the current record. A record can become the current record because you've just created it with <MvADD>, or because you've navigated to it using <MvFIND>, <MvGO>, or <MvSKIP>. Miva Script creates variables that correspond to the fields of the current record in each open database, and it is through these variables that your program can read and write the data in the record. For each database field of type CHAR, NUMBER, BOOL, or MEMO, a variable named db_alias.d.fieldname is created, where db_alias is the name under which the database is aliased, and fieldname is the field name. When a particular record is the current record, the variable db_alias.d.fieldname automatically contains the value of that record's fieldname field. For example, if the database worker_db has a field called title, then the following expression will display the current record's title field: <MvEVAL EXPR="{worker_db.d.title}">
For each field fieldname of type DATE, special variables are created with the following values:
Suppose the database with alias worker_db has a DATE field called started, and the date stored in the started field for the current record is April 16, 1998. <P>Date: <MvEVAL EXPR="{worker_db.d.started_day$'/'$worker_db.d.started_month$'/'$worker_db.started_year}"></P>
<P>Raw date: <MvEVAL EXPR="{worker_db.d.started_raw}"></p>
This code will display: Date: 16/04/1998 Raw date: 19980416 See the section Adding a record to a database for more examples of using database records.
If you are referring to fields of the primary database, you can use d.fieldname instead of the longer form db_alias.d.fieldname. If the primary database does not have a field called fieldname, then the value of d.fieldname will come from the open database that does have a field fieldname and was most recently the primary database (a database becomes the primary database when it is created, opened, or made primary using <MvPRIMARY>). If no open database has the field fieldname, then d.fieldname is undefined. If the variables s.fieldname and l.fieldname do not exist, then the variable fieldname (that is, without a prefix) is equivalent to d.fieldname.
The same variables that you use to display the fields of the current record are also used when you want to update a record with <MvUPDATE> or add a record with <MvADD>. Values for the special variables db_alias.d.totrec (total number of records in the database with alias db_alias) and db_alias.d.recno (current physical record number in the database with alias db_alias) are also set automatically when a database is open. The boolean variable db_alias.d.eof is true if the end of the database with alias db_alias has been reached. When referring to the primary database, d.totrec, d.recno, and d.eof; totrec,recno, and eof (without the prefix) are equivalent to the d. variables if no s. (system) or l. (local) variable with the same name exists.
Opening and closing databasesThe <MvOPEN> and <MvCLOSE> tags are used to open and close databases. Opening a database - MvOPEN
A database must be open before you can use it. When a database is created, it is opened automatically. Usually, however, the script that you used to create the database will be run only once, so if you use other scripts to manipulate the database, you have to explicitly open the database, using the <MvOPEN> tag. A database stays open until the script terminates, or until you close it explicitly with <MvCLOSE>. The next time you use the database, you have to open it again. If the current script makes a call to another script (or even the same script) the database will have to be opened again if operations are to be performed on it. Here is an example: <MvOPEN
NAME="worker_db"
DATABASE="hr/dbs/workers.dbf"
INDEXES="idx1.mvx,idx2.mvx">
When you open a database it becomes the primary database for the program regardless of how many other databases were previously opened or the order in which they were opened. A database becomes the primary database by default if it is the one most recently opened. However, you can specify a new primary database with <MvPRIMARY>. NAME and DATABASE are required. The alias specified by NAME doesn't have to be the same one used when the database was created. You can also have the database open multiple times simultaneously under different aliases, and update it under any of these aliases. The optional INDEXES attribute contains a comma-separated list of index files that will be associated with the database being opened. All indexes are updated records are added or updated, or the database is packed. The first index file in the list will become the main index; it governs the way that the database will be sorted for navigation. If the program will be modifying the database that is being opened, all relevant index files should be loaded so that they will be properly updated (you can also update the indexes at a later time using <MvREINDEX>). If a database is being opened only for reading information, an index is not necessary (unless you are using <MvFIND>), although using one will speed up access. Closing a database alias - MvCLOSE
Adding, updating, and deleting recordsThe following sections explain how to modify the data in a database. Database and index files are locked at the record level automatically when records are added or updated to prevent data corruption (that is, two programs cannot update the same record at the same time). Entire files can be locked using <MvLOCKFILE>. Adding a record to a database - MvADD
Here is an example that adds a record to a database: <MvOPEN
NAME="worker_db"
DATABASE="hr/dbs/workers.dbf"
INDEXES="idx1.mvx,idx2.mvx">
<MvASSIGN NAME="worker_db.d.employee" VALUE="Walter Skinner">
<MvASSIGN NAME="worker_db.d.title" VALUE="Assistant Director">
<MvASSIGN NAME="worker_db.d.salary" VALUE="150000">
<MvADD>
Instead of explicitly assigning values to database fields, <MvADD> obtains values implicitly, from variables whose names are the same as the field names (except possibly for prefixes). In this example, the database has fields called employee, title, and salary (also started, fulltime, and comments, but we're not using those here). The three <MvASSIGN> tags assign values to three variables whose names are of the form db_alias.d.field_name, where db_alias is a database alias ('worker_db' in this case), d is a special prefix standing for 'database', and field_name is the name of a database field. Since 'worker_db' matches the name of the current primary database, and the three field_names match the names of fields in the primary database, <MvADD> stores the three assigned values in the new record. The index files idx1.mvx and idx2.mvx associated with the database are updated when an <MvADD> is executed.
The db_alias and d prefixes are optional for variables whose values are to be stored in the database, provided that the values are to be stored in the primary database. For example, the following two blocks of code would have worked the same as the one in the example above: <MvASSIGN NAME="d.employee" VALUE="Walter Skinner"> <MvASSIGN NAME="d.title" VALUE="Assistant Director"> <MvASSIGN NAME="d.salary" VALUE="150000"> <MvADD> <MvASSIGN NAME="employee" VALUE="Walter Skinner"> <MvASSIGN NAME="title" VALUE="Assistant Director"> <MvASSIGN NAME="salary" VALUE="150000"> <MvADD> Variables of the form d.field_name or just field_name can be used to assign values to be stored in any database. By contrast, values of variables of the form db_alias.d.field_name will be stored only in the database with alias db_alias. The longer form of the variable name is used to make your code more readable and easier to maintain. If you use the db_alias prefix there is no doubt about what the variable is being used for. Date fieldsRecall that for a date field fieldname, Miva Script creates variables fieldname_year, fieldname_month, fieldname_day, and fieldname_raw. fieldname_raw contains the date's value in yyyymmdd format. You can assign a value to a date field in three ways:
(In each case you must follow the variable assignment(s) with <MvADD>.) The following two blocks of code have the same effect (assume that the active database worker_db has a date field called started): <MvASSIGN NAME="worker_db.d.started_year" VALUE="1992"> <MvASSIGN NAME="worker_db.d.started_month" VALUE="12"> <MvASSIGN NAME="worker_db.d.started_day" VALUE="05"> <MvADD> Or: <MvASSIGN NAME="worker_db.d.started_raw" VALUE="19921205"> <MvADD> Dates can also be assigned in time_t format. time_t is the number of seconds elapsed since the beginning of Coordinated Universal Time (C. U. T), at 00:00:00 on January 1, 1970. Miva supplies this value via the time_t and dyn_time_t built-in variables; time_t represents the time the script started running; dyn_time_t is updated dynamically when it is used in the script. The built-in function mktime_t generates a time_t value, given the date, time, and timezone. If you know the time_t value for the date you want to assign, you can assign it to the database variable directly. For example: <MvASSIGN NAME="worker_db.d.started" VALUE="{time_t}">
<MvADD>
(Notice that a value is assigned directly to the started variable.)
Updating records - MvUPDATE
Here is an example that modifies a database record: <MvOPEN
NAME="worker_db"
DATABASE="hr/dbs/workers.dbf"
INDEXES="nameidx.mvx">
<MvFIND VALUE="Skinner">
<MvASSIGN NAME="worker_db.d.title" VALUE="Director"
<MvASSIGN NAME="worker_db.d.salary" VALUE="250000">
<MvUPDATE>
In this example, the database is opened with <MvOPEN> and the desired record is found with <MvFIND>. Then values are assigned to two variables corresponding to the title and salary fields in the worker_db database: worker_db.d.title is set to 'Director' and worker_db.d.salary is set to '250000'. Finally <MvUPDATE> stores these values in the current record. Deleting a record - MvDELETE/MvUNDELETE/MvPACK
Using database indexesWhen records are added to a database, they are simply added at the bottom of the 'logical' table structure. Unless you explicitly added them in a specific order, the records will not be ordered in any way. Often you will want to be able to group or order records according to the values of certain fields (for example, to sort names alphabetically, or group together all employees with the same job title). For this you can create an index: instead of physically reordering the records, a database index changes the way the order appears to various Miva Script database commands. An index performs a logical (rather than physical) reordering of the records in a database. This means that the order of the records in the database file doesn't actually change; however, if an index is open, some of the commands that operate on the database behave as if the ordering had changed: specifically, <MvSKIP> and <MvFIND> (in fact, <MvFIND> requires an index). The reordering is based on the values returned by a key expression that is evaluated when the index is created or updated: these values can be, and often are, the values in a single field, but they can also be the concatenated values in two or more fields, or some other manipulation of the field values. A database can have one or more indexes. You would create more than one index if you wanted to be able to switch indexes to search on different index key expressions. Even though a database can have several indexes open at the same time, only one of these will be the main or controlling index. The main index is the index that is used when you are searching the database. All open indexes are updated automatically and immediately if the contents of the database are changed. In particular, if the indexed field of the current record changes, the record's position in indexed order may change, but the record pointer will continue to point to that record. This has an impact on the results given by the database navigation tags <MvFIND> and <MvSKIP>. If you are opening a database only for searching, there is no need to open more than one index. If you are opening a database for updating, you should open all indexes that you may wish to use at any point with this database, so that they will be correctly updated (they can also be re-generated later). You can open indexes for a database (and make one of them the main index) using the <MvOPEN> and <MvSETINDEX> tags. You should not attempt to modify index files directly, as this is likely to corrupt the index. Creating a database index - MvMAKEINDEX
A key expression is a Miva Script expression that will be evaluated for each record in the database, and the records will be ordered in the index according to the results of these evaluations. A key expression can be any Miva Script expression; except in unusual circumstances, the key expression will be in some way based on field values in the database. A common choice would simply be a variable corresponding to one of the fields in the database. The key expression may not exceed 500 characters in length, and may not evaluate to more than 100 characters. If you have a database aliased as worker_db that has a field called salary, you could create an index that orders the record according to the value of the salary field, as follows: <MvMAKEINDEX
NAME="worker_db"
INDEXFILE="salary.mvx"
EXPR="{worker_db.d.salary}"
Suppose the sequence of records before indexing were:
After indexing, the apparent sequence of records will be:
For each record, the variable worker_db.d.salary is evaluated and the records ordered accordingly.
A variable corresponding to a field in a key expression can be written in the form db_alias.d.fieldname, d.fieldname, or just fieldname. The first form refers only to the database with alias db_alias, and the other two refer to the current primary database. An advantage to using the d.fieldname (or fieldname) form is that if the same physical database is opened under a different alias, the index will still be calculated correctly. However, if you use this form you must ensure that when you're updating the database in question, either (1) it is the primary database, or (2) the primary database does not also have a field called fieldname: if it does, then the value for d.fieldname will come from the current record in the primary database, rather than from the database being updated. It's up to you which form of the variable you choose to use, but in each case you need to take care to avoid unintended results. You can index a database on more than one field by concatenating the values of these fields in the key expression. If you have a database called users that has fields firstname and lastname, you could index on the full name as follows: <MvMAKEINDEX
NAME="users"
INDEXFILE="names.mvx"
EXPR="{users.d.lname $ users.d.fname}">
Here the key expression concatenates the firstname with the last name and the index is built according to the results of these expressions. If two last names are the same they will be subindexed based on the first name. FlagsThe FLAGS attribute lets you supply further instructions for creating the index file.
At the end of an indexing operation, the index file is active and the record pointer is positioned at the top record of the indexed database.
Setting a new main index - MvSETINDEX
<MvOPEN> and <MvMAKEINDEX> will also open listed index files for the specified or primary database. Recreating index files - MvREINDEX
Moving around in a databaseThis section explains several methods for navigating to specific records in a database. See also the section Configuring runtime error handling for information on how to test the results of a database navigation tag. Finding records - MvFIND
<MvOPEN NAME="worker_db" DATABASE="hr/dbs/workers.dbf" INDEXES="names.mvx"> <MvFIND NAME="worker_db" VALUE="Mary"> In this example, if the index file names.mvx contains an index based on the employee field, the <MvFIND> will search for the first record in the database for which the employee name starts with 'Mary'. Since <MvFIND> always finds the first matching record, subsequent calls to <MvFIND> will find the same record again. Therefore, if you want to find all records matching a particular value, you should use other techniques (such as <MvSKIP> in conjunction with an <MvWHILE> loop) to locate the rest of the records in the database that match. The advantage of starting with an <MvFIND> is that you can quickly locate the first such record. Since the database is indexed, you can be certain that other matching records will directly follow this one in indexed order. (<MvSKIP> will skip in indexed order if the database is indexed.) This example uses <MvFIND> to locate the first record in which the name starts with 'Mary', and then uses an <MvWHILE> loop to find the others. <MvCOMMENT>Open the database.</MvOMMENT>
<MvOPEN NAME="worker_db" DATABASE="workers.dbf">
<MvCOMMENT>Create an index based on the employee (employee name) field
</MvCOMMENT>
<MvMAKEINDEX NAME="worker_db" INDEXFILE="names.mvx" EXPR="{d.employee}">
<MvCOMMENT>Find the first 'Mary': MvFIND searches in the index.</MvCOMMENT>
<MvFIND NAME="worker_db" VALUE="Mary">
<MvCOMMENT>Now loop through all the records starting with 'Mary'
by testing that the first four characters of worker_db.d.employee
consist of the string 'Mary'. Since the database is indexed, we
know that all such records are adjacent.</MvCOMMENT>
<MvWHILE
EXPR="{NOT worker_db.d.eof
AND substring(worker_db.d.employee, 1, 4) EQ 'Mary'}">
<P><B><MvEVAL EXPR="{worker_db.d.employee$' - '$worker_db.d.title}"></B><P>
<MvSKIP>
</MvWHILE>
Interaction between indexing and navigationAll open indexes are updated automatically and immediately if the contents of the database are changed. In particular, if the indexed field of the current record changes, the record's position in indexed order may change, but the record pointer will continue to point to that record. This has an impact on the results given by <MvFIND> and <MvSKIP>. Suppose a database index contains the following entries, corresponding to the database's name field: Aardvark Dog Giraffe Zebra Consider the following code: <MvFIND VALUE="Dog"> <MvSKIP> <MvEVAL EXPR="db_alias.d.name"> This will display the value 'Giraffe', since the <MvSKIP> skips to the record following 'Dog' in the index. Now let's see what happens if a record is changed: <MvFIND VALUE="Dog"> <MvASSIGN NAME="db_alias.d.name" VALUE="Octopus"> <MvUPDATE> <MvSKIP> <MvEVAL EXPR="db_alias.d.name"> This will display the value 'Zebra'. Remember that when the name field of the 'Dog' record is changed, the index is immediately updated, as follows: Aardvark Giraffe Octopus Zebra However, the record pointer still points to the same record, even though that record is at a different position in the index. Since the <MvSKIP> skips to the record following the current record ('Octopus') in the index, it now skips to the 'Zebra' record. Filtering records - MvFILTER
If you want to find a series of records that all match a certain criterion, you have two basic options:
Here is a small example that illustrates the use of <MvFILTER>. Suppose the database contains the following records, in indexed order, ordered by the value of the salary field:
If <MvFIND VALUE="15000"> is executed, it will move the record pointer to the 'Novak' record. Now apply a filter: <MvFILTER FILTER="{'Washer' CIN db_alias.d.title}">
All of the records that do not satisfy the filter condition ("Title contains 'Washer'") will become 'invisible' (even though they're still in the database, and in the same locations). The database now effectively looks like:
Run the <MvFIND> again: <MvFIND VALUE="15000"> Now the record pointer will be at the 'Maloney' record. Since the 'Novak' record does not match the filter condition, it is invisible to <MvFIND>. This example uses an indexed database, but <MvFILTER> itself can be used with indexed or un-indexed databases.
Moving to a specific record number - MvGOSummary
Skipping to a record - MvSKIP
Obtaining a database's structure - MvREVEALSTRUCTURE
<MvREVEALSTRUCTURE> creates a new database with information about the open source database (db_alias). The records in this database correspond to the field definitions used in the <MvCREATE> tag that created the source database; there will be one record for each field definition for the source database. <MvREVEALSTRUCTURE> does not open this new database. If you want to access information in the new "MvREVEALSTRUCTURE" database, use <MvOPEN> to open it. Each record will contain the following fields:
Accessing ODBC datasourcesMiva Script access to ODBC datasources is currently supported only with Miva Mia. Connecting to an ODBC datasource
Running SQL queriesMiva Script enables you to run SQL queries with ODBC datasources. SQL queries fall into two categories: those that return results and those that don't. Miva Script treats these two cases differently.
For example: <MvQUERY
NAME="my_db"
QUERY = "create table Sample
(Sample_ID integer,
Sample_Name char( 100 ) )">
SQL queries that return results are handled by first opening a view. A view is like a 'virtual database' or snapshot of a subset of a database (or perhaps the entire database) as retrieved by a particular SQL query. Subsequent SQL queries refer to the view.
Here is an example of opening a view: <MvOPENVIEW
NAME="my_dbs"
VIEW="sampleview"
QUERY="select * from Sample">
The results of applying the query 'select * from Sample' are assigned the name 'sampleview'. Once you have opened a view, you can use the familiar <MvSKIP> and <MvGO> tags to navigate through the results. For example: <MvSKIP VIEW="sampleview" ROWS="1"> <MvGO VIEW="sampleview" ROW="top"> The variable eof will be true when the end of the view has been reached, and recno will indicate the current position in the view. totrec and deleted, available for regular (xbase3) Miva databases, are not supported with ODBC datasources. When you are done with a view, close it using <MvCLOSEVIEW>: <MvCLOSEVIEW VIEW="sampleview"> The following tags allow the optional VIEW attribute, but currently only <MvGO> and <MvSKIP> can be used with views:
Internet commerce - <MvCOMMERCE>
Commerce Library Exported FunctionsA commerce library communicates with a Miva Script application through the Miva Engine. When the Miva Engine encounters the <MvCOMMERCE> tag in a Miva Script application, it consults its list of registered commerce libraries. If a matching commerce library is found, the Miva Engine loads the corresponding DLL. To develop a commerce library for a Miva Script application, the DLL must export the following four functions:
miva_commerce_initThis function is called when the Miva Engine encounters a <MvCOMMERCE> block. Its purpose is to initialize any data that will be used inside the <MvCOMMERCE> block. The DLL can store any application-specific values in the "data" parameter. This parameter is passed to the other exported functions.Syntax Miva_Commerce_Status miva_commerce_init ( Miva_Context context,
void **data,
const char *method,
const char *action,
Miva_VariableList input,
Miva_VariableTree output );
Parameters
Return Value
miva_commerce_loopWhen miva_commerce_init returns MIVA_COMMERCE_OK, the Miva Engine calls the miva_commerce_loop function. This function is called once per iteration of a <MvCOMMERCE> block. The parameter ìiterationî indicates the number of times that miva_commerce_loop has been called. Syntax Miva_Commerce_Status miva_commerce_loop ( Miva_Context context,
void **data,
const char *method,
const char *action,
Miva_VariableList input,
Miva_VariableTree output,
int iteration ); Parameters
The action that the Miva Engine takes is dependent on the return value of the miva_commerce_loop.
miva_commerce_cleanupWhenever the Miva Engine has completed using the commerce library, regardless of the return value, it calls miva_commerce_cleanup.Syntax void miva_commerce_cleanup (
Miva_Context context,
void **data,
const char *method,
const char *action,
Miva_VariableList input ); Parameters
Return Value No return value.miva_commerce_errorIf either miva_commerce_init or miva_commerce_loop returns MIVA_COMMERCE_ERROR, the Miva Engine calls miva_commerce_error to receive a description of the error. It makes this call prior to calling miva_commerce_cleanup. This function is called by the Miva Engine to receive a description of an error. It is called prior to calling miva_commerce_cleanup.Syntax const char *miva_commerce_error (
Miva_Context context,
void **data,
const char *method,
const char *action,
Miva_VariableList input );
Parameters
Return Value The text for the error is returned.Using UPS Quick Cost<MvCOMMERCE> supports the 'UPSCost' METHOD. This enables your program to submit information about a shipment (weight, origin, destination, etc.) to UPS's Quick Cost calculator and receive back the shipping cost and other information. <MvCOMMERCE> provides a convenient way to do pre- and post-processing of UPS shipping information without having to prepare your own CGI scripts to do so. UPS's documentation on Quick Cost is available from http://www.ups.com/tools/tools.html.
The basic format of <MvCOMMERCE> is as follows: <MvCOMMERCE
ACTION="http://www.ups.com/using/services/rave/qcostcgi.cgi"
METHOD="UPSCost"
FIELDS="var1, var2,...">
The values of ACTION and METHOD must be exactly as indicated. The value of the FIELDS attribute is a series of input variables giving information about the shipment. These variables will generally get their values from a form in your document. There are specific variable names (listed below) that must be used; these variables are case-sensitive. To set up UPS processing, follow these steps:
UPS input variablesThis list gives the input variables that you can use in a form and pass to the Quick Cost calculator using the FIELDS attribute. The Value column describes the types of values that each variable must be given in the form. Required variables are in red. Contact UPS or consult their online documentation for detailed definitions and service descriptions.
Return FieldsThe following fileds are returned inside the <MvCOMMERCE>...</MvCOMMERCE>: <MvCOMMERCE
METHOD = "UPSRSS"
ACTION = "http://www.ups.com/using/services/rave/qcost_dss.cgi"
FIELDS = "{ l.fields }">
Returned Fields ExampleThe file http://www.miva.com/products/engine/mia/templates/frame-ups.html gives an example of using UPSCost. Here is a shorter example that uses only required fields. <HTML>
<HEAD><TITLE>UPS Cost Calculator</TITLE></HEAD>
<BODY BGCOLOR = "#ffffff">
<MvIF EXPR = "{ g.AcceptUPSLicenseAgreement EQ 'yes' }">
<MvCOMMENT> This branch is expected if the form has been submitted.</MvCOMMENT>
<TABLE BORDER = 0 WIDTH = "100%">
<TR><TD>
<B>Product</B>
</TD><TD WIDTH = "100%">
<B>Name</B>
</TD><TD>
<B>Price</B>
</TD></TR>
<TR><TD COLSPAN = 3>
<HR>
</TD></TR>
<MIVA MvCOMMERCE_Error = "nonfatal, nodisplay">
<MvCOMMERCE METHOD = "UPSRSS"
ACTION = "http://www.ups.com/using/services/rave/qcost_dss.cgi"
FIELDS ="AcceptUPSLicenseAgreement,
ActionCode,
ServiceLevelCode,
RateChart,
ShipperPostalCode,
ConsigneePostalCode,
ConsigneeCountry,
PackageActualWeight,
ResidentialInd,
PackagingType">
<MvIF EXPR = "{ s.ReturnCode NE '0000' }">
<MvASSIGN NAME = "g.Error" VALUE = "{ s.MessageText }">
<MvCOMMERCESTOP>
<MvELSE>
<TR><TD>
<MvEVAL EXPR = "{ s.ServiceLevelCode }">
</TD><TD>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '1DM' }">
Next Day Early AM
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '1DA' }">
Next Day Air
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '1DAPI' }">
Next Day Air Intra (Puerto Rico)
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '1DP' }">
Next Day Air Saver
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '2DM' }">
2nd Day Air AM
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '2DA' }">
2nd Day Air
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ '3DS' }">
3 Day Select
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ 'GND' }">
Ground
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ 'STD' }">
Canada Standard
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ 'XPR' }">
Worldwide Express
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ 'XDM' }">
Worldwide Express Plus
</MvIF>
<MvIF EXPR = "{ s.ServiceLevelCode EQ 'XPD' }">
Worldwide Expedited
</MvIF>
</TD><TD>
<MvEVAL EXPR = "{ s.TotalCharge }">
</TD></TR>
</MvIF>
</MvCOMMERCE>
</TABLE>
<MvIF EXPR = "{ MvCOMMERCE_Error }">
<P><B><MvEVAL EXPR = "{ MvCOMMERCE_Error }"></B></P>
<MvELSE>
<MvIF EXPR = "{ g.Error }">
<P><B><MvEVAL EXPR = "{ g.Error }"></B></P>
</MvIF>
</MvIF>
<P><A HREF = "&[s.documenturl];">Calculate shipping for another package.</A></P>
<MvELSE>
<FORM METHOD = "post" ACTION = "&[s.documenturl];">
<TABLE BORDER = 0>
<TR><TD>
</TD><TD>
<B>AcceptUPSLicenseAgreement</B>
<INPUT TYPE = "checkbox" NAME = "AcceptUPSLicenseAgreement" VALUE = "yes" CHECKED>
</TD></TR>
<TR><TD>
<B>ActionCode:</B>
</TD><TD>
<INPUT TYPE = "radio" NAME = "ActionCode" VALUE = 4 CHECKED> All Services<BR>
<INPUT TYPE = "radio" NAME = "ActionCode" VALUE = 3> Specified Service Only<BR>
</TD></TR>
<TR><TD>
<B>ServiceLevelCode:</B>
</TD><TD>
<SELECT NAME = "ServiceLevelCode">
<OPTION VALUE = "1DM">Next Day Early AM
<OPTION VALUE = "1DA">Next Day Air
<OPTION VALUE = "1DAPI">Next Day Air Intra (Puerto Rico)
<OPTION VALUE = "1DP">Next Day Air Saver
<OPTION VALUE = "2DM">2nd Day Air AM
<OPTION VALUE = "2DA">2nd Day Air
<OPTION VALUE = "3DS">3 Day Select
<OPTION VALUE = "GND">Ground
<OPTION VALUE = "STD">Canada Standard
<OPTION VALUE = "XPR">Worldwide Express
<OPTION VALUE = "XDM">Worldwide Express Plus
<OPTION VALUE = "XPD">Worldwide Expedited
</SELECT>
</TD></TR>
<TR><TD>
<B>RateChart:</B>
</TD><TD>
<SELECT NAME = "RateChart">
<OPTION VALUE = "Customer Counter" SELECTED>Customer Counter</OPTION>
<OPTION VALUE = "Letter Center">Letter Center</OPTION>
<OPTION VALUE = "On Call Air">On Call Air</OPTION>
<OPTION VALUE = "One Time Pickup">One Time Pickup</OPTION>
<OPTION VALUE = "Regular Daily Pickup">Regular Daily Pickup</OPTION>
</SELECT>
</TD></TR>
<TR><TD>
<B>ShipperPostalCode:</B>
</TD><TD>
<INPUT TYPE = "text" NAME = "ShipperPostalCode" SIZE = 10 VALUE = "92117">
</TD></TR>
<TR><TD ALIGN = "left">
<B>ConsigneePostalCode:</B>
</TD><TD ALIGN ="left">
<INPUT TYPE = "text" NAME = "ConsigneePostalCode" SIZE = 10 VALUE = "44145">
</TD></TR>
<TR><TD ALIGN = "left">
<B>ConsigneeCountry:</B>
</TD><TD ALIGN = "left">
<INPUT TYPE = "text" NAME = "ConsigneeCountry" SIZE = 4 VALUE = "US">
</TD></TR>
<TR><TD ALIGN = "left">
<B>PackageActualWeight:</B>
</TD><TD ALIGN = "left">
<INPUT TYPE = "text" NAME = "PackageActualWeight" SIZE = 10 VALUE = "5">
</TD></TR>
<TR><TD>
<B>ResidentialInd:</B>
</TD><TD ALIGN = "left">
<SELECT NAME = "ResidentialInd">
<OPTION VALUE = "0" SELECTED>Commercial</OPTION>
<OPTION VALUE = "1">Residential</OPTION>
</SELECT>
</TD></TR>
<TR><TD>
<B>PackagingType:</B>
</TD><TD ALIGN = "left">
<SELECT NAME = "PackagingType">
<OPTION VALUE = "00" SELECTED>Shipper Supplied Packaging</OPTION>
<OPTION VALUE = "01">UPS Letter Envelope</OPTION>
<OPTION VALUE = "03">UPS Tube</OPTION>
<OPTION VALUE = "21">UPS Express Box</OPTION>
<OPTION VALUE = "24">International UPS 25KG Box</OPTION>
<OPTION VALUE = "25">International UPS 10KG Box</OPTION>
</SELECT>
</TD></TR>
<TR><TD>
</TD><TD ALIGN = "left">
<INPUT TYPE = "submit" VALUE = "Calculate">
</TD></TR>
</TABLE>
</FORM>
</MvIF>
</BODY>
</HTML>
Using CyberSource ICSThe <MvCOMMERCE> tag provides an interface to CyberSource Corporation's Internet Commerce Services (ICS). ICS is a collection of services that allow you to conduct reliable, safe, and secure transactions on the Internet. Each service is available individually; you subscribe only to those services you require. The sections that follow contain outlines of ICS, the preparations you have to make to become ICS-enabled, and setting up ICS processing in Miva Script programs. Full ICS documentation is available at http://www.miva.com/cybersource. Many of the links below point to documents at that location. ICS overviewThe process starts when an end user places an order on your Web site through their web browser. Your Miva Script applications then request the appropriate services from ICS. To use ICS, you subscribe to the services you need to conduct business from your electronic storefront. To use these services as an ICS subscriber using Miva Empresa, you set up your system and build the scripts that allow you to transmit information to, and receive and integrate information from, CyberSource's ICS servers. This is done by using the <MvCOMMERCE> tag to send a Simple Commerce Messaging Protocol (SCMP) message to an ICS server. The scripts can be implemented on any web server that is equipped with Miva Empresa. SCMP specifies name/value pairs for specific CyberSource services and wraps this sensitive transaction information in an RSA encrypted envelope. The message is sent to CyberSource where CyberSource performs the services and returns the results back to you. Becoming ICS-enabledBefore you can develop scripts that access ICS, several preparations must be made. Most importantly:
Setting up ICS-processing scriptsThe steps for setting up ICS processing in your scripts are as follows:
Setting up the <MvCOMMERCE> tagTo request an ICS service, you build an SCMP message with the <MvCOMMERCE> tag. Each service has its own detailed requirements, but you will request all services using the same general approach. The attributes of <MvCOMMERCE> are set as follows:
Each of the components of FIELDS is a Miva Script variable. These variables specify four types of information. Merchant identificationThe ics_merchant variable contains the name of your company's encryption key. Services requestedThe ics_svcs variable contains a comma-separated list of strings that specify the services desired for the order. For example: <MvASSIGN NAME="ics_svcs" VALUE="ics_preapp,ics_bill"> ics_preapp and ics_bill are services. You can choose any or all of the following services (for details, see SCMP and ICS Services Reference):
For best results, include all services for a single order in a single message. The ICS server will pass some information among the services that you would otherwise have to provide. The order of the services is not important if you are requesting them simultaneously. Service-specific fieldsEach service requires that certain fields be present in the SCMP message. These correspond to Miva Script variables included in the FIELDS attribute of <MvCOMMERCE>. Fields for each service are described in SCMP and ICS Services Reference. These variables must be assigned their values somewhere in your program before the <MvCOMMERCE> tag is executed; typically, these variables will get their values from an HTML form. If more than one service uses the same fields (for example, several
services use the fields Product descriptionsThe variables offer0, offer1, offer2, ..., offerN contain a product description (digital offer) or each product in the current order. Product descriptions consist of a string of name:value pairs, where the name and value are separated by a colon (:), and the pairs are separated by a caret (^) character. You can include as many product descriptions as you need. This example defines two digital offers:
<MvASSIGN NAME="offer0"
VALUE="{'offerid:1^productname:Miva Engine^' $
'productsku:mivaeng^producttype:electronic^' $
'price:495.00^quantity:1'}">
<MvASSIGN NAME="offer1"
VALUE="{'offerid:2^productname:Miva Merchant^' $'productsku:kclic^producttype:electronic^' $
'price:99.00^quantity:1'}">Using CyberCash CashRegisterMiva Script provides an interface to the CyberCash CashRegister API, which supports a variety of e-commerce services. The sections that follow contain an overview of the available operations and how to access them from Miva Script. See the CashRegister Service: Development Guide from CyberCash at http://www.cybercash.com/cybercash/merchants/docs/dev.pdf For complete CashRegister support documantation, visit http://www.cybercash.com/cybercash/merchants/support/doclib.html.
Getting startedBefore you can use CyberCash services, you must do the following:
Calling CyberCashThe basic format of a call to CyberCash is as follows: <MvCOMMERCE
ACTION="http://cr.cybercash.com/"
METHOD="CyberCash"
FIELDS="cybercash-id,operation,[operation-specific-input-fields]">
...
</MvCOMMERCE>
cybercash-id contains your CyberCash merchant ID. operation contains a string describing the CyberCash operation that is being requested (this string is referred to as a 'message'). Each service has a number of input variables that should be included in the FIELDS attribute. CyberCash will return a number of output variables. Miva Script can process these variables in the <MvCOMMERCE>...</MvCOMMERCE> block. If an operation returns multiple sets of results, <MvCOMMERCE> will loop once for each set.
CyberCash operationsTo specify a CyberCash operation with <MvCOMMERCE>, set the cybercash-id variable to the name of the operation, as a literal string. For example: <MvASSIGN NAME="cybercash-id" VALUE="mauthonly"> There are three kinds of operations: those that implement a particular commerce transaction; those that query a database of transactions; and batch operations that allow several transactions or queries to be submitted at once. Here are a selection of operations:
Input variablesEach operation has a specific set of input variables associated with it. These variables must appear in the FIELDS attribute of the <MvCOMMERCE> tag.
Output variablesFor each operation, CyberCash returns a specific set of output variables. These variables are available inside the <MvCOMMERCE> loop. These variables are described in the sections documenting each operation, in Appendix B of the CashRegister Service: Development Guide. Some common output variables for transactions are:
Formatting strings - FMT operator
Miva Script provides the FMT operator to format strings. For example, you may have a value of which you want to display only the first four characters: <MvASSIGN name="tex" value="t56hkl0p">
<MvEVAL EXPR="{tex FMT '4.'}">
The FMT expression contains a value (the variable tex) and a pattern, the string '4.'. FMT tries to match the pattern to the characters in the value of tex, starting at the leftmost character. The pattern in this example is a very simple one, and simply matches the first four characters, no matter what they are. The result of the expression will be the characters 't56h'. Formatting patterns can contain the following components:
Unlike patterns in some other programming languages, the whole pattern does not have to match in order to for it to have an effect. Miva Script matches as much of the pattern as it can, displays the text that was matched, and discards the rest. FMT Patterns and Modifiers
Any modifiers can be preceded by a number, which causes the modifier to try to match the specified number of characters. A special case is 0, which means "Match this pattern for as long as you can." Here are some more examples: {'HoTMetaL' FMT 'aAa'}
This displays hOt: the pattern matches three characters, the first and third to be displayed in lowercase and the second displayed in uppercase. {'HoTMetaL' FMT '8a'}
This displays hotmetal: the pattern matches eight characters, and displays them in lowercase. {'HoTMetaL' FMT '0a'}
This also displays hotmetal, but unlike the previous pattern, it will display the whole string in lowercase even if it has more than eight characters. {'HoTM3taL' FMT '8a'}
Displays hotm; this pattern could match up to eight letters, but it has to stop after four characters because a number is present. Try to understand the following patterns:
Any of the pattern modifiers may also be preceded by an exclamation point, to invert the meaning of the format. If the pattern contains a number, the '!' must come before the number.
Here are some examples: {'HoTM3taL' FMT '!0#'}
This will display HoTM; the pattern matches as many non-numeric characters as it can. {'HoTM3taL' FMT '!0#!a'}
This will display HoTM3; the pattern matches as many non-numeric characters as it can, followed by a single non-letter. {'HoTM3taL' FMT '3.!2.0.'}
This will display HoTtaL; the pattern matches 3 characters of any type, then matches and discards two characters of any type, then matches as many characters of any type as it can. If you enclose two or more modifiers in square brackets, '[' and ']', the pattern thus created will match any character that any of the modifiers match. The most common example of this is '[aA]', which will match an uppercase or lowercase letter and display it unmodified. Here is another example: {'HOTM3Tal' FMT '0[A#]'}
This will display HOTM3T. In addition to displaying characters, a formatting pattern can also insert new characters. The expression &digits; with the ASCII code digits (where digits can be up to three characters). A frequent application of this is inserting currency symbols in numbers. For example: {'15000' FMT '3#&36;2#'}
{'100' FMT '&163;0#'
These expressions will display 150$00 and £100 respectively. The ASCII code for '$' is 36 and the ASCII code for '£' is 163. The '&digits;' expression cannot insert a character at the end of a string. On technique for working around this is to temporarily add a character to the string: {('69' $ 'x') FMT '2.&36;'}
This will display 69$. Numbers such as monetary amounts, telephone numbers, credit card numbers and dates are often displayed with separators in order to improve readability. For example, in the U.S. and in English Canada monetary amounts are usually displayed with a comma between every three digits. The FMT operator supports a notation for specifying such separators. Here is an example: <MvEVAL EXPR="{'80550998' FMT '3+,0#'}">
This displays 80,550,998 The characters '3+,' in the pattern above cause FMT to insert the commas. In general, the notation n+c, where n is a number and c is a character means: "Insert character c every n characters, going from right to left." Formatting U.S./English Canadian monetary valuesCombining format patterns specifically for displaying numbers as dollars and cents according to the conventions used in the U.S. and in English Canada is easily accomplished using FMT. Example Code:<MvASSIGN NAME="usmoneyfmt" VALUE="&36;3+,0#.2P">
<MvASSIGN NAME="price" VALUE="569812.3">
<MvEVAL EXPR="{price FMT usmoneyfmt}">
This displays $569,812.30 The format expression above is interpreted as follows:
If your site administrator has installed the format pattern usmoneyfmt into your system's site variables file, the pattern can be used as a variable in any Miva Script program. System variablesSystem variables are automatically initialized when a Miva Script program begins execution. There are two types of system variables: static and dynamic. A static system variable has its value set only when the script begins execution, and dynamic system variables have their values set each time they are used in an expression. All of the time-related variables (except for dyn_time_remaining and globaltimeout) have both static and dynamic versions: the dynamic variables start with the dyn_ prefix. With the exception of recno, all other system variables are static. Time variables
CGI, HTTP, and other variablesAll available CGI environment variables are automatically converted into static Miva Script system variables upon start-up. All HTTP headers are saved in environment variables and therefore are also converted to Miva Script static variables. The availability of environment variables depends on the server software; the availability of HTTP headers also depends on the browser; therefore, not all variables listed here are guaranteed to be available in all circumstances. For more information on HTTP headers and environment variables, consult a CGI reference and/or your server documentation. One reference that we recommend is The HTML 4.0 Sourcebook (http://www.wiley.com/compbooks/graham/html4ed/).
In the CGI version of Miva Empresa, all available HTTP headers and CGI variables (except for TERMCAP, MAIL, LOGNAME, and PATH) are accessible. In the NSAPI version, a selection of variables and headers (listed below) are accessible. With Miva Mia, all available headers are accessible, as are the variables remote_addr, remote_host, request_method, server_name, server_port, and server_protocol. The list below contains many of the variables that you may encounter. If the browser and/or server software support other variables, they will be inherited by Miva Script where possible. The following key is used here to summarize the accessibility of system variables:
For example, E: C,N means that the variable in question is inherited from the environment and is accessible in the CGI and NSAPI versions of Miva Empresa.
Miva Script also allows site administrators to define their own system variables. Check with your administrator to find out whether any have been added to your site.
Built-in functionsMiva 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 any expression: <MvEVAL EXPR="{fdelete(filename $ '.dat')}">
...
<MvIF EXPR="{asciivalue(char) GT 32}">Time functionsMost 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 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)}">
Text string functionsNote: 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 functionsThese 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.
Other string functions
Numerical functions
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||