The Meta-HTML Reference Manual
Brian J. Fox, Universal Access Inc.
_________________________________________________________________
Warning for WML Users
The wml_p2_mhc program is a stripped down version of the mhc program
from Meta-HTML. Because lots of functionalities have been removed from
the original Meta-HTML, this documentation may refer to non-existing
features. Only variables and functions listed in index are relevant.
By reading this guide, keep in mind it is a Meta-HTML reference
manual. It may be used as a reference guide for wml_p2_mhc, and
instructions on how to define new tags can be found into
wml_tutorial(1) and wml_intro(1).
Denis Barbier
Welcome To Meta-HTML
This document describes the Meta-HTML language, Version 6.05. It
should be considered the definitive reference manual for this version
of the language, but the language target itself remains somewhat
mobile. While the functions described in this manual will continue to
operate as documented, there may be new functions or enhancements
appearing in future versions of the language which will supersede the
functionality that the documented ones provide.
If you are really impatient, or you fancy yourself a wizard, I suggest
that you first look at the code examples at
http://www.metahtml.com/examples.
Comments and/or suggestions for improvement on this manual, the
language definition, or writing style(!!) should be sent to
[email protected].
Although World Wide Web use of the Internet has been growing at a
phenomenal rate over the past 3 years, there remains a dearth of
interesting and useful client/server applications. Traditional
programming languages do not provide an optimal environment for
programming such applications because of the syntactical and
paradigmatic distance between traditional languages and the target
output, namely HTML.
The stateless and dynamic nature of the WWW requires a level of
support from traditional programming languages which they are hard
pressed to provide. Must each application programmer write his or her
own tool set to accomplish goals which are fundamentally similar
across applications?
Meta-HTML presents an alternative language choice for the design and
implementation of Web applications, and supplies three methods of
delivering the language.
The Purpose of Meta-HTML
HTML is a description layout language. It describes in general the
placement and visual style of elements in a page. These elements are
generally sequences of text, with an occasional image thrown in for
good measure.
Meta-HTML<sup>TM</sup> is an interpreted computer language with
dynamic variables and flow-control statements. Although it is not a
complete general purpose computer language in the traditional sense
(i.e., you cannot write a version of a Meta-HTML interpreter in
Meta-HTML) it does perform processing and decision making of and on
data elements.
A quick example for the impatient is in order. The text:
You are connected to "" and reading text written by .
is produced in Meta-HTML by:
<b>You are connected to "<get-var ENV::SERVER_NAME>" and
reading text written by <get-var the-author>.</b>
As the WWW grows, more and more document providers are realizing that
stateless connections are only useful for retrieving documents full of
static information, and that, at times, it can be very useful to
remember state pertaining to the browser that is connecting.
The problem of keeping state for a particular browser user has been
resolved by various individuals; all of the solutions require
information to be passed back and forth between the browser and the
server. For example, to play a WWW Blackjack game could involve the
passing back and forth of information including the current
wins/losses of the user, which cards have been dealt from the deck so
far, and so forth. This information is most often passed to and fro in
the form of a "magic" URL. The problems with passing information in
this way are two-fold:
1. The information can be modified by the user before sending it
back, which might allow a user to put more money in his or her
bank account, for example, and, less importantly,
2. The URL looks "ugly", since there is a large amount of information
present which doesn't describe the essence of the location that
the user is connecting to.
Another mechanism can be taken advantage of when both the server and
browser being used support HTTP Cookies. While this solves the problem
of "ugly" URLs, (this mechanism does not place information in the URL)
it generates a new problem: the user must be in possession of a
compliant browser, and be communicating with a compliant server. In
addition, the information can be changed by the user before sending it
back.
Meta-HTML solves the problem of keeping state for a particular
session, and it does it in a server and browser independent manner.
Our method requires no additional CGI programs to be written. You can
read about the technical details in the Session Operators (not
included in this document) section of this manual.
Implementation Design
Initially, the vast majority of World Wide Web (WWW) documents
consisted of static pages of text and images, which were described
using HTML, and displayed using a browser which understood only the
HTML language. The nature of a WWW connection is stateless by
definition; each request for information is not associated in any way
with any previous request for information, even when from the same
source.
Connections are made from a browser to a WWW server, in which the
browser requests a particular item of data by specifying a Universal
Resource Locator (URL). The server looks up the URL, and then returns
the data contained within. While most URLs are static HTML documents,
there exists a mechanism in which a program can be run. The output of
such a program is an HTML document, and such programs are referred to
as Common Gateway Interface, or CGI programs.
Meta-HTML is currently implemented as a CGI program which can be
executed every time the server is ready to retrieve a document. As
before, the document to be retrieved can be a file of HTML, an image,
or a CGI program to be executed. However, the document can also be a
file of Meta-HTML code, in which case the benefits of dynamic
variables and flow-control statements are fully realized.
Although this implementation method is not server-specific, you still
must make a couple of configuration changes to your HTTP server in
order to hide the Meta-HTML program from the user. Details are in the
Installation Guide.
Language Syntax
A Meta-HTML document consists of plain text, HTML directives, and
Meta-HTML statements.
The syntax of the Meta-HTML language was designed to be as similar to
HTML as possible, so as to not sacrifice readability of the total
document. All of the Meta-HTML statements are delivered as a form of
HTML tags. There are two types of Meta-HTML tags: simple and complex.
A simple tag begins with an open angle bracket (<) and ends with a
corresponding close angle bracket (>). The text enclosed within the
brackets is called the body; it can contain assigned variables and
positional arguments.
A complex tag begins with what looks exactly like a simple tag,
continues throughout the body of the text, and ends with the a
matching closing tag. This is analogous to the use of tags within
HTML. The body of a complex tag is all of the text which appears
between the opening tag and the closing tag, exclusive of those tags
themselves.
Here is an example of using the simple tag set-var:
<set-var foo=bar>
Here is an example of using the complex tag when:
<when <get-var foo>>
The value of `foo' is <get-var foo>.
</when>
Note that both the set-var and when forms have opening tags which
contain additional material. This material is used to supply
information to the form.
Additionally note that "simple" and "complex" do not refer to the
complexity of the function performed; they simply refer to the syntax
used to write the form in a document. For example, the simple tag
var-case performs a complex operation based upon the arguments it is
given.
Variables assigned in the opening (or simple) tag have the form:
name=value
This gives the variable referred to as name a local value of value.
Variable assignments such as these give the Meta-HTML writer a way to
pass dynamic arguments to a function. For example, the
with-open-database form can open the requested database in one of 3
modes; you control which one by locally assigning the variable mode
within the form:
<with-open-database db "/phones.db" mode=<get-var db-mode>>
...
</with-open-database>
Quoting Syntax
At times, you will need to quote the expressions that you pass to
various Meta-HTML functions. You do this with double quotes (") and
blackslashes (. Here is a somewhat hairy example of quoting:
<if <get-var "Space Name">
<get-var "Space Name[space index]">
<set-var space-name-present=false>>
For most cases, quoting is unnecessary, because open braces are
expected to match close braces, and doubles quotes are expected to
come in pairs. This is the usual case. For example:
<ifeq <get-var foo[index]> <get-var bar>
<set-var array[index]=<get-var bar>-found>
<set-var array[index]=<get-var bar>-missing>>
In the above example, no quoting was required because the only
whitespace which appeared in the expression was within a set of
matched braces.
Essential Language Features
Variables
Meta-HTML provides a simple mechanism for the storage and retrieval of
variables during a single (possibly recursive) processing pass. In
addition to this, functions are provided which test the value of a
variable, and conditionally execute other code based upon the result.
There is also a mechanism to group a set of variables using See
section Packages.
Variable Types and Information
There are internal functions in Meta-HTML which create binary
variables. Such variables cannot be used in the ordinary way, since
the data contained within them may not retain integrity once printed
out and read back in. You can check to see what the type of a
particular variable is with the symbol-info function.
Many variables are predefined by Meta-HTML, and made available to the
page writer. The Page Variables (not included in this document)
section of this manual documents those variables fully, while the
Server Variables (not included in this document) section contains more
information on variables which control, or were specifically created
by, the web server.
Simple Tag: alist? string
Return "t" if string is a representation of an association
list.
Simple Tag: coerce-var varname &key [type=(STRING|BINARY|ARRAY)]
Coerces varname's data to have the type specified by the
argument to type. You can convert a binary object to a string
object, and vice-versa.
A binary variable might be created as the result of a call to
stream-get-contents, for example. Once the data is read, you
might wish to perform some substitutions on it, or otherwise
get its value. To do so, you call coerce-var on the value:
<with-open-stream s /tmp/file mode=read>
<stream-get-contents s foo>
</with-open-stream>
<coerce-var foo type=string>
<subst-in-string <get-var foo> "Hello" "Goodbye">
<get-var foo>
Simple Tag: copy-var from-var &optional [to-var...]
Copies the variable from-var to each of the named to-vars.
Each to-var becomes the repository of a copy of the information
already stored under from-var. This is a true copy; not an
alias to the original variable.
<set-var foo=bar>
<get-var foo> ==> bar
<get-var new> ==>
<copy-var foo new> ==>
<get-var new> ==> bar
<copy-var *meta-html*::get-var *meta-html*::foo>
<foo new> ==> bar
Simple Tag: decrement name &key [by=amount]
Subtract amount (default 1) from the contents of the variable
named by varname.
<set-var foo=1>
<get-var foo> ==> 1
<decrement foo>
<get-var foo> ==> 0
Also see increment.
Simple Tag: defvar name value
DEFault the value of the VARiable named by name to value.
defvar assigns value to name if, and only if, name has a
non-empty value.
defvar could have been defined in Meta-HTML using define-tag:
<define-tag defvar var val>
<if <not <get-var var>> <set-var <get-var var>=<get-var val>>>
</define-tag>
Simple Tag: get-var &optional [name...]
Return the value of the names given. Each name is a variable
name which has had a value assigned to it with set-var,
set-var-readonly, or was created implicity via
alist-to-package or coerce-var.
The values are returned in the order in which the names appear.
Examples:
<set-var foo=Var-1 bar=Var-2>
<get-var foo>, <get-var bar>
produces
Var-1, Var-2
When multiple names are given:
<get-var foo bar foo>
produces
Var-1Var-2Var-1
Simple Tag: get-var-once &optional [name...]
Returns the current value of the variables named by the names
given. The interpreter pointer is then moved to after the
returned data, thus preventing further interpretation of the
data.
Example:
<set-var bar=HELLO>
<set-var-verbatim foo=<get-var bar>>
<get-var-once foo> ==> <get-var bar>
but...
<get-var foo> ==> HELLO
Simple Tag: increment name &key [by=amount]
Add amount (default 1) to the contents of the variable named by
varname.
<set-var foo=1>
<get-var foo> ==> 1
<increment foo>
<get-var foo> ==> 2
Also see decrement.
Simple Tag: set-var &optional [name=value...]
Gives the variable name the value of value for the current
processing run. Any number of name/value pairs may be given,
and whitespace is not significant. Where =value is omitted, the
value is the empty string.
<set-var foo=bar bar=baz>
<get-var foo> ==> bar
<get-var bar> ==> baz
<get-var <get-var foo>> ==> baz
Simple Tag: set-var-readonly &optional [name=value...]
For each name specified, if that name is not already assigned a
value with set-var-readonly, assigns the associated value to
it, exactly in the way that set-var would.
Once name has had a value assigned to it with set-var-readonly,
then that variable is immutable, i.e., its value cannot be
changed using any Meta-HTML commands.
A useful construct for setting various site specific variables
in your engine.conf or mhttpd.conf file, this allows one to
create globally defined variables which cannot be changed by
the execution of Meta-HTML statements in a page.
Variables which can usefully benefit from this type of setting
include mhtml::include-prefix and mhtml::relative-prefix among
others.
Simple Tag: set-var-verbatim &optional [name=value...]
Gives the variable name the value of value for the current
processing run. The difference between set-var-verbatim and
set-var is that in set-var-verbatim the right-hand side of
assignments are not evaluated.
Example:
<set-var-verbatim foo=<get-var bar>>
<get-var-once foo>
produces
Var-2
Simple Tag: symbol-info symbol
Returns information about the symbol symbol.
The information is two lines:
+ The type of the symbol, which is one of:
1. STRING,
2. BINARY,
3. USER DEFUN,
4. USER SUBST,
5. USER MACRO,
6. PRIM DEFUN, or
7. PRIM MACRO.
+ The "size" of the symbol.
For STRING. variables, the size value is the number of elements
in the array.
For BINARY variables, the size value is the number of bytes of
binary data stored within.
The size value is zero for all other variable types.
Simple Tag: unset-var &optional [name...]
Make names be non-existent in the page environment.
This is different than <set-var foo=""> because the variable
actually ceases to exist, rather than is given no value.
Example:
<set-var foo="">
<var-exists foo> ==> true
<get-var foo> ==>
<unset-var foo>
<var-exists foo> ==>
Simple Tag: var-exists name
var-exists checks for the existence of the variable named by
varname, and returns true if that variable exists.
The existence of a variable has nothing to do with its value --
a variable exists if it has been created with set-var, and
doesn't exist after it has been unset with unset-var.
<set-var foo=1 bar>
<var-exists foo> ==> true
<var-exists bar> ==> true
<get-var bar> ==>
<unset-var foo>
<var-exists foo> ==>
Arrays
Meta-HTML allows the use of array variables as well as single element
variables. In fact, all string variables in Meta-HTML can be treated
as array variables -- there is no special command for creating such
variables. Array variable values are referenced by placing the array
index directly after the variable name, enclosed in square brackets ([
and ]). Thus, a reference to the 3rd element of the array foo looks
like:
foo[3]
When an array reference is made without any containing index, the
reference refers to the entire array. So, to get the value of the
entire array stored in foo, you would write:
<get-var foo[]>
In order to ease the writing of array references which rely on a
variable index, a variable name seen as an array reference index is
automatically looked up as if you had written <get-var VAR>. Finally,
multiple values may be given in a set-var command by separating those
values with newline characters. The following sequence of commands
illustrates the typical use of array variables.
<set-var array[] =
"value-zero
value-one
value-two
value-three">
<set-var i=0>
<while <get-var array[i]>>
The value of array[<get-var i>] is `<get-var array[i]>'.<br>
<increment i>
</while>
produces
The value of array[0] is `value-zero'.
The value of array[1] is `value-one'.
The value of array[2] is `value-two'.
The value of array[3] is `value-three'.
Simple Tag: array-add-unique item arrayvar &key [caseless=true]
Add item as the last array element of the contents of arrayvar
if, and only if, item is not already a member of that array.
The comparison is a direct string-wise compare. If CASELESS is
non-empty, then a caseless string compare is done.
See also array-append.
Simple Tag: array-append item arrayvar
Add item as the last array element of the contents of arrayvar.
This is especially useful in conjunction with foreach as a
collector:
<foreach name allnames>
<if <satifies-criteria <get-var name>>
<array-append <get-var name> useful-names>>
</foreach>
See also array-add-unique.
Simple Tag: array-concat receiver &optional [contributor...]
Appends the contents of each contributor array to the end of
receiver.
Both receiver and each contributor are variable names whose
values are treated as arrays.
For a single contributor, array-concat could have been defined
as:
<defsubst array-concat>
<foreach item %1>
<array-append <get-var item> %0>
</foreach>
</defsubst>
Simple Tag: array-member item arrayvar &key [caseless=true]
Look up (and return) the index of item in the contents of the
array referenced by arrayvar.
If item is not found, then array-member returns the empty
string.
If caseless is non-empty, then the comparison is done without
regard to character case. Otherwise, character case is
significant in the location of the item.
<set-var array[] =
<prog
this
another
multi word
thing>>
<array-member "multi word" array>
produces
2
Simple Tag: array-shift amount arrayvar &key [start]
Shift the elements of arrayvar the indicated amount.
If amount is negative, the elements are shifted down (i.e.
towards zero), with the lowest number elements being lost.
If amount is positive, the elements are shifted up, with no
loss at all -- instead empty elements are used to fill the
created space.
If the keyword argument start is present, it indicates the
zero-based offset from which to start shifting.
Given the array:
<set-var array[] =
<prog
0
1
2>>
then after executing <array-shift 2 array>, the array looks
like:
""
""
"0"
"1"
"2"
and, a subsequent execution of <array-shift -3 array> leaves
array:
"1"
"2"
Simple Tag: array-size arrayvar
Returns the number of elements in the array referenced by the
variable arrayvar.
Examples:
<set-var array[]="this">
<array-size array>
produces
1
and,
<array-shift 4 array>
<array-size array>
produces
5
Complex Tag: foreach elementvar arrayvar &key [start=x] [end=x]
[step=x] [iter=var] [no-copy=true]
Perform body with elementvar bound to successive memebers of
arrayvar, starting with the element at start (default 0), and
ending at end (default <array-size ARRAYVAR>), advancing by
step (default 1).
The foreach command is the basic array looping device in
Meta-HTML. It is guaranteed to iterate over each element that
you specify, whether that element is the empty string or not.
If no-copy=true is specified, the array is not copied before
iteration, so that changes that you make to the array take
place immediately, during the execution of the surrounding
<foreach>.
Starting with the simple array:
<set-var array[]="0000000000">
we can print out the odd numbers of this array by using values
for both start and step:
<foreach x array start=1 step=2> <get-var x>, </foreach>
produces
1, 3, 5, 7, 9,
or, we can produce a "countdown" with a negative value for
step:
<foreach x array step=-1> <get-var x>, </foreach> BOOM!
produces
9, 8, 7, 6, 5, 4, 3, 2, 1, 0, BOOM!
Simple Tag: sort arrayvar &optional [sort-fun] &key [caseless=true]
[sortorder=[ascending|descending]] [number=true]
Sort the contents of the array arrayvar.
The elements are sorted in place -- this function has no return
value.
If caseless=true is given, then the comparison of the elements
of the array is done without regards to case.
If sortorder=reverse is given, then the results are returned in
descending order, instead of ascending order. The default is to
order the elements in ascending order.
If numeric=true is given, then the elements of arrayvar are
treated as numeric entities, whether they are or not. The
default is to treat the elements as character strings, which
can have unexpected results when sorting numeric quantities
("11" is less then "2" when sorting alphabetically!)
Finally, you may supply a sorting function, whose name is
passed as sort-fun. This function will be called on each
element just before comparison, and the results of that
function will be used for the comparison instead of the element
itself. This allows you to create a collating sort, or to sort
on complex weighting features, or anything else that you can
conceive of.
Examples:
Given the array:
<set-var array[0] = 1
array[1] = 2
array[3] = 3
array[4] = 4
array[5] = 20>
then,
<sort array>
<foreach x array> <get-var x> </foreach>
produces
1 2 20 3 4
while
<sort array numeric=true>
<foreach x array> <get-var x> </foreach>
produces
1 2 3 4 20
Sorting strings:
<set-var array[]="a00000000000">
<sort array sortorder=descending>
<foreach x array> <get-var x> </foreach>
produces
f e d c b a F E D C B A
Without regards to case:
<sort array caseless=true>
<foreach x array> <get-var x> </foreach>
produces
a A b B c C d D e E f F
Finally, here is an example which sorts a list of words based
upon the percentage of vowels present in each word, using a
sort function which calculates that value for each string:
<defun vowel-percentage string>
<set-var x =
<subst-in-string <downcase <get-var string>> "([^aeiou])" "">>
<percent <string-length <get-var x>>
<string-length <get-var string>>>
</defun>
<set-var words[]=
<prog
Brian
Fox
sorts
elegant
strings
beautifully>>
<sort words vowel-percentage numeric=true sortorder=descending>
<foreach word words>
<get-var word> (<vowel-percentage <get-var word>>)<br>
</foreach>
produces
Brian (<percent 2
5>)
Fox (<percent 1
3>)
sorts (<percent 1
5>)
elegant (<percent 3
7>)
strings (<percent 1
7>)
beautifully (<percent 5
11>)
Packages
Packages are repositories which contain symbols and their values.
Each time a symbol is referenced, a package must first be found, and
then the symbol may be found within that package. You indicate which
package to look the symbol up in by supplying a package prefix. When
the prefix is not supplied, the symbol is looked up in the current
package.For example, a full reference to the symbol bar stored in the
foo package looks like:
FOO::BAR
There are very few commands specifically for dealing with packages,
because most of the operations are performed implicitly, rather than
explicitly. To create a package, simply give the package name as part
of the symbol, in the place where the symbol is normally used.
<set-var foo::bar = "Hello">
This has the effect of creating the package foo if it didn't already
exist.
The majority of the functions documented here perform package
maintenance, as opposed to variable manipulation. There are functions
for querying a package about its contens, for deleting an entire
package, for exporting and importing packages to and from sessions,
for copying the contents of packages, and for converting packages from
an internal representation to a printable representation, called an
alist.
Simple Tag: alist-defvar alistvar name value
DEFault the value of the VARiable named by name to value, in
the association list referenced by <alistvar>.
defvar assigns value to name if, and only if, name has a
non-empty value.
Simple Tag: alist-get-var alistvar &optional [name...]
Return the value of the names given from the association list
specified by alistvar. Each name is a variable name which has
had a value assigned to it with alist-set-var, or was created
implicity via alist-to-package.
The values are returned in the order in which the names appear.
Simple Tag: alist-package-delete alistvar &rest packages[]
For each variable in the association list within alistvar,
remove the variable from the association list if it is prefixed
with one of the specifed package names. For example, given that
the variable alist contained the alist:
(("FOO::BAR" . "bar") ("FOO::BAZ" . "baz") ("BAR::X" . "val"))
then calling:
<alist-package-delete alist foo>
<get-var-once alist>
produces:
(("BAR::X" . "val"))
Simple Tag: alist-package-names alistvar
Return a newline separated list of all of the packages which
are defined within the association list stored within alistvar.
Because the list is newline separated, the result can easily be
assigned to an array variable:
Simple Tag: alist-set-var alistvar &optional [name=value...]
Gives the variable name the value of value in the association
list specified by alistvar. Any number of name/value pairs may
be given, and whitespace is not significant. Where =value is
omitted, the value is the empty string.
<alist-set-var myalist foo=bar bar=baz>
<alist-get-var myalist foo> ==> bar
<alist-get-var myalist bar> ==> baz
<alist-get-var myalist <alist-get-var myalist foo>> ==> baz
Simple Tag: alist-to-package alist &optional [package]
Takes the textual list representation of a package, and creates
(or modifies) the package named by package-name.
alist-to-package is the inverse of the package-to-alist
function -- given an "alist" (short for `association list') you
can create a package, and vice-versa. The following expression
is one way to copy all of the variables from the package FOO
into the package BAR:
<alist-to-package <package-to-alist foo> bar>
Simple Tag: alist-unset-var alistvar &rest names...
Make names be non-existent in the association list specified by
alistvar.
Simple Tag: alist-var-exists alistvar name
var-exists checks for the existence of the variable named by
varname, in the association list specified by alistvar, and
returns true if that variable does in fact exist.
The existence of a variable has nothing to do with its value --
a variable exists if it is present within the list, whether or
not it has a value.
Complex Tag: in-package package-name
Evaluate body in an environment where variables which are not
specifically prefixed with a package name are looked up and
stored within package-name.
The special package name "local" creates an anonymous package
within which to work. The contents of local packages are only
accessible within the expressions surrounded by the in-package
operator.
Simple Tag: package-delete package-name...
Remove the definition of the packages named by package-names,
and all of the variables defined within them.
Simple Tag: package-names
Return a newline separated list of all of the named packages
which are currently defined. Because the list is newline
separated, the result can easily be assigned to an array
variable:
<set-var all-packages[]=<package-names>>
Simple Tag: package-to-alist &optional [package]
Returns a Lisp readable string containing the names and values
of the variables in package. If strip=true is supplied, the
package name is removed from the variables before placing them
in the list. See the following code sequence:
<set-var
foo::bar=baz
foo::array[0]=Elt-0
foo::array[1]=Elt-1>
The contents of Foo: <package-to-alist foo>
The stripped contents: <package-to-alist foo strip=true>
produces
The contents of Foo: (("FOO::BAR" . "baz")("FOO::ARRAY" "Elt-0" "Elt-1"))
The stripped contents: (("BAR" . "baz")("ARRAY" "Elt-0" "Elt-1"))
Simple Tag: package-vars &optional [package-name] &key [strip=true]
Returns a newline separated list of the fully qualified
variable names found in the package named by package-name, or
in the current package if package-name is not given. When
strip=true is supplied, the returned variable names have the
package prefix stripped off, making them not fully qualified.
The names are not returned in any significant order. Because
the list is newline separated, the results can easily be
assigned to an array variable:
<set-var foo::bar=baz>
<set-var foo::baz=bar>
<set-var names[]=<package-vars foo>>
<get-var names[1]>
produces
FOO::ARRAY
Complex Tag: with-local-package
Shorthand for <in-package local> <i>body</i> </in-package>
Flow Control
Meta-HTML contains commands for controlling which of a set of
statements will be executed, and for repetitive execution of a set of
statements.
Such commands constitute what is called flow control, since they tell
the Meta-HTML interpreter where or what the next statement to
interpret resides.
All of the flow control operators in Meta-HTML take a test and some
additional statements; the closest thing to a goto statement in
Meta-HTML is the redirect command.
Simple Tag: break
Unconditionally and immediately stop the execution of the
nearest surrounding while or foreach.
Example usage:
<while true>
<if <file-newer? <get-var foo.c> <get-var foo.o>>
<break>>
<process-chunk <get-var chunk-num>>
<increment chunk-num>
</while>
Simple Tag: concat &rest args
Concatenate all of the arguments given, creating a single token
with no intervening whitespace. This is quite useful for those
situations where intervening whitespace would look bad in the
output, but the input source would be unreadable without any.
For example:
<concat <textarea name=label rows=10 cols=40>
<get-var-once label>
</textarea>>
Simple Tag: group &rest args
Combine all of the material passed into a single Meta-HTML
statement. This is the primitive for grouping multiple
statements where only a single statement is expected.
Whitespace within the group is preserved, making this command
useful for assigning to array variables.
Some examples:
<set-var array[] =
<group this is element 0
this is element 1
this is element 2>>
<if <eq this that>
<group <h2> This is equal to That </h2>>
<group <h2> This is NOT equal to That </h2>>>
Although group is a primitive in Meta-HTML, it could have been
defined as:
<defsubst group>%body</defsubst>
Simple Tag: if test &optional [then] [else]
First test is evaluated. If the result does not contain only
whitespace characters the then clause is evaluated, otherwise,
the else clause is evaluated. Although Meta-HTML has the
relational operator or, you can efficiently test for the
presence of any of a group of variables with code similar to
the following:
<if <get-var foo bar>
"Either FOO or BAR is present"
"Neither FOO nor BAR is present">
Simple Tag: ifeq this that &optional [then] [else] &key
[caseless=true]
The this and that clauses are evaluated. If the results are
text-wise identical, then the then clause is evaluated,
otherwise, the else clause is evaluated. If caseless=true is
given, the text-wise comparison of the values is done with no
regard to upper and lower case distinctions.
Simple Tag: ifneq this that &optional [then] [else] &key
[caseless=true]
The this and that clauses are evaluated. If the results are not
text-wise identical, then the then clause is evaluated,
otherwise, the else clause is evaluated. If caseless=true is
given, the text-wise comparison of the values is done with no
regard to upper and lower case distinctions.
Variable: mhtml::iteration-limit
The use of this variable has been deprecated. while loops last
until either the test-clause is met, or a break statement is
seen.
Simple Tag: prog &rest args
Synonym for group.
Simple Tag: return &rest args
Unconditionally and immediately stop the execution of the
current function, macro, while or foreach statement, and return
the evaluated args.
Example usage:
<define-function countdown start stop>
<if <eq start stop>
<return BlastOff!>>
<get-var start>,
<countdown <sub start 1> <get-var stop>>
</define-function>
<countdown 10 4>
produces
10, 9, 8, 7, 6, 5, BlastOff!
Simple Tag: var-case &optional [name=value] [consequent...] [default]
[default-consequent]
For each name=value pair, the value of name is string-wise
compared with value. If they are identical, then the
corresponding consequent code is performed, and its value is
the return value of the <var-case> form.
If none of the clauses match, and there is a default clause,
then the default-consequent is evaluated, and its return value
is the return value of the <var-case> form.
var-case is especially useful as a `traffic switch' to select
one of several actions based on a user button press.
For example:
<var-case
action="Save Files" <save-files <get-var posted::files[]>>
action="Delete Files" <delete-files <get-var posted::files[]>>
action="Rename Files" <redirect
rename-files.mhtml?<cgi-encode files>>>
Complex Tag: when test
Evaluate test. If the result is a non-empty string, then
execute the body statements. This is a cleaner way to handle
optional multiple statement execution rather than dealing with
quoting everything inside of an if form.
Complex Tag: while test
test is evaluated. If the result is a non-empty string, then
the body statements are evaluated, and the process is repeated.
Complex Tag: with &optional [var=val...]
Execute body in an environment where var has the value val.
Execution takes place in the current package. After execution,
the value of var is restored to the value that it had before
encountering the with macro.
<set-var x=hello>
<with x=1 z=<get-var foo>> <get-var x> </with>
<get-var x>
produces
1
hello
Convenience Primitives
Meta-HTML provides various functions and variables which are used to
operate on or within the language environment itself, rather than
within the application environment.
Such constructs make it possible to create self-modifying code, to
change the way in which a builtin function operates, and other such
language dependent features.
Complex Tag: comment
Simply discard the body. No processing is done, and no output
is produced.
A shorthand for commenting source on a single line exists; when
the sequence of 3 semicolon character is seen (;;;), then the
text from this sequence to the end of the line inclusive is
discarded.
Example:
<comment>
This text is simply ignored.
All of it.
</comment>
;; But NOT this line -- it only has two semi-colons on it.
Variable: mhtml::inhibit-comment-parsing
When this variable is set to a non-empty value, the triple
semi-colon comment feature is disabled.
You may need this for complex applications where you are
deliberately shipping the source of a Meta-HTML document to the
client.
Variable: mhtml::version
Contains the version identification of the currently running
interpreter. This variable is available whereever the
interpreter is running, including the Meta-HTML server, Engine,
and in mdb.
<get-var mhtml::version>
produces
5.09
Strings and Numbers
String Operators
There is a single function in Meta-HTML which performs pattern
matching, substring extraction, and substring deletion. For
convenience, a blind substring extraction function is supplied as
well. Three functions perform the three most common case changes.
Finally, the pad function allows alignment of fixed-width text.
Simple Tag: capitalize string
Changes the case of each character in string to uppercase or
lowercase depending on the surrounding characters.
<capitalize "This is a list">
produces
This Is A List
Also see downcase, and upcase.
Simple Tag: char-offsets string ch &key [caseless]
Return an array of numbers, each one representing the offset
from the start of string of ch. This function is useful for
finding candidate locations for word-wrapping, for example.
Here is a complete example:
<char-offsets "This is a list" " ">
produces
4
7
9
Simple Tag: downcase string
Converts all of the uppercase characters in string to
lowercase.
<downcase "This is Written in Meta-HTML">
produces
this is written in meta-html
Simple Tag: match string regex &key
[action=[delete|extract|report|startpos|endpos|length]]
Matches regexp against string, and then performs the indicated
action. The default for action is "report".
When action is "report" (the default), returns "true" if regex
matched.
When action is "extract", returns the substring of string
matching regex.
When action is "delete", returns string with the matched
substring removed.
When action is "startpos", returns the numeric offset of the
start of the matched substring.
When action is "endpos", returns the numeric offset of the end
of the matched substring.
regexp is an extended Unix regular expression, the complete
syntax of which is beyond the scope of this document. However,
the essential basics are:
+ A period (.) matches any one character.
+ An asterisk (*) matches any number of occurrences of the
preceding expression, including none.
+ A plus-sign matches one or more occurrences of the preceding
expression.
+ Square brackets are used to enclose lists of characters which
may match. For example, "[a-zA-Z]+" matches one or more
occurrences of alphabetic characters.
+ The vertical bar is used to separate alternate expressions to
match against. For example, "foo|bar" says to match either
"foo" or "bar".
+ A dollar-sign ($) matches the end of STRING.
+ Parenthesis are used to group subexpressions.
Here are a few examples:
<match "foobar" ".*"> ==> "true"
<match "foobar" "foo"> ==> "true"
<match "foobar" "foo" action=extract> ==> "foo"
<match "foobar" "oob" action=delete> ==> "far"
<match "foobar" "oob" action=startpos>==> "1"
<match "foobar" "oob" action=endpos> ==> "4"
<match "foobar" "oob" action=length> ==> "3"
<match "foobar" "[0-9]+"> ==> ""
Complex Tag: plain-text &key [first-char=expr] [nobr=true]
Performs the following steps:
1. Replace occurrences of pairs of newline characters with a single
<P> tag.
2. Applies the function expr to the first character of every
paragraph, and inserts the closing tag after that character.
The output will start with a <P> tag, unless the optional argument
nobr=true is given.
<plain-text first-char=<font size="+1"> nobr=true>
This is line 1.
This is line 2.
</plain-text>
produces
This is line 1.
This is line 2.
Simple Tag: string-compare string1 string2 &key [caseless]
Compare the two strings string1 and string2, and return a
string which specifies the relationship between them. The
comparison is normall case-sensitive, unless the keyword
argument caseless=true is given.
The possible return values are:
1. equal
The two strings are exactly alike.
2. greater
string1 is lexically greater than string2.
3. less
string1 is lexically less than string2.
Examples:
<string-compare "aaa" "aab"> ==> less
<string-compare "zzz" "aab"> ==> greater
<string-compare "zzz" "ZZZ"> ==> greater
<string-compare "zzz" "ZZZ" caseless=true> ==> equal
Simple Tag: string-eq string-1 string-2 &key [caseless=true]
Compare string1 to string2 and return the string "true" if they
are character-wise identical.
The optional keyword argument caseless=true indicates that no
consideration should be given to the case of the characters
during comparison.
<string-eq "foo" "FOO"> ==>
<string-eq "foo" "foo"> ==>true
<string-eq <upcase "foo"> "FOO"> ==>true
<string-eq "foo" "FOO" caseless=true> ==>true
Simple Tag: string-length string
Returns the number of characters present in string.
<string-length "This is an interesting string">
produces
29
Simple Tag: string-neq string-1 string-2 &key [caseless=true]
Compare string1 to string2 and return the string "true" if they
are NOT character-wise identical.
The optional keyword argument caseless=true indicates that no
consideration should be given to the case of the characters
during comparison.
<string-neq "foo" "FOO"> ==>true
<string-neq "foo" "foo"> ==>
<string-neq <upcase "foo"> "FOO"> ==>
<string-neq "foo" "FOO" caseless=true> ==>
Simple Tag: subst-in-string string &rest regexp replacement
Replaces all occurrences of regexp with replacement in string.
regexp can be any regular expression allowed by POSIX extended
regular expression matching.
In the replacement string, a backslash followed by a number n
is replaced with the contents of the nth subexpression from
regexp.
<set-var foo="This is a list">
<subst-in-string <get-var foo> "is" "HELLO">
==> "ThHELLO HELLO a lHELLOt"
<subst-in-string "abc" "([a-z])" "\1 "> ==> "a b c "
Simple Tag: subst-in-var varname &optional [this-string] [with-that]
Replaces all occurrences of this-string with with-that in the
contents of the variable named varname. Both this-string and
with-that are evaluated before the replacement is done.
this-string can be any regular expression allowed by the POSIX
extended regular expression matching. This command can be
useful when parsing the output of cgi-exec.
Simple Tag: substring string &key [start] [end]
Extracts the substring of string whose first character starts
at offset start, and whose last character ends at offset end.
The indexing is zero-based, so that:
<substring "Hello" 1 2> ==> "e"
This function is useful when you know in advance which part of
the string you would like to extract, and do not need the
pattern matching facilities of match.
If you wish to index through each character of a string, the
most direct way is to convert it to an array first using
string-to-array, and then use the foreach function to iterate
over the members.
<set-var s="This is a string.">
<string-to-array <get-var-once s> chars>
<foreach character chars><get-var character>-</foreach>
produces
<string-to-array This is a string. chars>
Simple Tag: upcase string
Converts all of the lowercase characters in string to
uppercase.
<upcase "This is Written in Meta-HTML">
produces
THIS IS WRITTEN IN META-HTML
Arithmetic Operators
Meta-HTML contains a small set of commands for operating on numerical
quantities.
All of the arithmetic operators described in this section can accept a
number, or simply the name of a variable, which is then looked up as
if it had been written with <get-var ...>.
That is to say:
<set-var total = <add <get-var subtotals[0]>
<get-var subtotals[current]>>>
can be written as:
<set-var total = <add subtotals[0] subtotals[current]>>
The binary arithmetic operators always expect two arguments, and will
produce a warning message in DEBUGGING-OUTPUT when given too few
arguments.
You can perform floating point arithmetic if one or both of the
arguments is already a floating point number:
<div 10 3> ==> 3
<div 10.0 3> ==> 3.33
Simple Tag: add arg1 arg2 &rest more-args
Returns the summation of all of the arguments passed.
Examples:
<add 1 2> ==> 3
<add -1 2 2 1> ==> 4
Simple Tag: div arg1 arg2 &rest more-args
Returns the quotient of all of the arguments passed.
Examples:
<div 100 5> ==> 20
<div 5 100> ==> 0
<div 5.0 100.0> ==> 0.05
<div 100 5 2> ==> 10
Simple Tag: eq arg1 arg2
Returns "true" if the numeric value of arg1 is exactly equal to
the numeric value of arg2. Just as with the arithmetic
functions (See section Arithmetic Operators), the arguments may
be the names of variables containing numeric values, and not
just the values themselves. In that case, eq performs an
implicit call to <get-var ...> in order to get the value to
operate on.
Examples:
<eq 3 4> ==>
<eq 3 3> ==> true
<eq 3.0 3> ==> true
<set-var x=3.01>
<eq <get-var x> 3.01> ==> true
Simple Tag: gt arg1 arg2 &rest more-args...
Returns "true" if the numeric value of arg1 is greater than the
numeric value of arg2 (which is greater than more-args. Just as
with the arithmetic functions (See section Arithmetic
Operators), the arguments may be the names of variables
containing numeric values, and not just the values themselves.
In that case, gt performs an implicit call to <get-var ...> in
order to get the value to operate on.
Examples:
<gt 4 3> ==> true
<set-var x=3.4 y=3.5>
<gt x y> ==>
<gt y x> ==> true
<gt <get-var y> x> ==> true
<defun between? item high low>
<gt high item low>
</defun>
<between? 7 8 6> ==> true
Simple Tag: integer? string &key [base[=10]]
Returns "true" if string is the string representation of an
integer value in base base (default 10). This function is
useful for checking the validity of user input to a form.
You call this function with the actual value -- you may not
pass the name of a variable instead.
Some examples:
<set-var x=123>
<integer? -90> ==> true
<integer? <get-var x>> ==> true
<integer? 2.3> ==>
<integer? FEFE base=16> ==> true
<integer? 874 base=8> ==>
Simple Tag: lt arg1 arg2 &rest more-args
Returns "true" if the numeric value of arg1 is less than the
numeric value of arg2 (which is less than more-args. Just as
with the arithmetic functions (See section Arithmetic
Operators), arg1 and arg2 may be the names of variables
containing numeric values, and not just the values themselves.
In that case, lt performs an implicit call to <get-var ...> in
order to get the value to operate on.
Examples:
<lt 3 4> ==> true
<lt 4 3> ==>
<set-var x=3.4 y=3.5>
<lt x y> ==> true
<lt y x> ==>
<lt x <get-var y>> ==> true
<lt 4 5 6> ==> true
Simple Tag: max arg1 arg2 &rest more-args
Returns the largets of all of the arguments passed.
Examples:
<max 2 2> ==> 2
<max 2.3 8 7> ==> 8.00
<max 4 10 -4> ==> 10
Variable: mhtml::decimal-places
Controls the number of decimal places which arithmetic
functions produce. The default value of this variable is 2, but
for times when you need greater resolution in your
calculations, you may wish to set it higher.
<set-var mhtml::decimal-places = 10>
To 10 places: <div 1 .34567>
<unset-var mhtml::decimal-places>
To 2 places: <div 1 .34567>
produces
To 10 places: 2.8929325657
To 2 places: 2.89
Simple Tag: min arg1 arg2 &rest more-args
Returns the smallest of all of the arguments passed.
Examples:
<min 2 2> ==> 2
<min 2.3 8 3> ==> 2.30
<min 3 -4 10> ==> -4
Simple Tag: mod arg1 arg2 &rest more-args
Returns the remainder of all of the arguments passed.
Examples:
<mod 100 10> ==> 0
<mod 101 10> ==> 1
<mod 89 9 3> ==> 2
Simple Tag: mul arg1 arg2 &rest more-args
Returns the product of all of the arguments passed.
Examples:
<mul 2 2> ==> 4
<mul 2.3 8 3> ==> 55.20
<mul -4 10> ==> -40
Simple Tag: neq arg1 arg2
Returns "true" if the numeric value of arg1 is NOT equal to the
numeric value of arg2. Just as with the arithmetic functions
(See section Arithmetic Operators), the arguments may be the
names of variables containing numeric values, and not just the
values themselves. In that case, eq performs an implicit call
to <get-var ...> in order to get the value to operate on.
Examples:
<neq 3 4> ==> true
<neq 3 3> ==>
<neq 3.0 3> ==>
<set-var x=3.01>
<neq <get-var x> 3.00> ==> true
Simple Tag: real? string
Returns "true" if string is the string representation of a real
number.Useful for checking the validity of user input to a
form.
You call this function with the actual value -- you may not
pass the name of a variable instead.
Some examples:
<set-var pi=3.141569>
<real? <get-var pi>> ==> true
<real? 45> ==>
<real? 2.3> ==> true
<real? "This"> ==>
<real? -.087e4> ==> true
Simple Tag: set-output-radix new-radix
Set the output radix for numbers produced by arithmetic
operations to new-radix, which is specified in decimal. Returns
the value of the previous output radix. Note that there is no
corresponding function for setting the input radix. If the
value of new-radix is a number between 2 and 32 decimal,
inclusive, then the output radix is set to that value.
new-radix can also be the name of a function of one argument,
which should be called to produce the appropriate output.
If the argument to does not fall between 2 and 32 inclusive,
and is not the name of a defined function, then the output
radix remains unchanged, and produces no output.
Examples:
<set-output-radix 16> ==> 10
<add 0x3e 1> ==> 0x3f
<set-output-radix 10> ==> 16
<set-output-radix number-to-english> ==> 10
<add 23.4 32.32> ==> Fifty-Five point Seven Two
Simple Tag: sub arg1 arg2 &rest more-args
Returns the difference of all of the arguments passed.
Examples:
<sub 2 1> ==> 1
<sub 6 2 1> ==> 3
<sub -1 -2> ==> 1
Relational Operators
Relational operators in Meta-HTML return information about the
relationship between two items. There are three logical operators,
and, or, and not.
There are several other operators which compare numeric values; the
section See section Arithmetic Operators cover those in detail.
Simple Tag: and &rest expr...
and evaluates each expr given until one of them evaluates to
the empty string, or until they are all exhausted. The result
is the result of the last evaluation. Evaluating just <and>
returns "true".
Examples:
<and> ==> true
<and this that> ==> that
<unset-var foo>
<and <get-var foo> this> ==>
<and this <get-var foo>> ==>
<set-var foo=bar>
<and this long list <get-var foo>> ==> bar
true could have been defined in Meta-HTML as follows:
<define-tag and &unevalled &rest expressions[] whitespace=delete>
<set-var result=true>
<foreach :expr expressions>
<set-var result = <get-var :expr>>
<if <not <get-var-once result>>
<break>>
</foreach>
<get-var-once result>
</define-tag>
Simple Tag: not &optional [body]
body is evaluated. If the result is the empty string, then the
string "true" is returned, otherwise nothing is returned. body
is simply the entire contents of the simple tag, with the word
"not" in it. Thus, in typical usage one might write:
<when <not <get-var foo>>>
Hey! You didn't set the variable FOO.
</when>
Simple Tag: or &rest expr...
or evaluates each expr given until one of them evaluates to a
non-empty string, or until they are all exhausted. The result
is the result of the last evaluation. Evaluating just <or>
returns the empty string.
Examples:
<or> ==>
<or this that> ==> this
<unset-var foo>
<or <get-var foo> this> ==> this
<or this <get-var foo>> ==> this
<set-var foo=bar>
<or <get-var foo> this> ==> bar
could have been defined in Meta-HTML as follows:
<define-tag or &unevalled &rest expressions[] whitespace=delete>
<foreach :expr expressions>
<set-var result = <get-var :expr>>
<if <get-var-once result>
<break>>
</foreach>
<get-var-once result>
</define-tag>
Input and Output
File Operators
There are several types of commands in Meta-HTML for dealing with
files.
Some of these commands operate directly on an open files, while others
operate on streams (see Stream Operators (not included in this
document)), which may be connected to files or network data.
The functions allow you to include the contents of, open
(with-open-stream), create, read, or write various data sources, or to
replace the contents of a page (replace-page) with another
file.Commands such as get-file-properties may return additional
information on some systems; this is documented with each function
where that is the case.
Simple Tag: directory-contents pathname &optional [package-name] &key
[matching=pattern]
Returns a newline separated list of association lists for the
files matching pattern.
When package-name is supplied, each variable in package-name is
the name of a file in pathname, and the value of each variable
is the association list for that file.
Simple Tag: file-exists pathname
Returns "true" if pathname is an existing file or directory.
pathname is absolute, that is to say that it is looked up in
absolute file system space, not in Web space. To find out if a
file foo in the current directory exists, use:
<file-exists <thisdir>/foo>
Simple Tag: get-file-properties pathname
Return an association-list containing operating system
information about the file or directory named by path. pathname
must be given fully; it is not relative to Web space in any
way.
If the file exists and is accessible, the members of the
returned association-list which are guaranteed to be present
are:
+ NAME: welcome.mhtml
The name of the file or directory, without any of the path
information.
+ FULL-NAME: /www/site/docs/welcome.mhtml
The name of the file or directory, with full path
information. This should be identical to PATH as received by
.
+ SIZE: 2188
The size of the file in bytes.
+ TYPE: FILE
The type of the file. This will either be FILE or DIRECTORY.
In addition to the above fields, the following fields appear on
Unix based systems:
+ CREATED: 6 29 96 10 3 24 897595648
The date on which this file was created. The value is an
array, with ordered values being: month, day, year, hours,
minutes, and seconds, and then the number of seconds since
Jan 1st, 1970.
+ WRITTEN: 6 29 96 10 3 24 897595648
The date on which this file was last written. The value is an
array, with ordered values being: month, day, year, hours,
minutes, and seconds, and then the number of seconds since
Jan 1st, 1970.
+ READ: 6 30 96 19 27 51 897595648
The date on which this file was last read. The value is an
array, with ordered values being: month, day, year, hours,
minutes, and seconds, and then the number of seconds since
Jan 1st, 1970.
+ CREATOR: bfox
The system identifier of the user who created this file.
A example calling sequence:
<dump-alist <get-file-properties />>
Defining New Tags
Macro Commands
Meta-HTML contains a powerful macro facility, which allows you to
define your own commands. Such commands are first-class objects in
Meta-HTML; they may even supersede the compiled in definitions.
There are two types of macros that you can define. One type is a
complex-tag; it consists of an opening tag, a body, and a closing
tag. The other type is a simple-tag; it only has an opening tag.
You create a macro by using one of the macro-defining commands. In the
body of the definition, special keywords can be placed, which affect
what is produced when the macro is invoked. As a macro writer, you
have logical access to the arguments passed to the macro in the
opening tag, and for complex-tags, you have access to the body which
appears between the opening and closing tags. In the opening tag of
the macro defining command, several special meta-arguments may be used
to affect the binding method used at invocation time to bind the
passed parameters to the formal arguments.
* &optional
Indicates that the following named parameter is optional, and does
not have to be supplied. While at this time Meta-HTML does not
complain if there are missing arguments at invocation time, it is
likely that the byte-compiler will require function calls to match
the formal parameters of the defined function.
<defun func x &optional y> <get-var x>, <get-var y> </defun>
* &key
Indicates that the following named parameters will be bound by the
caller placing the name of the parameter followed by an equals
sign, and the value of that parameter in the opening tag of the
function call. Thus, keyword arguments may appear in any order in
the calling function. Here is an example of defining a tag called
<image> which will add the width and hieght if they are not
already present:
<defun image &key src width height>
<if <or <not <get-var width>>
<not <get-var height>>>
<find-image-xy <get-var src> width height>>
<img src="<get-var src>" width=<get-var width> height=<get-var height>>
</defun>
* &rest
Gobbles up any remaining arguments to the function, collecting
them in the named parameter which follows the &rest. The arguments
may be gathered into a single string, or into an array, with one
argument per slot. This is controlled by writing the formal
parameter name either with or without sqaure braces: (i.e., foo[]
or foo).
<defun func req-arg &rest rest-args[]>
<ol>
<foreach x rest-args>
<li> <get-var x> </li>
</foreach>
</ol>
</defun>
* &body
Causes the following named parameter to be bound to the body of
the invoked function or macro. For <defun> and <defsubst>, this is
all of the material which appeared in the opening tag, while for
<defmacro> and <defweakmacro>, this is all of the material that
appeared between the opening and closing tags.
<defmacro with-debugging-output &body body>
<with-open-stream debug-stream /tmp/debug-output mode=append>
<stream-put debug-stream <get-var body>>
</with-open-stream>
</defmacro>
* &unevalled
Modifies the binding rule of a formal parameter such that the
material which is bound is not evaluated before the binding takes
place. This is almost equivalent to using the %0 ... %9, or %body
textual substitutions, but the arguments are bound to variables
instead of pure textual substitution. Here is how one might write
a function which takes an expression, and produces the expression
and the evaluation of the expression as output:
<defun debug-expr &body &unevalled qbody &body body>
<get-var-once qbody> EVALS TO: <get-var-once body>
</defun>
Such an invocation might look like:
<set-var x=4 y=5>
<debug-expr <add x y>>
which would produce:
<add x y> EVALS TO: 9
Here is a ridiculous function, which uses all of the special
meta-parameters:
<defsubst func req &optional opt &key k1 &unevalled k2 &body b &rest args[]>
REQ: <get-var-once req>,
OPT: <get-var-once opt>
K1: <get-var-once k1>
K2: <get-var-once k2>
BODY: <get-var-once b>
REST: <foreach arg args><get-var-once arg> </foreach>
</defsubst>
And, here are examples of calling that function:
Example 1:
<set-var key-1-arg=key-1>
<func required k2="Unevalled" opt-arg k1=<get-var key-1-arg> rest0 rest1>
REQ: required,
OPT: opt-arg
K1: key-1
K2: Unevalled
BODY: required k2="Unevalled" opt-arg k1=key-1 rest0 rest1
REST: rest0 rest1
Example 2:
<func k2=<get-var k1> required rest0 rest1>
REQ: required,
OPT: rest0
K1:
K2: <get-var k1>
BODY: k2= required rest0 rest1
REST: rest1
Notice how in the second example, our optional parameter opt got bound
to the second non-keyword argument rest0!
Complex Tag: define-container name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
Define name as a complex tag. At invocation time, various
substitutions are made within body. Specifically, if the text
string is:
+ %0,%1, and so on, upto %9 are replaced with the exact text of
the positional arguments that were found in the opening tag
of the invocation
+ %attributes is replaced by all of the arguments which
appeared in the opening tag.
+ %body is replaced with the exact text of the material that
appeared between the opening and closing tags
+ %qbody is similar to %body, but the string is first
surrounded by double quotes, and double quote characters
which appear in the string are escaped.
+ %xbody is replaced with the evaluation of the material that
appeared between the opening and closing tags
If any named-parameters are supplied, the values that were
passed in the opening tag are evaluated and bound to the named
parameters.
A keyword argument of package-name wraps the entire body of the
macro in an in-package statement.
The keyword argument whitespace can be set to the string delete
to remove whitespace from the starts and ends of lines in the
macro definition before it is stored. This effectively
concatenates all of the lines of the macro definition into a
single long line.
Complex Tag: define-function name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
Define name as a simple tag.
The only differences between define-function and define-tag
are:
1. The whitespace=delete option is assumed.
2. The named-parameters are evaluated in the context of the caller,
not of the definition of the defun.
3. By default, a local package is wrapped around the invocation of
the defined function. This can be changed by the use of the
package=packname keyword.
<define-function factorial num>
<if <lt num 2> 1
<mul num <factorial <sub num 1>>>>
</define-function>
<factorial 5> ==> 120
Complex Tag: define-tag name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
Define name as a simple tag. Within body, the values of %0...%9
are defined to be the positional arguments that were found in
the opening tag of the invocation, and %body is all of that
material in a single string.
If any named-parameters are supplied, the values that were
passed in the opening tag are evaluated and bound to the named
parameters.
A keyword argument of package-name wraps the entire body of the
macro in an in-package statement.
The keyword argument whitespace can be set to the string delete
to remove whitespace from the starts and ends of lines in the
subst definition before it is stored. This effectively
concatenates all of the lines of the subst definition into a
single long line.
Also see define-function and define-container.
Complex Tag: defmacro name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
A synonym for define-container.
Complex Tag: defsubst name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
A synonym for define-tag.
Complex Tag: defun name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
A synonym for define-function.
Complex Tag: defweakmacro name &optional [named-parameters] &key
[package=packname] [whitespace=delete]
defweakmacro is exactly like define-container, with one
exception: at invocation time, the closing tag does not have to
be present -- in that case, the invocation is treated as if the
definition were a defsubst.
This facility exists primarily to allow the redefinition of
standard HTML constructs which allow the closing tag to be
missing, and yet, still inexplicably operate correctly.
For example, the <p> tag is often used without its closing
counterpart of </p>. If you wished to redefine <p> to do
something special when a closing tag was found, you might write
the following definition:
<defweakmacro p>
<verbatim><P></verbatim>
<when %qbody> Look ma! %body See? </when>
<verbatim></P></verbatim>
</defweakmacro>
then, a simple <P> would produce <P></P>, while a complex
invocation, such as:
<P> this is a list </P>
produces
<P> Look ma! this is a list See? </P>
Simple Tag: undef &optional [name...]
Remove the definition of a user-defined defun, defmacro or
defsubst. For every name that has been defined in this way,
the definition is removed.
Debugging Your Programs
Debugging Commands
Debugging a CGI application executing under a running Web server can
be quite problematic. Meta-HTML provides the following functions,
macros, and variables in an effort to alleviate the problems
associated with this situation.In addition to the functions and
variables above, Meta-HTML has a complete source language debugger
called mdb, which can be used to interactively execute expressions, to
place breakpoints in files and then run them examining local and
global variables, and to single-step through source code that you have
written in Meta-HTML. Instructions on the use of the debugger is
beyong the scope of this manual -- please see MDB: A User's Guide to
Debugging Meta-HTML Programs for more information specific to the
debugger.
Simple Tag: debugging-on &optional [function-name=level...]
Turns on debugging for the function-names mentioned, setting
the level of output to level. level is a number between 0 (the
least amount of debugging info) and 10 (the maximum amount of
debugging info).
The output is placed into the Meta-HTML internal debugger
buffer, and can be placed into an output page by simply placing
the tag <DEBUGGING-OUTPUT> somewhere in the page, or can be
explicity retrieved using <debugging-output retrieve>.
Simple Tag: debugging-output &optional [action...]
Meta-HTML stores debugging information in an internal buffer.
You may directly place information into this buffer using the
page-debug command, and you may retrieve or clear this buffer
using <debugging-output>.
Possible values for action are:
+ retrieve
Inserts the current contents of the debugging buffer into the
page at the current location.
+ clear
Empties the debugging buffer of all stored information.
If you place <debugging-output> into your page without passing
any arguments, Meta-HTML treats this invocation specially; it
marks the location at which any debugging statements which have
been collected during the processing of the entire page should
be placed.
We recommend that you always place this tag somewhere in the
output page, whenever that output is an HTML document, as
opposed to a standalone script.
Simple Tag: function-def function-name...
Get the body of the macro, verbatim.
Simple Tag: page-debug &rest body
Cause body to be inserted into the debugger output.
The output is placed into the Meta-HTML internal debugger
buffer, and can be placed into an output page by simply placing
the tag <DEBUGGING-OUTPUT> somewhere in the page, or can be
explicity retrieved using <debugging-output retrieve>.
Simple Tag: system-error-output &optional [action...]
Meta-HTML stores system error information in an internal
buffer. Such information may be the results of an error which
occurred during the execution of an external command (such as
with cgi-exec), or other information which is generated by the
inability of Meta-HTML to access a particular file (such as
with the require command).
You may retrieve or clear this buffer using
<system-error-output>.
Possible values for action are:
+ retrieve
Inserts the current contents of the system error buffer into
the page at the current location.
+ clear
Empties the system error buffer of all stored information.
If you place <system-error-output> into your page without
passing any arguments, Meta-HTML treats this invocation
specially; it marks the location at which any system errors
which have been collected during the processing of the entire
page should be placed.
We recommend that you always place this tag somewhere in the
output page, whenever that output is an HTML document, as
opposed to a standalone script.
Code Profiling
The profiler module allows you to get a detailed listing of the number
of times a particular function has executed, the amount of time spent
within each function, and other information which can help you to tune
your Meta-HTML application, and get it running as fast as possible.
The use of this module is trivial. First, place
<set-var mhtml::profile-functions = true>
at the top of the page that you would like to profile.
At the bottom of the page, after the last normal instruction, place
<profiler::dump /tmp/meta.prof>
After visiting the page in a browser, the file /tmp/meta.prog will
contain a human readable dump of the profile information. Your page
won't perceptibly slow down during loading -- the only indication that
profiling is on is the creation of the output file that you specify.
Simple Tag: profiler::dump filename &key [sort=[names|times|calls]]
Write profiling information to filename. Unlike C profilers,
the output is quite self-explanatory.
Known bugs: The total time doesn't really correctly reflect the
amount of time spent processing the entire page -- the time
displayed is additive, so it is always orders of magnitude
larger than it should be. However, the time displayed for each
function call is correct.
Defined Meta-HTML Variables
Variable: mhtml::decimal-places
Controls the number of decimal places which arithmetic
functions produce. The default value of this variable is 2, but
for times when you need greater resolution in your
calculations, you may wish to set it higher.
<set-var mhtml::decimal-places = 10>
To 10 places: <div 1 .34567>
<unset-var mhtml::decimal-places>
To 2 places: <div 1 .34567>
produces
To 10 places: 2.8929325657
To 2 places: 2.89
Variable: mhtml::inhibit-comment-parsing
When this variable is set to a non-empty value, the triple
semi-colon comment feature is disabled.
You may need this for complex applications where you are
deliberately shipping the source of a Meta-HTML document to the
client.
Variable: mhtml::iteration-limit
The use of this variable has been deprecated. while loops last
until either the test-clause is met, or a break statement is
seen.
Variable: mhtml::version
Contains the version identification of the currently running
interpreter. This variable is available whereever the
interpreter is running, including the Meta-HTML server, Engine,
and in mdb.
<get-var mhtml::version>
produces
5.09
Function Index
a
add
alist-defvar
alist-get-var
alist-package-delete
alist-package-names
alist-set-var
alist-to-package
alist-unset-var
alist-var-exists
alist?
and
array-add-unique
array-append
array-concat
array-member
array-shift
array-size
b
break
c
capitalize
char-offsets
coerce-var
comment
concat
copy-var
d
debugging-on
debugging-output
decrement
define-container
define-function
define-tag
defmacro
defsubst
defun
defvar
defweakmacro
directory-contents
div
downcase
e
eq
f
file-exists
foreach
function-def
g
get-file-properties
get-var
get-var-once
group
gt
i
if
ifeq
ifneq
in-package
increment
integer?
l
lt
m
match
max
min
mod
mul
n
neq
not
o
or
p
package-delete
package-names
package-to-alist
package-vars
page-debug
plain-text
profiler::dump
prog
r
real?
return
s
set-output-radix
set-var
set-var-readonly
set-var-verbatim
sort
string-compare
string-eq
string-length
string-neq
sub
subst-in-string
subst-in-var
substring
symbol-info
system-error-output
u
undef
unset-var
upcase
v
var-case
var-exists
w
when
while
with
with-local-package
_________________________________________________________________
This document was generated on 5 July 1999 using the texi2html
translator version 1.54.