- The Miva Script tags (commands) are executed, and replaced by
the results of the execution, which is generally a mixture of
HTML tags and text (there may also be input to and output from
external files).
- The pre-processed document, consisting of the original HTML
tags and text, together with the tags and text generated by Miva
Empresa or Miva Mia, is served to the browser and displayed.
Miva 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.
If 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
If 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 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.
This 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:
A simple Miva Script program
The answer is: 13.
|
Even though this program is simple, it illustrates several important
features of Miva Script programs:
- Miva Script tags can be mixed freely with regular HTML tags.
- Variables: the two <MvASSIGN>
tags assign values to variables.
- Expressions: {var1 + var2} is an expression that adds
together the values of two variables.
- Evaluation: the <MvEVAL> tag evaluates the EXPR (expression)
and displays the result.
These features are explained further in the sections that follow.
All 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.
Most 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 tags
Miva 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.
A 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. -->
A 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:
- Assigning a variable name with a value using the Miva Script
<MvASSIGN> tag.
- Assigning a variable name by way of a standard input field from
an HTML form.
To display the value of a variable, use the <MvEVAL>
tag or a macro:
<MvEVAL EXPR="{var}">
&[var];
Summary
<MvASSIGN
NAME="var"
VALUE="{expression}|literal">
<MvASSIGN> assigns the variable var the value
given by expression or literal. <MvASSIGN>
is an empty tag.
|
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.
|
|
Note: <MvASSIGN> should be used instead of the
deprecated tag <MvLET>. Miva Script supports this tag
to maintain compatibility with older scripts, but it should
not be used for new coding. <MvLET> is not XML-compliant
and will cause problems if the code is validated or edited
with an XML-compliant editor. <MvLET> also cannot use
an expression to represent the name of the variable being
assigned (by contrast, <MvASSIGN>'s NAME attribute
can have an expression as its value). |
|
A 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.
|
|
Note: Variables assigned in HTML forms are not available
to a program until the form has been submitted. |
|
|
|
Note: An 'image submit' button (<INPUT TYPE="IMAGE">
called name is represented by two Miva Script variables:
name.x and name.y will contain the X and Y coordinates
of the point that was clicked on when the form was submitted. |
|
|
|
Note: If a drop-down list (SELECT tag) has more than
one option selected, the value of the variable corresponding
to the list will be the value of the last selected
option in the list. |
|
See the section Multiple passes through a
program for more information on using variables set in forms.
The 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:
- Local: if a variable is created with the prefix local
or l (for example, local.age and l.age),
and is used inside a function (an <MvFUNCTION>...</MvFUNCTION>
block), its scope is only inside that function.
- Database: the scope a variable whose
name is of the form dbname.database.var or dbname.d.var
is the database named dbname and commands that act on that
database.
- System: Whenever a built-in system variable or a variable that
is generated by an <MvSMTP>, <MvPOP>,
<MvWHILE>, or <MvCALL>
loop is named, use the prefix convention system.varname
or s.varname.
- Global: if a variable is created with the prefix global
or g (for example, global.age and g.age),
it is a global variable--its scope is the entire program.
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 Miva pre-processor checks if a system variable s.var
or system.var exists and has scope in the current location.
If so, then var is interpreted as referring to that variable.
- If a local variable l.var or local.var exists
and has scope in the current location, then var is interpreted
as referring to that variable.
- If a database variable d.var or database.var exists
and has scope in the current location, then var is interpreted
as referring to that variable.
- If a global variable g.var, global.var, or var
exists then var is interpreted as referring to that variable.
- If no variable var (with any prefix) exists, then var
is created as a global variable.
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'.
|
|
Note: For xBase3 databases, use <MvREVEALSTRUCTURE>
|
|
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:
- Assign new1 the value 10.
- As expected, evaluating new1 displays '10'.
- Since new1 was used for the first time without a prefix,
it is a global variable and therefore g.new1 also evaluates
to '10'.
- Call the function f1().
- Since new1 is global, it is available inside the function
block and (currently) has the same value, 10.
- Assign a new value, 20, to new1.
- Evaluating g.new1 gives '20', indicating that the previous
assignment to new1 still referred to the global variable.
- Create a local variable l.new1 and assign it the value
30.
- Evaluating new1 now displays '30'; since a local new1
now exists, new1 without a prefix now refers to that version
of the variable.
- The global variable new1 is still available, but you
have to use the g. prefix to access it.
- Assign the value 40 to new1.
- Evaluating l.new1 displays '40', indicating that the
previous assignment referred to the local version.
- g.new1 (the global variable) still has the value '20'
- Now the function has terminated; since the local version of
new1 has no scope here, evaluating new1 (without
a prefix) now refers to the global variable new1 again.
It still has the last value assigned to the global variable, on
line F.
|
|
Note: Variables used in documents in a frameset document
are local to the frame in which they are used. |
|
System 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.
An 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:
- They can create a new value.
- They can be evaluated for their logical "truthfulness".
Any expression that is equal to '0' (zero) or a null string is
considered false. All others are considered true. True is often
represented by '1' (one).
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:
- Variables (age, name, x, y, z)
- Numbers (1, 17)
- Literal text ('a')
- Arithmetical operators (+, *, /)
- A numerical comparison operator (GE--"greater than or equal
to")
- A string (text) comparison operator (IN--"is contained
in")
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:
- If an operator contains characters that can also occur in a
variable name, then it must be separated from the other components
by one or more spaces: {n POW 2} cannot be written as
{nPOW2}, but {a + b} and {a+b} are
equivalent (since '+' cannot be a character in a variable name).
- Spaces inside literal strings are significant.
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).
|
|
Note: An expression consisting of a literal number,
for example, {149.99}, evaluates to that number. |
|
Since 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:
- Use single quotes instead
- Use the built-in function asciichar()
to represent the double quotes
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 characters
You 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.'}">
Summary
<MvEVAL EXPR="{expression}">
<MvEVAL> evaluates and displays the value of expression.
<MvEVAL> is an empty tag.
|
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.
An 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:
These operators are used with numbers or numeric expressions.
Miva Script also supports a number of built-in
numerical functions.
- +
- Addition
expr1 + expr2
- -
- Subtraction
expr1 - expr2
- *
- Multiplication
expr1 * expr2
- /
- Division
expr1 / expr2
- POW
- POWer
expr1 POW expr2
Raise expr1 to the power expr2
For example, 3 POW 4 is 34, or 81.
- MOD
- MODulus
expr1 MOD expr2
Returns the integer remainder from expr1/expr2
For example, 26 MOD 7 is 5. See also the built-in
function fmod(), which returns floating point remainders.
- ROUND
- Number rounding
number ROUND places
Rounds number up or down to places decimal places.
For example, 123.45676 ROUND 2 is 123.46
|
|
Note: A minus sign can precede a literal number to
make it negative (for example, -3.14), but otherwise must
be used strictly as a binary operator: {-x} evaluates
to the literal string '-x'; to express the negative of a value,
use {-1*x} or {0-x}. Using +, /,
or * as a unary operator results in an expression
error. |
|
These 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).
- GT
- Greater Than
expr_a GT expr_b
Tests whether expr_a is greater than expr_b
- LT
- Less Than
expr_a LT expr_b
Tests whether expr_a is less than expr_b
- EQ
- EQual To
expr_a EQ expr_b
Tests whether expr_a is equal to expr_b
Two strings are equal only if the case (upper or lower) matches
letter-by-letter.
- NE
- Not Equal To
expr_a NE expr_b
Tests whether expr_a is not equal to expr_b
- GE
- Greater Than or Equal To
expr_a GE expr_b
Tests whether expr_a is greater than or equal to expr_b
- LE
- Less Than or Equal To
expr_a LE expr_b
Tests whether expr_a is less than or equal to expr_b
|
|
Note: The expression {0 EQ ''} ("does
zero equal the null string?") returns 1 (true). |
|
|
|
Tip: To check whether a string is non-null, you can
use the expression {string} rather than the longer
form {string NE ''}. Similarly, to test whether a
number is non-zero, use {number} rather than {number
NE 0}. |
|
|
Tip: Strings that consist of numbers and punctuation
characters, and begin with identical numeric prefixes (for
example '234-1' and '234-2') are considered equal by EQ. To
force Miva Script to perform a true string comparison, prepend
the same letter to both sides of the EQ. For example:
{'x' $ lhs EQ 'x' $ rhs}
|
|
These 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.
- NOT
- Logical NOT
NOT expr
Returns the opposite of expr (if expr is false,
NOT expr is true, and vice versa). Notice that this operator
is unary: it acts on one expression, not two.
- AND
- Logical AND
expr_a AND expr_b
This expression is true if both expr_a and expr_b
are true.
- OR
- Logical OR
expr_a OR expr_b
This expression is true if either of expr_a and expr_b
is true.
These operators are used with text strings or text string expressions.
Miva Script also supports a number of built-in
string functions.
- $
- Concatenate strings
expr_a $ expr_b
Concatenates (joins) the strings expr_a and expr_b
together.
For example, {'fred' $ 'flintstone'} would result in 'fredflintstone'.
- IN / CIN
- Beginning position
expr_a IN expr_b
expr_a CIN expr_b
Returns the beginning position of expr_a contained
in expr_b.
For example, {'da' IN 'canada'} returns 5, because 'da' begins
at the fifth letter in 'canada'. IN is case-sensitive: it will
find matches only if the matched sub-string in expr_b has
the same case, letter-by-letter, as expr_a. Use the CIN
operator if you want to make your comparison case-insensitive.
Notice that if you use literal strings in this expression you
have to surround them with single quotes.
- EIN / ECIN
- End position
expr_a EIN expr_b
expr_a ECIN expr_b
Returns the end position of expr_a contained in
expr_b.
For example, {'dia' IN 'canadian'} returns 7, because 'dia' ends
at the seventh letter in 'canadian'. EIN/ECIN returns 0 when the
left operand is NULL. This fixes backward comptibility with Miva
v3.57 and earlier "Htmlscript" versions. ECIN is the case-insensitive
version of EIN.
- SUBSTR
- Substring
expr SUBSTR 'position, #chars'
Returns the substring of expr that begins at position
and is #chars characters in length. For example, {'canadian'
SUBSTR '3,5'} returns 'nadia', which starts at the third character
in 'canadian', and is five characters long. Note that the right
side of a SUBSTR expression must be a string consisting of two
numbers separated by a comma, or an expression or macro that evaluates
to such a string.
- FMT
- Format string
expr FMT pattern
The FMT operator enables you to format a string based
on a pattern. This operator provides a way to enhance the search,
display, and logical processing capabilities of Miva Script
active documents. New users are advised to gain some experience
with constructing expressions using the built-in
string functions before trying FMT. See the section Formatting
values for a discussion of FMT string format patterns and
modifiers.
- CRYPT
- Encrypt a string
plaintext CRYPT key
Performs a one-way encryption, similar to that provided with
the UNIX crypt command. The string plaintext is
encrypted using the string key (this string is sometimes
called a 'salt') . key can be any two characters (extra
characters will be ignored). Only the first eight characters
of plaintext will be used in the encryption. key
is used as the first two characters of the encrypted value.
CRYPT always yields the same result when applied to a particular
plaintext and key.
These 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.
- BITAND
- Bitwise AND
expr_a BITAND expr_b
Perform a logical AND on the bits of expr_a and expr_b.
- BITOR
- Bitwise OR
expr_a BITOR expr_b
Perform a logical OR on the bits of expr_a and expr_b.
- BITXOR
- Bitwise Exclusive OR
expr_a BITXOR expr_b
Perform a logical exclusive OR on the bits of expr_a and
expr_b (return the number whose bits are equal to 1 in
either, but not both, of the original numbers).
- BITOC
- Bitwise ones complement
BITOC expr
Flip the bits of expr (including the 'sign bit'). Notice
that this operator is unary: it acts on one number, not two. Here
is an example: {BITOC 9}. 9 in binary form is '1001'; including
the 'sign bit' (leftmost bit), which indicates that the number
is positive, it is '01001'. Flipping these bits gives '10110'.
Since the sign bit is now '1', the number is negative. According
to the rules of binary arithmetic, '0110' interpreted as a negative
number is '-10'.
- BITSL
- Bitwise shift-left
expr_a BITSL expr_b
Shift the bits of expr_a to the left by expr_b places.
The leftmost bits are lost, and the rightmost bits are replaced
by zeroes.
'{23 BITSL 2}' is interpreted as follows: 23 is 00010111 in binary
form; shifting these bits left two places gives 01011100, or 92
in decimal format.
- BITSR
- Bitwise shift-right
expr_a BITSR expr_b
Shift the bits of expr_a to the right by expr_b
places. The rightmost bits are lost, and the leftmost bits are
replaced by zeroes.
Sometimes 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:
- Each operator is assigned a precedence, and if there is a choice
of which operator to evaluate first, the operator with higher
precedence is evaluated.
- If two operators have the same precedence, the leftmost one
is evaluated first.
- Sub-expressions inside parentheses, '(' and ')', are evaluated
first.
The order of precedence for Miva Script operators, from highest
to lowest, is as follows:
- NOT
- FMT, ROUND, CRYPT, MOD, SUBSTR, POW
- /, *
- +,-,$
- IN, CIN, EIN, ECIN, EQ, NE, GE, LE, LT, GT
- AND, OR
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.
So 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.
|
|
Note: A macro can contain only a single variable, and
no expressions, literals, or functions. |
|
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:
|
Tip: Both expressions and macros can be used to specify
the values of Miva Script attributes. Only macros can
be used to specify the values of HTML attributes. This
attribute assignment is correct:
<FORM ACTION="&[documenturl];">
This form is incorrect:
<FORM ACTION="{documenturl}">
|
|
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'.
|
Tip: If the value of a variable contains double quotes,
using it in a macro as the value of an attribute may cause
a syntax error. The form:
EXPR="{var}"
is safer than:
EXPR="&[var];"
In general, you should not use a macro unless you have a very
good idea of the format of the value in the variable it contains.
See also the following section on security. |
|
Because 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.
|
|
Note: A macro in a quoted string that is inside an expression is expanded inside of the quoted string and will not be executed.
|
|
- All user input (for example, input from a FORM, from a data
file, from the URL command line, or from a POST action) should
be validated to ensure that it does not contain executable code.
If it does, it must not be displayed using a macro (or if it is,
it must be entity-encoded). Ideally,
your script should issue an error message to the user indicating
that tags must not be entered. Variations on the the following
code fragment will test whether the input contains any executable
code (that is, tags). In this example, assume that input from
a FORM is contained in the variables field1, field2,
field3, field4, and field5.
<MvASSIGN
NAME="input"
VALUE="{field1$field2$field3$field4$field5}">
<MvIF EXPR="{('<' IN input) OR ('>' IN input)}">
<P>Invalid input! Please do not enter HTML or Miva Script tags in any field!</P>
</MvIF>
Entity-encoding a variable makes
the contents of the variable safe and can be used instead of the
code above.
- Use <MvEVAL> instead of a macro to display the values
of variables. Macros must be used if you want to insert a variable's
value in an attribute, but for displaying text to the browser
a macro can always be replaced by an <MvEVAL> tag. For example:
<MvCOMMENT>Possibly unsafe!</MvCOMMENT>
...
You said: &[someinput];
<MvCOMMENT>Safe!</MvCOMMENT>
...
You said: <MvEVAL EXPR="{someinput}">
- If your program is not relying on the value of a variable
being set via user input, and that variable is being displayed
with a macro, the variable should be explicitly initialized (set
to some initial value with <MvASSIGN>) in the program. This
prevents values from other sources inadvertently or intentionally
being output.
The 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-encoding
The 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-encoding
A 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.
Summary
<MIVA
INTERPRET="tags,macros"
STANDARDOUTPUTLEVEL="html,text,compresswhitespace"
DEFAULTMACROENCODING="none,entities,attributes"
ERROROUTPUTLEVEL="syntax,expression,runtime"
ERRORMESSAGE="text_of_error_message"
<TAGNAME>_Error="fatal/nonfatal,display/nodisplay">
The <MIVA> tag enables you to configure the level
of code interpretation, output,
Default Macro Encoding,
error reporting, and error
handling. <MIVA> is an empty
tag.
|
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.
The 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:
- tags: Miva Script tags will be interpreted
- macros: Miva Script macros will be interpreted
- tags,macros or macros,tags: both tags and
macros will be interpreted (the default).
- null string: neither tags nor macros will be interpreted.
Note that an INTERPRET value consisting of any arbitrary
string (such as none) is equivalent to the null string.
A 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.
|
|
Note: Since the Miva Script macros on each line of
the document are resolved into their textual equivalents before
the Miva Script tags on that line are executed, macro references
are treated as just another type of text by STANDARDOUTPUTLEVEL. |
|
The possible STANDARDOUTPUTLEVEL values are:
- html: HTML tags will be passed to the browser
- text: text will be passed to the browser
- text,html or html,text: both text and HTML
tags will be passed to the browser (same as the default)
- null string: neither text nor HTML tags will be passed
to the browser. Note that a STANDARDOUTPUTLEVEL value consisting
of any arbitrary string (such as none) is equivalent
to the null string.
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.
The Miva Script DEFAULTMACROENCODING attribute will assign the default
encoding type to all macros. There are three values that can be assigned
to the attribute:
- none: marcos have no encoding,
- entities : macros are entity encoded
- attributes: macros are attribute encoded
Encoding used on an individual macro will override the default macro encoding.
Miva Script can report three kinds of errors:
- syntax errors: badly formed or missing tags or attributes.
For example:
<MvCOMMENT>Badly-formed tag</MvCOMMENT>
<MvIF EXPR="{var}">Hello</MvIF
<MvCOMMENT>Missing attribute</MvCOMMENT>
<MvIF>hello</MvIF>
- expression errors: badly-formed expressions. For example:
<MvCOMMENT>Missing '}'</MvCOMMENT>
<MvEVAL EXPR="{a + b">
<MvCOMMENT>Expected operator, none found</MvCOMMENT>
<MvEVAL EXPR="{a b}">
- runtime errors. For example, attempting to read (with
<MvIMPORT>) from an external file that does not exist.
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.
Whenever 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:
- fatal/nonfatal: fatal will cause
all runtime errors for this tag to terminate the script; nonfatal
will allow the script to continue.
- display/nodisplay: display will cause
runtime error messages for this tag to be displayed; nodisplay
will suppress error messages for this tag.
For example:
<MIVA MvIMPORT_ERROR="nonfatal,nodisplay">
This will cause <MvIMPORT> runtime errors to not terminate
the script or be displayed.
|
|
Note: If the ERROROUTPUTLEVEL attribute exists,
its runtime setting (whether present or absent) overrides
the display/nodisplay setting made with
TAGNAME_ERROR. |
|
JavaScript 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:
- You can write Miva Script code that generates JavaScript
code.
- JavaScript code can assign a value to a form field that is later
passed on to a Miva Script program.
- You can call a Miva Script program from a command line (URL)
that was generated from JavaScript.
Keep in mind, though, that the JavaScript code can interact directly
only with the HTML code in your document, not the Miva Script code.
Most 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:
Summary
<MvIF EXPR="{condition}">
...code...
</MvIF>
Process the code between the <MvIF> and </MvIF>
tags if and only if condition is true. EXPR
is required.
<MvIF EXPR="{condition}">
...code...
<MvELSE>
...code...
</MvIF>
Process the code between the <MvIF> and <MvELSE>
tags if condition is true. Otherwise (that is, if condition
is false) process the code between the <MvELSE> and
</MvIF> tags. EXPR is required. <MvELSE>
is an empty tag.
|
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 first <MvIF> is evaluated.
- Since age is greater than or equal to 17, the program
continues with the next line after the <MvIF>.
- This line is executed, and the text is displayed.
- The second <MvIF> is evaluated.
- Since age is not greater than 80, the next line
after this <MvIF> is not executed. Instead, the program
jumps to the next line after the </MvIF> end-tag that corresponds
to the second <MvIF>.
- This line is executed, and the text is displayed.
The result will be:
This person may be eligible to drive a motor vehicle.
The license fee is $40.75. |
With 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 decisions
Sometimes 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:
- age is less than 17
- age is between 17 and 114, inclusive
- age is greater than 114
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.
Summary
<MvWHILE EXPR="{expression}">
...code...
....<MvWHILESTOP>
...code...
</MvWHILE>
Repeats the code between <MvWHILE> and </MvWHILE>
until the condition expression, given by the required
attribute EXPR, is false, or an <MvWHILESTOP>
(optional) is executed. <MvWHILESTOP> is an empty
tag.
|
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 times
Here 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 times
The '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.
Summary
<MvEXIT>
The <MvEXIT> tag causes the script to terminate. <MvEXIT>
is an empty tag.
|
|
|
Note: An <MvEXIT> in a script called with <MvDO>
also causes the script containing the <MvDO>
to terminate. To exit from a script called by <MvDO>,
without exiting from the calling script, use <MvFUNCRETURN>. |
|
There 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:
|
|
Note: Unless a Miva Script variable is passed to another
program using one of the methods listed above, it has no meaning
outside the currently running instance of the program; that
is, its maximum scope is the current
program instance. |
|
Data 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:
| Character |
URL-encoding |
| Space ( ) |
+ |
| Plus sign (+) (used
to represent itself) |
%2b |
| Percent (%) |
%2f |
| Equal (=) |
%3d |
| Ampersand (&) |
%26 |
Arguments 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:
nargs=
arg1=
arg2=
arg3= |
3
fruit.mv
black%20cherries
oranges |
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:
| Character |
Hexadecimal form |
| Space ( ) |
%20 |
| Plus sign (+) |
%2b |
| Minus sign/hyphen
(-) |
%2d |
| Tilde (~) |
%7e |
For example:
http://127.0.0.1/fruit.mv?granny%20smith%20apples+oranges
|
Note: If you pass a null argument (an argument with
no value), Miva Script will readjust the list of argument
values to ignore the null argument. For example:
http://www.your_server.com/cgi-bin/miva?fruit.mv++oranges
The first argument after the script name is absent. In this
example, 'oranges' will become arg2 instead of arg3. |
|
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.
Summary
<FORM ACTION="..." METHOD="GET|POST">
...
<MvHIDE FIELDS="var1,var2,var3,...">
...
</FORM>
<MvHIDE> tags are converted into one or more 'hidden'
<INPUT> tags, corresponding to each of the variables
var1, var2, var3 specified by FIELDS
(required).
If variable var1 has value x, and var2
has value y (x and y are literals), then:
<MvHIDE FIELDS="var1,var2">
is converted in place to:
<INPUT TYPE="hidden" NAME="var1" VALUE="x">
<INPUT TYPE="hidden" NAME="var2" VALUE="y">
<MvHIDE> tags should be used only inside forms. When
the form is submitted, the variables and their values are
passed to the receiving program (specified by the <FORM>
element's ACTION attribute) as name/value pairs (if
METHOD is 'GET') or in the standard input (if METHOD
is 'POST'). This provides a way to pass variable values to
the program called by the form.
|
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.
|
|
Note: Variables corresponding to fields that are already
part of the form should not also be passed to the receiving
program using <MvHIDE>. |
|
Each 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 (;).
- A name/value pair (id=MyCo in this example) is mandatory.
The name and value are arbitrary strings, but cannot contain a
comma, semi-colon, or space.
- You can optionally specify an expiry date. The date can
be in one of these forms, of which the first is preferred:
Day, DD Mon YYYY, HH:MM:SS GMT (Thu, 05 Nov 1998 16:00:00 GMT)
Day, DD-Mon-YY HH:MM:SS GMT (Thursday, 05-Nov-98 16:00:00 GMT)
Day Mon D (or DD) HH:MM:SS YYYY (Thu Nov 5 16:00:00 1998)
- You can optionally specify to which domain the cookie
can be sent, and to which URLs (paths) within that domain.
- You can optionally specify that a secure protocol be
used to send the cookie.
All of the cookies for this document are available in the http_cookie
system variable.
Summary
<MvFUNCTION NAME="myfunc"
PARAMETERS="var1,var2,..."
STANDARDOUTPUTLEVEL="html,text"
ERROROUTPUTLEVEL="syntax,expression,runtime">
...code...
<MvFUNCRETURN VALUE="{expression}">
...code...
</MvFUNCTION>
...
myfunc(val1,val2,...)
Defines the function myfunc, whose name is specified
with the required attribute NAME. Parameters var1,
var2, ..., can optionally be defined with the PARAMETERS
attribute. These are assigned the values va11, val2,
..., in the function call. The function can optionally terminate
with a return value specified with <MvFUNCRETURN>. Functions
can use locally defined variables whose scope is the function
body. STANDARDOUTPUTLEVEL and ERROROUTPUTLEVEL
are optional and are interpreted in the same way as in the
<MIVA> tag. <MvFUNCRETURN>
is an empty tag.
Functions are called in expressions. Functions can be forward
referenced: Miva Script code can make references to functions
that are defined after the reference in question.
|
Sometimes you will need to carry out the same series of steps at
several different locations in your program. If you were to repeat
the same lines of code every place they were needed, your program
would get long, hard to read, and hard to modify, and the chances
of making errors would increase. Functions enable you to write re-usable
code that can be called on to perform operations throughout
the program, by calling the function in any valid expression. Even
if a function is only called once in your program, moving the code
out of the main body of the program and replacing it with a function
call still helps to make the program more 'modular' and easy to
follow.
Here is an example--a function that returns the greater of two
numbers:
<MvFUNCTION name="greater2" parameters="num1,num2">
<MvIF EXPR="{num1 GE num2}">
<MvFUNCRETURN value="{num1}">
<MvELSE>
<MvFUNCRETURN value="{num2}">
</MvIF>
</MvFUNCTION>
...
...
<MvASSIGN name="older" value="{greater2(age1,age2)}">
This example defines a function called greater2 and shows
how it is used in an <MvASSIGN> tag. The point of the <MvASSIGN>
is to get the greater of the values in the two variables age1
and age2 and assign that value to the variable older.
The value of the <MvASSIGN> is a reference or 'call' to the
function greater2. The variables age1 and age2
appear in brackets after the function name; they are called the
'arguments' of the function and are said to be 'passed to' the function.
Now consider the function definition. Functions start with <MvFUNCTION>
and end with </MvFUNCTION>. The NAME attribute of <MvFUNCTION>
is required, and specifies the name by which the function is called.
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:
- You might want to call greater2 with different variables
as its arguments; if the function always used just age1
and age2, you would always have to call it with those variables.
- Since the function isn't supposed to change the values
of age1 and age2 it's safer not to use these variable
names in the function. If you unintentionally changed one of these
values in the function, it might cause a problem that would be
hard to track down later.
Let's return to the definition of the function: it consists of
a single <MvIF>-<MvELSE>-</MvIF> block. If num1
is greater than or equal to num2, then the first <MvFUNCRETURN>
tag is executed. The purpose of this tag is to 'return' or send
a value back to the tag that called the function in the first place.
This value is said to be the 'value of the function'. In this case,
the function was called inside an expression in the VALUE attribute
of an <MvASSIGN>; when the function returns a value, it is
the same as if that value were substituted for the call to the function.
Here is the <MvASSIGN> again:
<MvASSIGN name="older" value="{greater2(age1,age2)}">
Suppose age1 equals 17 and age2 equals 12. When greater2
returns the value 17, it is the same as if the <MvASSIGN>
were:
<MvASSIGN name="older" value="{17}">
If num2 is greater than num1 when the function is
executed, then the second <MvFUNCRETURN> returns a value.
Once an <MvFUNCRETURN> is executed, the function immediately
stops executing (this includes any loops such as <MvWHILE>
and <MvIMPORT>) and the program jumps
back to the location of the function call.
Local variables and parameters
In addition to parameters defined with the PARAMETERS attribute,
you can use 'local' variables that are meaningful only inside the
function. These variables must start with the l. or local.
prefix. 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>
A function can be called in any expression. The simplest way to
call a function is in an <MvEVAL> tag:
<MvEVAL EXPR="{func1(var_a)}">
Function calls can be combined with other components of an expression:
<MvEVAL EXPR="{'The answer is: ' $ func1(42)}">
<MvEVAL EXPR="{square(4) + square(5)}">
The argument(s) of a function can be literal, variable, or any
valid expression; an expression inside a list of arguments will
be evaluated before the function call takes place, and the function
will be called with the resulting value.
<MvEVAL EXPR="{func1(6)}">
<MvEVAL EXPR="{func1('xyzzy')}">
<MvEVAL EXPR="{func1(a + b)}">
<MvEVAL EXPR="{func1('Dear ' $ customer $ ',')}">
The function is called before EXPR is evaluated, and the
function result (the value returned by <MvFUNCRETURN>) is
substituted in the expression.
|
|
Tip: If a function returns a value, but you don't
want to display this value in your output, you can use <MvASSIGN>
instead:
<MvASSIGN NAME="do_this" VALUE="{func1(var_a)}">
This calls the function and assigns the return value (if
there is one) to the variable do_this. You can just
'throw away' do_this (that is, don't use it for anything).
You may find it useful to use the same variable name--do_this,
do, junk, or a name of your choice--for this
purpose to make it easier to keep track of what this assignment
tag is really doing.
|
|
Calling functions from a form
You can also indirectly call a function via a form submission.
That is, you cannot call a function directly in this way, but you
can put code in your program that takes the results of a form submission
and makes a function call. Consider this example:
<BODY>
<H1>This is a test of calling a function</H1>
<MvIF EXPR = "{ fname }">
<MvEVAL EXPR = "{ &[ fname ];() }">
<MvELSE>
<MvEVAL EXPR = "{ main() }">
</MvIF>
<MvFUNCTION NAME="funk">
...code...
</MvFUNCTION>
...other function definition code...
<MvFUNCTION NAME="main">
...code...
<FORM ACTION="&[ documenturl ];fname=funk" METHOD="post">
...code...
</FORM>
...code...
</MvFUNCTION>
</BODY>
This example has three main parts: a function called main,
a section of function definitions (funk is the only one that's
shown), and an <MvIF> tag that decides which function will
get called when the document is loaded.
As the name suggests, main is the part of the program that
controls the other functions. Inside main there is a FORM
element; the ACTION attribute of the FORM is a URL that tells
the browser what to do when the user submits the form. In this case
the ACTION consists of &[documenturl ];fname=funk.
documenturl is a special built-in variable that always consists
of the URL of the current document, with a plus sign (+) or question
mark (?) appended, depending on which flavor of Miva Engine you
are using . Suppose the current document's URL is:
http://www.your_server.com/cgi-bin/miva?testy.mv
The expression '&[ documenturl ];fname=funk' will be equal
to:
http://www.your_server.com/cgi-bin/miva?testy.mv+fname=funk
As 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.
Here are a few more things you should be aware of:
Summary
<MvDO
FILE="filename"
NAME="var"
VALUE="{func(args)}">
A value for FILE is required. If NAME and VALUE
are specified, the function func defined in the file
filename is run with arguments args and the
result is assigned to the variable var. If NAME
and VALUE are omitted, the file filename is
processed as if it were included in the current file. In each
case, any output from the external file is merged into the
current file. filename can be a path: if it is a relative
path, it is interpreted as relative to the current file; if
it starts with a forward slash (/), it is relative to the
Miva Script document root directory. <MvDO> is an empty
tag.
|
<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.
|
|
Note: If the required attribute FILENAME
is missing, a value (error message)
for the variable mvdo_error is set, and the script
continues processing.
|
|
<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).
|
|
Note: There is a limit on the number of nested MvDO
calls at run-time. This limit is fixed at 23 for
Miva Mia; the default limit for Miva Empresa is 23 by default,
but this can be changed by the server administrator via
the maxfunctiondepth setting in the global configuration
file.
|
|
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">
If 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.
Miva 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.
Summary
<MvIMPORT
FILE = "filename"
FIELDS = "var1,var2,var3,..."
DELIMITER = "chars"
FILTER = "{expression}">
...
<MvIMPORTSTOP>
...
</MvIMPORT>
<MvIMPORT> imports a record (a single line) of data
fields, separated by the character(s) chars, from the
file filename, and stores the data in the var1,
var2, var3,... variables. FILE, FIELDS,
and DELIMITER are required. Optionally, a condition
can be specified with FILTER, so that records that
do not match the condition will be discarded. The data can
be processed with the code between the <MvIMPORT> and
</MvIMPORT> tags. <MvIMPORT> will loop through
the entire file, stopping when the end of the file is reached
or an <MvIMPORTSTOP> is executed. The variable recno
is automatically created, and contains the current record
number in the input file, starting at 1. <MvIMPORT>
tags can be nested to read data from multiple files within
the same block of code. Records in data files can be terminated
by line feeds, carriage returns, or line feed/carriage return
pairs. Data files should end with a blank line. <MvIMPORTSTOP>
is an empty tag.
|
|
|
Tip: Since searching in a text file is much slower
than searching in a database, we recommend
that if you will be reusing the data in a text file, you import
it, store it in a Miva database, and perform searches on the
database. This will speed up your scripts and avoid overloading
your server. |
|
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:
- FILE="movies.dat": Read a line of data from
the file movies.dat.
- DELIMITER="|": Assume that the fields in
each line are separated by the character '|' (vertical bar).
- FIELDS="title,director,year": Save the first
three fields of data in the variables title, director,
and year, respectively. (If there are more fields in the
line than there are variables specified, the extra fields are
just discarded.)
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:
title=
director=
year=
|
Cape
Fear
Martin Scorsese
1991
|
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:
| 1. |
Cape Fear |
Martin Scorsese |
1991 |
|
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:
|
Title |
Director |
Year |
| 1. |
Cape Fear |
Martin Scorsese |
1991 |
| 2. |
The Trouble With Harry |
Alfred Hitchcock |
1955 |
| 3. |
Dr Strangelove |
Stanley Kubrick |
1963 |
| 4. |
Strange Days |
Kathryn Bigelow |
1995 |
| 5. |
Clerks |
Kevin Smith |
1994 |
|
Filtering the input
Sometimes 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:
|
Title |
Director |
Year |
| 1. |
Strange Days |
Kathryn Bigelow |
1995 |
|
Terminating the import
Importing 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 imports
It 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.
Summary
<MvEXPORT
FILE="filename"
FIELDS="var1,var2,var3,..."
DELIMITER="chars">
Writes the values of variables var1, var2, var3,...,
to the external file filename, separated by the characters
chars. FILE, FIELDS, and DELIMITER
are all required attributes. DELIMITER can be one or
more characters. <MvEXPORT> is an empty
tag.
|
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.
Summary
<MvLOCKFILE FILE="filename">
...
</MvLOCKFILE>
<MvLOCKFILE> indicates to other processes that the
current process has requested an exclusive lock on filename
(required). A lock request is in effect until the corresponding
</MvLOCKFILE> end-tag is reached or the process ends
or times out. Multiple lock requests with <MvLOCKFILE>
on the same file are queued. There is no limit on the number
of files on which lock requests can be made. filename
can be any file--a database, memo, index, or flat (.dat,
.txt, etc.) file. <MvLOCKFILE> tags can be nested.
|
|
|
Note: In this section, it is useful to make a distinction
between a 'program' and a 'process'. The same program (file
containing Miva Script code) can be running more than once
simultaneously on the same server: each such instance of a
running program is referred to as a 'process'. Often, an instance
of a program will be 'competing' with other instances of the
same program (that is, other processes) for access to the
same files. |
|
<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.
|
|
Note: <MvLOCKFILE> uses a 'semaphore file' mechanism.
The name of the semaphore file is not guaranteed be the same
when Miva Script is used on different platforms, or to remain
the same in future implementations of Miva Script. For this
reason, programs should not be written in a way that relies
on the existence of a specific semaphore file name. |
|
Nesting <MvLOCKFILE>s
You 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.
|
|
Note: If a process terminates without explicitly removing
a lock request on a file, it will be removed automatically
the next time an <MvLOCKFILE> requests a lock on the
same file. |
|
Database locking
As 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.
Summary
<MvCALL
ACTION = "URL"
METHOD = "POST|GET"
FIELDS = "var1,var2,var3,..."
FILES = "fvar1,fvar2,fvar3,...">
...code...
<MvCALLSTOP>
...code...
</MvCALL>
<MvCALL> uses the HTTP/1.0 protocol to emulate a browser
and contact a remote host. Static HTML, XML, and SGML pages
can be requested from the remote server, and data can
also be sent to the remote server.
ACTION specifies the URL to be contacted: this must
be a full URL starting with http. METHOD can
be POST (send data) or GET (send data or request a document).
FIELDS contains variables whose values are sent to
the URL when POST is used as the method. FILES contains
variables whose values are filenames that will be uploaded
to the specified URL (see the section File
uploading).
When <MvCALL> receives a document, it iterates once
for each object (text or tag) that it receives. Several special
variables (described below) are created with data about the
object.
The <MvCALL>...</MvCALL> loop terminates when
the entire document has been received, or when an <MvCALLSTOP>
(optional) is encountered. <MvCALLSTOP> is an empty
tag.
|
|
|
Note: <MvCALL> does not support the HTTPS (secure
HTTP) protocol. |
|
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:
- <P>
- When in
- <B>
- Rome
- </B>
- do as the
- <I>
- Romans
- </I>
- do.
- </P>
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.
Tags
The 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:
- callvalue: the whole tag, including angle brackets, tag
name, and any attributes and attribute values.
- callobjectelement: the tag name, for example 'IMG' for
an <IMG> tag, '/TABLE' for a </TABLE> tag.
- callobjectnumattributes: the number of attributes specified
for the tag.
- callobjectattributeN: if attributes have been specified
for the tag, variables callobjectattribute1, callobjectattribute2,
... will be created, containing the names of the attributes
as they appear in sequence.
- callobjectvalueN: if attributes have been specified for
the tag, variables callobjectvalue1, callobjectvalue2,
... will be created, containing the values of the attributes
as they appear in sequence.
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:
| Name |
Value |
| callvalue |
the entire tag |
| callobjectelement |
IMG |
| callobjectnumattributes |
4 |
| callobjectattribute1 |
SRC |
| callobjectvalue1 |
donkeys.gif |
| callobjectattribute2 |
ALT |
| callobjectvalue2 |
The Donkey Farm |
| callobjectattribute3 |
HEIGHT |
| callobjectvalue3 |
100 |
| callobjectattribute4 |
WIDTH |
| callobjectvalue4 |
200 |
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.
|
|
Note: All of these variables (except callvalue)
will be set to null if the current object is of type 'text'. |
|
Text
The 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.
|
|
Note: Sequences of whitespace between tags (such as
newlines, spaces, and tabs) are returned as text objects by
MvCALL. |
|
Headers
When it retrieves a document, <MvCALL> also receives HTTP
header information sent by the server. This information is stored
in the following variables:
- callnumberofheaders: This variable contains the number
of headers that have been retrieved. The number and content of
headers depends on the server software that is serving the document.
The value of callnumberofheaders will not change during
the iterations of the <MvCALL> loop through a particular
document.
- callreturnheaderN: The headers received are placed into
a separate variables callreturnheader1, callreturnheader2,
and so forth. The values of these variables do not change during
the iterations of the <MvCALL> loop through a particular
document.
Here is an example of header data:
callnumberofheaders=
callreturnheader1=
callreturnheader2=
callreturnheader3=
callreturnheader4=
callreturnheader5=
callreturnheader6= |
6
HTTP/1.0 200 OK
Date: Fri, 17 Jan 1997 01:23:24 GMT
Server: Apache/1.1b0a
Content-type: text/html
Content-length: 390
Last-modified: Thu, 16 Jan 1997 23:40:10 GMT |
MvCALL examples
The 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:
...
Tag name: B
Number of attributes: 0
Tag name: FONT
Number of attributes: 2
Text: ==An out-of -office experience==
Tag name: /FONT
Number of attributes: 0 ...
|
Limitations
<MvCALL> does not provide a true HTML, SGML, or XML parser,
so it has some limitations :
- It does not check whether a document is valid or well-formed
- It does not resolve internal or external entities
- It treats XML namespace prefixes a part of the tag (most of
the time this is not a problem)
Nevertheless, <MvCALL> is a useful tool for processing structured
documents, particularly those that are valid and well-formed.
|
|
Note: <MvCALL> may produce unexpected results
if the document being requested uses the double-quote character
(") instead of the entity " in literal
text. |
|
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.
|
|
Note: It is not possible in Miva Script to modify the
default HTTP headers when sending a request to a server. |
|
To 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>
If 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>
Since 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.
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 commands
Miva 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.
Miva supports two forms of file uploading: sending a file from
one host to another, and receiving a file from an end-user.
Summary
Sending a file
<MvCALL ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
FILES="var1,var2,...">
Send the files whose name are given by var1,var2,...
(relative to the Miva data directory) to the host and script
specified by ACTION, where the upload will be processed
by the specified script.
Receiving a file
<FORM ACTION="http://www.recipient.com/uploadscript.mv"
METHOD="POST"
ENCTYPE="multipart/form-data">
<INPUT TYPE="FILE" NAME="some_name">
<INPUT TYPE="SUBMIT">
</FORM>
Enables an end-user to choose a file on the local network
and send it to the host and script specified by ACTION,
where the upload will be processed by the specified script.
Whether you are sending or receiving a file, if the recipient
script is a Miva Script program, it must contain the following
user-defined functions:
<MvFUNCTION NAME="Miva_ValidateFileUpload"
PARAMETERS="field, filename, content_type">
<MvFUNCTION NAME="Miva_ProcessFileUpload"
PARAMETERS="field,filename,status,tempfile,content_type,size">
|
Files 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.
The 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>
|
|
Note: The specific parameter names used here are arbitrary. |
|
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:
- -1: skip this file--don't upload it at all.
- 0 (zero): upload the whole file, no matter how long
it is.
- Any positive integer N: upload only the first N bytes of the
file.
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">
The recipient script must contain the following function, which
processes the upload:
<MvFUNCTION NAME="Miva_ProcessFileUpload"
PARAMETERS="field,filename,status,tempfile,content_type,size">
...
</MvFUNCTION>
|
|
Note: The specific parameter names used here are arbitrary. |
|
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 Miva variable (field) containing the filename.
- The filename itself.
- The upload status: this will be one of the strings 'SKIPPED',
'COMPLETE', or 'PARTIAL', and indicates whether the file was skipped
(not uploaded at all), uploaded completely, or partially uploaded.
- A temporary file tempfile in which the uploaded file
will be stored. This file will be deleted as soon as Miva_ProcessFileUpload()
terminates.
- The MIME type (content_type) of the file, on the uploading
server.
- The size of the original file (untruncated)
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)}">
To 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.
|
|
Note: For this kind of upload, the field parameter
(the first argument passed to Miva_ValidateFileUpload()
and Miva_ProcessFileUpload()) is the name of the variable
containing the filename. |
|
|
|
Note: You can also send data to the recipient script
using the FIELDS attribute of <MvCALL> at the
same time that you send the file(s) to be uploaded. |
|
To 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.
|
|
Note: For this kind of upload, the field parameter
(the first argument passed to Miva_ValidateFileUpload()
and Miva_ProcessFileUpload()) is the NAME of the <INPUT>
object used to specify the file. |
|
|
|
Note: In general, browsers do not permit files specified
with http://-style URLs to be uploaded using this method.
Instead, local network drive paths (such as c:\...)
should be specified. Some browsers do not allow a default
VALUE for <INPUT TYPE="FILE"> fields. |
|
An 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.
Miva 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.
Summary
<MvSMTP
TO="to_address1,to_address2,..."
SUBJECT="expression"
CC="cc_address1,cc_address2,..."
MAILHOST="mailhost"
FROM="from_address">
[optional headers]
[blank line]
... message body (text/tags)...
</MvSMTP>
Send mail, using SMTP, to the to_address1, to_address2,
... email addresses. Required are: at least one TO
value, a MAILHOST value consisting of the domain name
or IP address of a host that understands SMTP, and the sender's
email address (FROM). Optionally, one or more CC
("carbon copy") addresses and a SUBJECT line
can be specified. The message body appears between the <MvSMTP>
and </MvSMTP> tags.
|
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 formats
Most 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.
In 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.
Summary
<MvPOP
MAILHOST="host"
LOGIN="login_name"
PASSWORD="password"
DIRECTORY="directory">
...code...
<MvPOPDELETE>
...code...
<MvPOPSTOP>
...code...
</MvPOP>
<MvPOP> creates a loop that logs into the POP3 mail
server named host, using the login_name and
password login information, and retrieves all incoming
mail messages, one message at a time. Messages are stored
on your local system (that is, the system running Miva, not
necessarily the system running the POP3 server) under unique
filenames, in the directory specified with DIRECTORY.
The host, login name, password, and storage directory are
all required. When a message is retrieved, information about
the message is stored in the special variables messagebody,
messagesubject, messagereplyto, messagesender,
and messagedate. This information can then be processed
inside the loop. If an <MvPOPDELETE> (optional) is executed,
the current message is deleted from the server. If an <MvPOPSTOP>
(optional) is executed, the <MvPOP> loop terminates.
<MvPOPDELETE> and <MvPOPSTOP> are empty
tags.
|
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:
- messagesubject: the 'Subject:' line of the incoming
message.
- messagedate: the 'Date:' line of the message.
- messagesender: the 'From:' line (sender) of the message.
Do not use this value for replying to a message; instead, use
the value of messagereplyto.
- messagereplyto: the 'Reply-To:' line (the address to
which replies should be sent). If the incoming message does not
have 'Reply-To' in its header, then the 'From:' line is used for
this value.
- messagebody: a guaranteed unique file name in which
the message body has been saved.
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:
You received mail from: Walter Mitty.
This mail is about: My latest adventures.
This mail was received on: Tue, 10 Mar 1998 13:50:10 -0500 (EST).
I stored this mail in the file: testmail/MIVA_POP.a06431.
You can reply to: Walter Mitty.
|
If there is more than one incoming message, <MvPOP> will
iterate through them and print these fields for each message.
Deleting an email message
By 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.
Miva 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.
|
|
Tip: If possible, use the Miva Mia to perform time-consuming
database operations such as converting a flat file to a database,
and creating a new index for a large database. This can avoid
heavy consumption of web server resources, and having your
program time out. You can set Miva Mia's timeout value to
be as high as you like. |
|
With 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>.
Miva 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:
| Benson |
President |
250000 |
19930630 |
1 |
Former V-P sales |
| Rochester |
V-P Finance |
120000 |
19921015 |
1 |
Weird ties |
| Jeeves |
V-P Technology |
150000 |
19880710 |
1 |
Funny hats |
| Hudson |
V-P Sales |
130000 |
19971201 |
1 |
|
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 operations
Databases 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 the database. 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. Miva Script uses
the <MvCREATE> tag to create a database.
- Database aliases. An important aspect of working with Miva databases
that you need to understand is that databases are almost always
referred to in Miva Script tags using a database alias,
rather than the actual physical filename of the database. An alias
is simply a name that you assign to the database when you open
it. The same database file can be open two or more times simultaneously
with different aliases. If the database has only one current alias,
then the alias and the database can be thought of as identical;
sometimes this manual will, for convenience, and if the intention
is clear, use the term 'database' when strictly speaking 'database
alias' is correct.
- Opening the database. 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 use 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 you want, you
can use a different alias for the database the next time you open
it.
- The primary database. Miva Script allows
several database aliases to be open at the same time, and each
of them can be accessed in Miva Script tags by referring to the
alias. As a convenience, Miva Script allows one alias at a time
to be designated the 'primary' database alias. This means that
if a database tag does not explicitly name an alias, the primary
alias is implied. An alias becomes the primary alias automatically
when it is created or opened (subsequent create or open operations
override this); an alias can also be made the primary alias explicitly
using <MvPRIMARY>.
- Adding and updating
records. Often you will want to add records or change one or more
fields in an existing record. The way you do this in Miva Script
is to assign values to a special set of variables
corresponding to the database fields, and then use the <MvADD>
tag to add a record, or <MvUPDATE> to update the current
record.
- Indexing the database. When 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, 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.
- Database navigation. There are several
ways of moving from one record to another. You can find (<MvFIND>)
the first record in the database index that contains a specific
value; you can go (<MvGO>) to a specific
record in physical order; and you can skip (<MvSKIP>)
to the next record in physical or indexed order.
- Filtering the database. You can use
the <MvFILTER> tag to make 'visible' only those records
that satisfy a specified criterion.
- Reading and displaying database records.
In order to read and display the contents of a record, you first
navigate to the record. At that point the contents of each of
the record's fields will be available in a set of special database
variables.
- Deleting records. To delete a record,
you first navigate to the record. The <MvDELETE> tag marks
the record for deletion; the <MvPACK> tag physically removes
it.
- Obtaining a database's structure:
the <MvREVEALSTRUCTURE> tag is used to find out information
about the kinds of fields in a database record for a specific
database.
Summary
<MvCREATE
NAME = "db_alias"
DATABASE = "db_file"
FIELDS = "fieldname1 CHAR(max_chars),
fieldname2 NUMBER(digits_before.digits_after),
fieldname3 DATE,
fieldname4 BOOL,
fieldname5 MEMO
..."
TYPE="xbase3">
<MvCREATE> creates a new database, with filename db_file,
having the data structure specified by FIELDS. The
NAME, DATABASE, and FIELDS attributes are all required. Fields
in the database can be of type CHAR, NUMBER, DATE, BOOL, and
MEMO. For CHAR fields, the maximum number of characters must
be specified; for NUMBER fields, the numbers of digits allowed
before and after the decimal point can be specified. If db_file
already exists, it will be overwritten with an empty database
with the specified structure. When a database is created it
is implicitly opened (just as with <MvOPEN>) with the
alias db_alias. db_alias cannot contain the
'.' (period) character. <MvCREATE> is an empty
tag.
|
|
|
Note: The TYPE attribute of <MvCREATE>
has the default value xbase3. This attribute can be
omitted, since <MvCREATE> is currently supported only
for xbase3 databases. |
|
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.
Here 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 database
The 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 fields
The 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.
Summary
<MvPRIMARY NAME="db_alias">
Several database aliases can be open at the same time, but
one alias is said to be the primary alias. This is
the default alias for all database operations (except creating
and opening a database). If the NAME attribute is not
specified by a database tag (except <MvCREATE> and <MvOPEN>),
that tag's action will be performed on the database pointed
to by the primary alias. By default, the primary alias is
the last open to be opened with <MvOPEN> or <MvCREATE>.
If more than one alias is open, <MvPRIMARY> makes the
alias db_alias the primary one (this value is required).
db_alias must currently be open. <MvPRIMARY>
is an empty tag.
|
|
|
Note: For convenience, this manual will refer to "the
database pointed to by the primary alias" as "the
primary database". |
|
When 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:
- fieldname_day: Contains the day of the month (as a two-digit
number)
- fieldname_month: Contains the month of the year (as a
two-digit number)
- fieldname_year: Contains the year (as a four-digit number)
- fieldname_raw: contains an exact date in yyyymmdd
string format
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.
|
Note: Database variables are automatically right-trimmed.
The length of the contents of a database variable is equal
to the actual length of the contents assigned to the corresponding
field, minus any extra spaces on the right. For example:
<MvASSIGN NAME="db.d.name" VALUE=" cow ">
<MvADD>
<MvEVAL EXPR="{len(db.d.name}">
This gives the result '4'.
In general, the length of a database variable is not equal
to the length of the corresponding database field, as defined
with <MvCREATE>.
|
|
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.
|
Tip: Avoid this common error: because of Miva Script's
variable scope rules, if the variable
vname exists and the primary database db_alias
has a field called vname, the value of the variable
vname will be interpreted as the value of db_alias.d.vname.
Consider the following assignment of a value that will be
stored in the database:
<MvASSIGN NAME="db_alias.d.title" VALUE="{title}">
This will have the effect of assigning db_alias.d.title
its current value, because title is interpreted
as db_alias.d.title. To avoid this, do one of the following:
|
|
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.
|
|
Note: The physical record number of a record may change
if the database is packed (that
is, some records are physically deleted). For this reason,
you should not code in a way that uses the physical
record number as a unique identifier by which a record can
be referred to. You may instead wish to define a database
field in which you store a unique identifier for each record. |
|
The <MvOPEN> and <MvCLOSE> tags are used to open and
close databases.
Summary
<MvOPEN
NAME="db_alias"
DATABASE="db_file"
TYPE="xbase3|odbc"
INDEXES="index1.mvx,index2.mvx,...">
Opens the database with filename db_file, under the
alias db_alias, and makes it the primary
database. The record pointer is positioned at the first
record. NAME and DATABASE are required. If indexes
have been created for the database, they can optionally be
loaded when the database is opened. TYPE is optional
for xbase3 databases; it must have the value 'odbc' if you
are opening an ODBC database. <MvOPEN>
is an empty tag.
|
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.
Summary
<MvCLOSE NAME="db_alias">
<MvCLOSE> makes the database alias db_alias
unavailable; the database file may still be open under
a different alias. If NAME is not specified, the primary
database (the one most recently opened with with <MvCREATE>
or <MvOPEN>) is closed. <MvCLOSE> is an empty
tag.
All open databases are closed automatically when a Miva Script
program finishes executing, however, you may wish to close
an database explicitly when you've finished with it, so as
to prevent the database being used accidentally.
|
The 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>.
<MvADD NAME="db_alias">
<MvADD> adds a record to the end of the database that
has alias db_alias and positions the record pointer
at that record. If NAME is omitted, the record is added
to the primary database. Before <MvADD> is executed,
the information to be stored in each field that you want to
insert in the record must be assigned to variables (described
below) corresponding to each field. <MvADD> locks
the record that is being added. <MvADD> is an empty
tag.
|
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.
|
|
Note: Assigning values to variables for addition to
a database must be done after the database is opened. |
|
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 fields
Recall 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:
- Assign values to the fieldname_year, fieldname_month,
and fieldname_day variables individually.
- Assign a value to fieldname_raw.
- Assign a time_t value directly to fieldname.
(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.)
|
Note: When you make an assignment of this kind, the
value actually stored in the date variable (and the database)
is the time_t value as of 00:00:00 on the date in question,
not the exact time_t value that was assigned. The following
code will display two different values (unless the script
is run exactly at midnight!):
<MvEVAL EXPR="{time_t}">
<MvASSIGN NAME="d.datevbl" VALUE="{time_t}">
<MvEVAL NAME="{d.datevbl}">
|
|
|
|
Note: The same set of variables is used for both reading
and writing to a record. Since these variables automatically
adopt the values of the fields of the current record,
any variables in this set that you do not explicitly assign
values to before doing an <MvADD> will still have the
values for the current record, and these will be written to
the new record. For this reason, you should assign all relevant
variables a value before using <MvADD>. Variables for
fields to which you do not want to assign an explicit value
at this time should be assigned null values. |
|
Summary
<MvUPDATE NAME="db_alias">
Modifies the current record of the database that has alias
db_alias, with the contents of the variables corresponding
to the database fields. If NAME is omitted, the current
record in the primary database is updated. <MvUPDATE>
locks the record that is being updated.
<MvUPDATE> is an empty tag.
|
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.
Summary
<MvDELETE NAME="db_alias">
<MvUNDELETE NAME="db_alias">
<MvPACK NAME="db_alias">
<MvDELETE> marks for deletion the current record in
the database that has alias db_alias. Records marked
for deletion accumulate until they are actually deleted from
the database with <MvPACK>. These records are also visible
to database searching and navigation until the database is
packed. If the current record has been marked for deletion,
the boolean variable db_alias.d.deleted is set to true
(deleted or d.deleted can be used when referring
to the primary database).
<MvUNDELETE> removes a mark set with <MvDELETE>
from the current record in the database that has alias db_alias,
stopping the record from being deleted by the next <MvPACK>.
<MvPACK> permanently removes all records in the database
that have alias db_alias that have been marked for
deletion with <MvDELETE>. Changes in database file size
and in record counts resulting from <MvPACK> are not
recorded until the active database is closed. All open index
files are automatically updated after <MvPACK >is executed.
Use <MvREINDEX> to update closed indexes.
For each of these tags, if NAME is omitted, the action
is applied to the primary database. All of these tags are
empty tags.
|
|
|
Tip: When a database is packed, physical record numbers
(as provided by the recno built-in variable) are reset
as required. For this reason, you should not code in
a way that uses the physical record number as a unique identifier
by which a record can be referred to. You may instead wish
to define a database field in which you store a unique identifier
for each record. |
|
|
|
Tip: Because <MvPACK> can be quite resource-intensive
for large databases, and does not automatically lock the database
and index files that it uses, it should be used off-line,
with Miva Mia. You can then re-install your database on your
server. If you do pack the database on-line, you should use
<MvLOCKFILE> to request a
lock on the database and index files while <MvPACK>
is executing. |
|
When 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.
Summary
<MvMAKEINDEX
NAME="db_alias"
INDEXFILE="filename"
EXPR="{key_expr}"
FLAGS="[ascending|descending],[unique|nounique],[string]" >
Creates an index file filename for the database with
alias db_alias. If NAME is omitted, the index
is created for the primary database. In this index, records
are arranged in order according to the value of the key expression
key_expr, and any flags that are present. INDEXFILE
and EXPR are required. The database that the index
applies to must exist and be open under the alias db_aliaswhen
the index is created, though it need not contain any records.
The newly-created index becomes the main index for that database.
We recommend using the extension .mvx for index files.
<MvMAKEINDEX> is an empty tag.
|
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:
| Childs |
50000 |
| Kostick |
30000 |
| Kerr |
100000 |
| Yan |
15000 |
After indexing, the apparent sequence of records will be:
| Yan |
15000 |
| Kostick |
30000 |
| Childs |
50000 |
| Kerr |
100000 |
For each record, the variable worker_db.d.salary is evaluated
and the records ordered accordingly.
|
|
Tip: Remember to put curly brackets, '{' and '}', around
index key expressions. |
|
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.
Flags
The FLAGS attribute lets you supply further instructions
for creating the index file.
- ascending (default): By default, indexed records are
arranged in ascending order, with lowest key values at the beginning
of the index. For CHAR keys, 'A' is first; for NUMBER keys, the
lowest numbers are first; and for DATE keys, the earliest date
is first.
Within an index having a key expression of type CHAR, records
are not ordered alphabetically, but rather according to the
ASCII codes of the characters in the key. Therefore 'A' through
'Z' precede 'a' through 'z'.
- descending: the reverse of ascending.
- unique: Allows only one record containing the results
of the key expression to be stored in the index file.
- nounique (default): all records containing the results
of the key expression will be indexed, whether the key fields
are unique or not. For write operations unlike the one in the
code example above, where the "unique" flag is not
set, no record will be excluded from being written to the database.
- string: force string (rather than numeric) comparisons
of key expressions when ordering the index.
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.
|
|
Tip: Because <MvMAKEINDEX> can be quite resource-intensive
for large databases, and does not automatically lock the database
and index files that it uses, it should be used off-line,
with Miva Mia. You can then re-install your database on your
server. If you do create the index on-line, you should use
<MvLOCKFILE> to request a
lock on the database and index files while <MvMAKEINDEX>
is executing. |
|
Summary
<MvSETINDEX
NAME="db_alias"
INDEXES="f1.mvx,f2.mvx,...">
The specified index files become the index files for the
database opened with alias db_alias. If NAME
is omitted, the index files are opened for the primary database.
The first file listed becomes the main index for the database.
<MvSETINDEX> closes any open index files for this database
before opening the specified index files. The record pointer
moves to the first record in the database (in indexed order)
after <MvSETINDEX> is executed. <MvSETINDEX> is
an empty tag.
|
<MvOPEN> and <MvMAKEINDEX>
will also open listed index files for the specified or primary database.
Summary
<MvREINDEX
NAME="db_alias">
<MvREINDEX> recreates all open index files for the
database with alias db_alias, updating them to reflect
the current contents of the database. If NAME is omitted,
the index files for the primary database are recreated. Use
<MvREINDEX> to incorporate all changes made to the database
into the open index file(s), if they were not open when the
database was updated. <MvREINDEX> is an empty
tag.
|
|
|
Tip: Because <MvREINDEX> can be quite resource-intensive
for large databases, and does not automatically lock the database
and index files that it uses, it should be used off-line,
with Miva Mia. You can then re-install your database on your
server. If you do re-create the index on-line, you should
use <MvLOCKFILE> to request
a lock on the database and index files while <MvREINDEX>
is executing. |
|
This 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.
Summary
<MvFIND
NAME="db_alias"
VALUE="search_value"
EXACT="EXACT">
<MvFIND> performs a case-sensitive search for
search_value in the index of the database with alias
db_alias, and moves the record pointer to the first
matching record in the database. If NAME is omitted,
the primary database's index will be searched. To succeed,
the search must match starting at the first character in the
indexed value. The first record found by <MvFIND> will
differ depending on which index is the controlling index.
At least one index must be open for the database being
searched. <MvFIND> is an empty tag.
If the EXACT flag is set, the search will succeed only if
search_value matches the entire indexed value, rather
than just a substring starting at the first character. When
searching for a number, set the EXACT flag.
|
<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>
|
|
Tip: To check whether an <MvFIND> was successful,
test the value of the variable db_alias.d.eof (you
can use d.eof or eof for the primary database);
if it has the value 1 (true), the end of the database file
was reached, and the search was unsuccessful. After an unsuccessful
<MvFIND>, the record pointer points at the first record
in the index. You can also test the value of the variable
mvfind_error; it will have the
value 'EOF' if the <MvFIND> did not succeed, and null
otherwise. |
|
|
|
Tip: <MvFIND> is always case-sensitive. If you
want to do a case-insensitive search, you can create an index
whose key expression converts all values to uppercase or lowercase,
and then search using values in the desired case. The built-in
string functions toupper and tolower will
help you do case conversion. |
|
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 <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.
Summary
<MvFILTER
NAME="db_alias"
FILTER="{expression}">
Makes all records in the database with alias db_alias
that do not match the filter condition expression invisible
to <MvFIND>, <MvSKIP>,
and other database navigation tags; these tags will then find
only the records that match both their own search condition
and the filter condition. If NAME is omitted,
the specified filter applies to the primary database.
If you have several open database aliases, each one can have
a filter associated with it. However, a single alias can have
only one filter applied to it at a time; a subsequent <MvFILTER>
referring to that alias will replace the current filter. To
remove a filter and not replace it, omit the FILTER
attribute. (If both NAME and FILTER are omitted,
the current filter for the primary database will be
removed.)
<MvFILTER> is an empty tag.
The variables totrec and recno will continue
to refer to the complete, unfiltered database.
|
If you want to find a series of records that all match a certain
criterion, you have two basic options:
- Create an index sorted on whatever
field(s) have the value you want to find, use <MvFIND>
to locate the first record that matches your criterion, then use
<MvWHILE> (using the same criterion
that you used with <MvFIND>) to loop through the database
records until you've read all the matching records.
- If the value you want to find does not match at the beginning
of a field value (it might appear anywhere in the field), you
can use <MvFILTER>.
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:
| Name |
Title |
Salary |
| Diamond |
Bottle Washer |
12000 |
| Novak |
Plongeur |
15000 |
| Maloney |
Dish Washer |
15000 |
| Barr |
Maitre d' |
35000 |
| Tchobanian |
Chief Cook |
40000 |
| Rabinovitch |
Window Washer |
45000 |
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:
| Name |
Title |
Salary |
| Diamond |
Bottle Washer |
12000 |
| Maloney |
Dish Washer |
15000 |
| Rabinovitch |
Window Washer |
45000 |
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.
|
|
Note: The variable recno cannot be used in a
filter expression. |
|
|
|
Note: The effect on the currently applied filter of
accessing a record that the filter does not apply to is undefined. |
|
Summary
<MvGO
NAME="db_alias"
ROW="row_number"
VIEW="odbc_db_view">
Moves the record pointer to the record whose position in
physical order is row_number, in the database
with alias db_alias, regardless of how the database
is indexed. If NAME is omitted, the record pointer
for the primary database is moved. The special values 'top'
and 'bottom' for row_number move the record pointer
to the first and last database record, respectively. <MvGO>
is an empty tag.
|
|
Note: In general, the ROW value specified with
<MvGO> refers to the row number in physical order, not
indexed order. There are two exceptions to this: if the database
is indexed, the special values 'top' and 'bottom' will move
the record pointer to the first and last records in indexed
order. It follows from this that 'top' and 'bottom' do
not move the record pointer to the physical top and bottom
of an indexed database. In this situation, you can
achieve the same effect via the following:
<MvGO ROW="1">
<MvGO ROW="{totrec}">
|
|
|
|
Note: <MvGO> is supported for ODBC databases.
A value for the VIEW attribute is not required when
working with non-ODBC databases. |
|
Summary
<MvSKIP
NAME="db_alias"
ROWS="number"
VIEW="odbc_db_view">
<MvSKIP> moves the record pointer of the database
with alias db_alias a specific number of records
forward or backward relative to its current position. If NAME
is omitted, the record pointer for the primary database is
moved. If the database is not indexed, the pointer moves according
to physical record number. If the database is indexed, the
pointer moves according to the order in which records are
indexed. If ROWS is omitted, the pointer moves one
record forward. If ROWS is negative, the pointer moves
backward. <MvSKIP> is typically used for constructing
loops to sequentially access file records. <MvSKIP>
is an empty tag.
|
|
|
Note: <MvSKIP> is supported for ODBC
databases. A value for the VIEW attribute is not required
when working with non-ODBC databases. |
|
Summary
<MvREVEALSTRUCTURE
NAME="db_alias"
DATABASE="filename">
<MvREVEALSTRUCTURE> creates a database with filename
filename (required) that contains information about
the structure (as defined by <MvCREATE>)
of the source database with alias db_alias. If NAME
is omitted, the primary database is assumed. The newly created
database contains one record for each field in the source
database. The source database must be open when <MvREVEALSTRUCTURE>
is executed. <MvREVEALSTRUCTURE> is an empty
tag.
|
<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:
- field_name: The name of a field in the source database.
- field_type - A letter that specifies the type of field:
- C - Character data (CHAR)
- N - Numeric data (NUMBER)
- D - Date (DATE)
- L - Boolean data (BOOL)
- M - Memo data (MEMO)
- field_len - The number of characters allowed in the field;
for CHAR fields, this is the number of characters specified in
the field definition; for NUMBER fields, this is the sum of the
number of characters before and after the decimal, plus 1 (for
the decimal); the other types of fields have fixed values for
field_len: 8 for DATE, 1 for BOOL, and 10 for MEMO.
- field_dec - For numeric data only, the number of decimal
places allowed to the right of the decimal point.
Miva Script access to ODBC datasources is currently supported only
with Miva Mia.
Summary
<MvOPEN
NAME="db_alias"
TYPE="odbc"
DATABASE="odbc_connection_string">
Connects to an ODBC datasource. The value for the DATABASE
attribute is an ODBC connection string. For example:
DSN=Sample;UID=dba;PWD=sqlpwd
This string will connect to an ODBC datasource called 'Sample',
using the user id 'dba' and the password 'sqlpwd'. Some ODBC
drivers may allow or require additional values.
|
Miva 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.
<MvQUERY
NAME="db_alias"
QUERY="SQL query">
<MvQUERY> runs an SQL query that does not return
any results, such as an update, delete, or insert. QUERY
is required. If NAME is omitted, the query applies
to the primary database (this must be an ODBC datasource).
<MvQUERY> is an empty tag.
|
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.
<MvOPENVIEW
NAME="db_alias"
VIEW="viewname"
QUERY="sqlquery">
<MvSKIP VIEW="viewname" ...>
<MvGO VIEW="viewname" ...>
<MvCLOSEVIEW
NAME="db_alias"
VIEW="viewname">
<MvOPENVIEW> opens a view viewname based on
the results of the query sqlquery. <MvSKIP>
and <MvGO> can be used to navigate
the view. <MvCLOSEVIEW> closes the view. <MvOPENVIEW>
and <MvCLOSEVIEW> are empty tags.
|
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:
- <MvSKIP>
- <MvGO>
- <MvPRIMARY>
- <MvFIND>
- <MvSETINDEX>
- <MvUPDATE>
- <MvDELETE>
- <MvUNDELETE>
- <MvADD>
- <MvREVEALSTRUCTURE>
Summary
<MvCOMMERCE
ACTION="url_to_commerce_server"
METHOD="access_method"
FIELDS="value1,value2,...">
...
...<MvCOMMERCESTOP>...
...
</MvCOMMERCE>
The <MvCOMMERCE> tag facilitates Internet commerce
by providing an interface for accessing commerce servers.
- ACTION - The URL for the destination server. (optional)
- METHOD (required) - Identifies the method you are using to contact the server
(that is, the type of service you are requesting). Define the METHOD to match the
one you have (or will) registered in the Miva Engine.
- FIELDS - List of variables that contains the data to be sent to the commerce library.
<MvCOMMERCE> can loop more than one time. It will continue to loop until it no longer receives
data, or until it is explicitly halted with the tag.
The commerce library performs its functions and passes the data back to the Miva Script application.
The output from the commerce library is a binary tree that allows the library to make results available to a Miva Script application.
|
A 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_init
- miva_commerce_loop
- miva_commerce_cleanup
- miva_commerce_error
All communication from a Miva commerce library to the Miva Script application is through these
four exported functions.
This 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
- context -- a handle to Miva_Context.
- data -- a placeholder that allows a commerce library to allocate and store instance-specific data.
Any value, which you assign to the data parameter, is passed to any subsequent calls to the commerce library.
- method -- the value of the METHOD attribute that was specified in the <MvCOMMERCE> tag.
- action -- the value of the ACTION attribute that was specified in the <MvCOMMERCE> tag.
- input -- a handle to a Miva_VariableList containing all the variables specified in the FIELDS parameter
of the <MvCOMMERCE> tag.
- output -- a handle to a Miva_VariableTree which is used by the commerce library to return values to the module.
All variables
added to this tree are made available to the module in the form of system variables, which are available only
inside the <MvCOMMERCE> block.
Return Value
- MIVA_COMMERCE_OK - successful, then proceeds with executing the code inside the <MvCOMMERCE> block.
- MIVA_COMMERCE_ERROR - one of more errors were encountered and the Miva Engine calls miva_commerce_error.
When 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
- context -- a handle to Miva_Context
- data -- a placeholder that was passed to miva_commerce_init. If you assigned a value to it there,
it will have the same value here.
- method -- the value of the METHOD attribute that was specified in the <MvCOMMERCE> tag.
- action -- the value of the ACTION attribute that was specified in the <MvCOMMERCE> tag.
input a handle to a Miva_VariableList containing all the variables specified in the FIELDS parameter
of the <MvCOMMERCE> tag.
- output -- a handle to a Miva_VariableTree which is used by the commerce library to return values
to the module. All variables added to this tree are made available to the module in the form of system
variables only inside the <MvCOMMERCE> block.
- iteration -- the number of times Miva has executed the code inside the <MvCOMMERCE> block. The
first time miva_commerce_loop is called, iteration has a value of 0.
Return Value
The action that the Miva Engine takes is dependent on the return value of the miva_commerce_loop.
- MIVA_COMMERCE_OK -- the engine will proceed to execute the code inside the <MvCOMMERCE> block.
- MIVA_COMMERCE_ERROR -- one of more errors were encountered and the Miva Engine calls miva_commerce_error.
- MIVA_COMMERCE_END -- the engine will exit the commerce block normally (you would normally return
MIVA_COMMERCE_END when your commerce library functions are complete and should stop).
Whenever 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
- context a handle to Miva_Context. Your commerce library will need this handle to use the networking and
file functions provided by the Commerce API.
data a placeholder that was passed to miva_commerce_init. If you assigned a value to it there, it will
have the same value here.
- method the value of the METHOD attribute that was specified in the <MvCOMMERCE> tag.
- action the value of the ACTION attribute that was specified in the <MvCOMMERCE> tag.
input a handle to a Miva_VariableList containing all the variables specified in the FIELDS parameter of the
<MvCOMMERCE> tag.
Return Value
No return value.
If 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
- context -- a handle to Miva_Context. Your commerce library will need this handle to use the
networking and file functions provided by the Commerce API.
- data -- a placeholder that was passed to miva_commerce_init. If you assigned a value to it
there, it will have the same value here.
- method -- the value of the METHOD attribute that was specified in the <MvCOMMERCE> tag.
- action -- the value of the ACTION attribute that was specified in the <MvCOMMERCE> tag.
- input -- a handle to a Miva_VariableList containing all the variables specified in the FIELDS
parameter of the <MvCOMMERCE> tag.
Return Value
The text for the error is returned.
<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.
|
|
Note: Quick Cost can calculate costs only for shipments
that originate in the United States. |
|
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:
- Create a form that contains fields for each input
variable (that is, each type of information) that you want
to send to the Quick Cost calculator. Some variables are required;
others are optional.
- The name (NAME attribute) of each field must be the
same as the corresponding variable name.
- Choose form objects that are appropriate to the type of
data: for example, check boxes for yes/no choices, text boxes
for text, and radio buttons or drop-down lists for choices
from a defined group.
- Set the form's ACTION attribute to point to the Miva
Script program containing the <MvCOMMERCE> tag. If it's
the same as the script containing the form, just use the macro
&[documenturl]; as the value of ACTION.
- Set the form's METHOD attribute to 'POST'.
- Include each of the input variables from the form in the FIELDS
attribute of <MvCOMMERCE>. The order is unimportant, and
you need include only those variables that actually appear in
the form.
- Between the <MvCOMMERCE> and </MvCOMMERCE> tags,
insert code that processes the information sent back by the Quick
Cost calculator. The information is sent back in the output
variables listed below. You don't have to use all of these
variables in your code, just the ones you need. The processing
that you do can be as simple as just displaying values of certain
variables, or you can do more complex processing as desired. As
a minimum, you should probably display the cost (totalchrg),
or an error message (errmsg) if there is one.
This 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. The default value
for all variables in the list between 29_oversized and 45_SecondShipNotify
is '0' (zero); variables with value '0' do not have to be passed
explicitly. Contact UPS or consult their online
documentation for detailed definitions and service descriptions.
|
|
Note: Any variables that start with a number must be
prefixed with g. (global) or l. (local) if they
are used in a Miva Script expression. For example,
{g.25_length + g.26_width}. |
|
| Name |
Value |
| accept_UPS_license_agreement |
Must have the value
'yes' when the form is submitted. |
| 13_product |
UPS Product Code
corresponding to the type of shipment service desired. For example,
'1DA' for Next Day Air. A complete list of codes is available
from UPS's online documentation. |
| 10_action |
Set to '3' to obtain
information only for the service specified with 13_product,
or '4' to obtain information on all applicable services. |
| 15_origPostal |
The ZIP code of the
originating location (U.S. only) |
| 19_destPostal |
The ZIP or other
postal code of the destination location (all countries, as applicable). |
| 22_destCountry |
The 2-letter country
code of the destination country: for example, 'US' for the United
States, 'CA' for Canada, 'MX' for Mexico. Other codes are available
from UPS. |
| 23_weight |
Weight in pounds
(not required if the requested service is for letters only). |
| 24_value |
Value in dollars |
| 25_length |
Length in inches |
| 26_width |
Width in inches |
| 27_height |
Height in inches |
| 29_oversized |
'1' if the package
is oversized, '0' if it isn't. |
| 30_cod |
'1' if the shipment
is COD, '0' if it isn't. |
| 33_hazard |
'1' if the package
contains a hazardous material, '0' if it doesn't. |
| 34_handing |
'1' if the package
requires additional handling, '0' if it doesn't. |
| 35_calltag |
'1' for basic call
tag service, '2' for electronic, '0' for none. |
| 37_saturdaydelivery |
'1' for Saturday
delivery, '0' otherwise. |
| 38_saturdaypickup |
'1' for Saturday
pickup, '0' otherwise |
| 39_response |
'1', '2', '3', '4'
for various proof of delivery responses, '0' for none. |
| 43_vcd |
'1' for verbal confirmation
of delivery, '0' otherwise. |
| 44_FirstShipNotify |
First Ship Notification
Service: '1' for Domestic, '2' for International, '0' for none. |
| 45_SecondShipNotify |
Second Ship Notification.
'1' for Domestic, '2' for International, '0' for none. |
The following variables are available inside the <MvCOMMERCE>...</MvCOMMERCE>
block:
| Name |
Value |
| errmsg |
Description of error,
or NULL if no error occurred |
| errorcode |
Numeric code of error,
or NULL if no error occurred |
| message |
Informational message |
| product |
UPS product code |
| orig_postal |
Shipment source postal
code |
| orig_country |
Shipment source country
code |
| dest_postal |
Shipment destination
postal code |
| dest_country |
Shipment destination
country code |
| zone |
UPS shipping zone |
| weight |
Shipment weight |
| productchrg |
Shipment charge,
minus any accessory or surcharges |
| accs_surcharg |
Shipment accessory
or surcharges |
| totalchrg |
Total cost of shipment
|
| time |
Commit time, or -1
if end of day |
Example
The 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 calculation</TITLE>
</HEAD>
<BODY>
<MvIF EXPR="{g.accept_UPS_license_agreement EQ 'yes'}">
<MvCOMMENT>This branch is executed if the form has been submitted.</MvCOMMENT>
<MvCOMMERCE
METHOD="UPSCost"
ACTION="http://www.ups.com/using/services/rave/qcostcgi.cgi"
FIELDS="accept_UPS_license_agreement,10_action,
13_product,15_origPostal,19_destPostal,22_destCountry,
23_weight">
<MvIF EXPR="{ s.errmsg }">
Error: <MvEVAL EXPR="{ s.errmsg }"><BR>
<MvCOMMERCESTOP>
<MvELSE>
Message: <MvEVAL EXPR="{s.message}"><BR>
Product: <MvEVAL EXPR="{ s.product }"><BR>
Total Charge: <MvEVAL EXPR="{ s.totalchrg }"><BR>
</MvIF>
</MvCOMMERCE>
<MvELSE>
<MvCOMMENT>This branch is executed if the form has NOT yet been submitted.</MvCOMMENT>
<FORM ACTION="&[s.documenturl];" METHOD="POST">
<P>Accept license agreement?:
<INPUT
TYPE="CHECKBOX"
NAME="accept_UPS_license_agreement"
VALUE="yes" CHECKED="CHECKED">
</P>
<P><INPUT TYPE="HIDDEN" NAME="10_action" VALUE="3"></P>
<P>Product code: <INPUT TYPE="TEXT" NAME="13_product"></P>
<P>Ship from: <INPUT TYPE="TEXT" NAME="15_origpostal"></P>
<P>Ship to: <INPUT TYPE="TEXT" NAME="19_destPostal"></P>
<P>Dest country: <INPUT TYPE="TEXT" NAME="22_destCountry"></P>
<P>Weight: <INPUT TYPE="TEXT" NAME="23_weight"></P>
<P><INPUT TYPE="SUBMIT" NAME="Submit1"></P>
</FORM>
</MvIF>
</BODY>
</HTML>
The <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 overview
The 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-enabled
Before you can develop scripts that access ICS, several preparations
must be made. Most importantly:
- A merchant account must be set up with your company's bank.
In order to use CyberSource's ICS Services, your bank must one
that handles 'Card Not Present' (CNP) or 'mail-order/telephone-order'
(MOTO) transactions. If your bank cannot process these types of
credit card transactions with your account, you may want to select
from the list of banks and financial institutions that are already
familiar with the CyberSource processing gateways.
- Basic information about products offered for sale must be available
to you and be delivered to CyberSource. Some of this information
is also described in the Product description (digital offer).
- Your company must have subscribed for services with CyberSource.
You can subscribe to any combination of the services described
in this document.
- Your product-ordering Web pages must be created.
Setting up ICS-processing scripts
The steps for setting up ICS processing in your scripts are as
follows:
- Create an <MvCOMMERCE> tag
(described below) that defines the SCMP message that you want
to send.
- Typically, some of the information contained in the <MvCOMMERCE>
tag will be predefined in your program (for example, the merchant
identification) while other information (such as the customer
name) will be gathered when the program is executed. You will
need to create a mechanism (typically an HTML form) that will
gather the second type of information.
- All the required information must be sent to the program containing
the <MvCOMMERCE> tag, typically through a form submission.
When the <MvCOMMERCE> tag is executed, it sends the message
to the ICS server. The ICS server reorders the requested list
as appropriate and checks the list against the list of services
authorized for the requesting merchant.
If the list is valid, the ICS server performs the services
and returns the results for all services to your program. These
results are available to your program as Miva Script variables.
- Place code between the <MvCOMMERCE> and </MvCOMMERCE>
tags that checks the results returned by the ICS server for status
and information.
- Test your scripts.
To 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:
- ACTION - URL for the CyberSource ICS server that you
are requesting services from. By default, all messages are sent
to the
ics.ic3.com ICS server. Do not change this
unless directed to do so by CyberSource.
- METHOD - Identifies how you are contacting the ICS server.
Use 'SCMP' (Simple Commerce Messaging Protocol) to request ICS
services.
- FIELDS - Contains the list of fields that make up the
SCMP message that you are sending for processing. Information
about the services being requested, the merchant requesting the
services, and the end user (customer) is sent in the message as
a set of values for the list of fields.
<MvCOMMERCE ACTION="http://ics.ic3.com"
METHOD="SCMP"
FIELDS="ics_svcs,
ics_merchant,
firstname,lastname,email,phone,address1,city,state,zip,
country,ccnum,expmo,expyr,
offer0,offer1,...,offerN">
...code...
...code...
...code...
</MvCOMMERCE>
Each of the components of FIELDS is a Miva Script variable.
These variables specify four types of information.
The ics_merchant variable contains the name of your company's
encryption key.
The 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):