Documentation: Core / mp4h (Pass 2)
mp4h - Macro Processor for HTML Documents
This documentation describes mp4h version 1.2.3.
Introduction
The mp4h software is a macro-processor specifically designed to deal
with HTML documents. It allows powerful programming constructs, with a
syntax familiar to HTML authors.
This software is based on
Meta-HTML,
written by Brian J. Fox, Even if both syntaxes look similar, source
code is completely different. Indeed, a subset of Meta-HTML was used
as a part of a more complex program, WML
(Website Meta Language)
written by Ralf S. Engelschall and which i maintain since January 1999.
For licensing reasons, it was hard to hack Meta-HTML and so i decided
to write my own macro-processor.
Instead of rewriting it from scratch, I preferred using another
macro-processor engine. I chose
GNU m4,
written by René Seindal, because of its numerous advantages :
this software is stable, robust and very well documented.
This version of mp4h is derived from GNU m4 version 1.4n, which is a
development version.
The mp4h software is not an HTML editor; its unique goal is to
provide an easy way to define its own macros inside HTML documents.
There is no plan to add functionalities to automagically produce valid
HTML documents, if you want to clean up your code or validate it,
simply use a post-processor like
tidy.
Command line options
Optional arguments are enclosed within square brackets.
All option synonyms have a similar syntax, so when a long option accepts
an argument, short option do too.
Syntax call is
mp4h [options] [filename [filename] ...]
Options are described below. If no filename is specified, or if its
name is -, then characters are read on standard input.
Operation modes
| --help | display an help message and exit |
| --version | output mp4h version information and exit |
| -E --fatal-warnings | stop execution after first warning |
| -Q --quiet --silent | suppress some warnings for builtins |
| -S --safety-level=NUMBER | disable risky functions;
0 means no filtering, 1 disable execute and 2 disable this
one too plus all filesystem related functions:
file-exists,
real-path,
get-file-properties,
directory-contents and
include.
|
Preprocessor features
| -I --include=DIRECTORY | search this directory for includes and packages |
| -D --define=NAME[=VALUE] | set variable NAME to VALUE, or empty |
| -U --undefine=COMMAND | delete builtin COMMAND |
| -s --synclines | generate `#line NO "FILE"' lines |
Parser features
| -c --caseless=NUMBER | set case sensitiveness according to the bits of NUMBER.
A null bit means symbol is case sensitive, and bits are defined as
followed: 0 for tags, 1 for variables and 2 for entities.
Default value is 3, i.e. only entities are case sensitive. |
| -e --encoding=NAME | specify document encoding. Valid options are `8bit' (default) or `utf8'. |
| -X --expansion=NUMBER | set parser behaviour according to the bits of NUMBER |
NUMBER is a combination of
| 1 | do not parse unknown tags |
| 2 | unknown tags are assumed being simple |
| 4 | trailing star in tag name do not make this tag simple |
| 8 | an unmatched end tag closes all previous unmatched begin tags |
| 16 | interpret backslashes as printf |
| 32 | remove trailing slash in tag attributes |
| 64 | do not remove trailing star in tag name |
| 128 | do not remove leading star in tag name |
| 256 | do not add a space before trailing slash in tag attributes |
| 1024 | suppress warnings about bad nested tags |
| 2048 | suppress warnings about missing trailing slash |
In version 1.2.3, default value is 3114=2+8+32+1024+2048.
Limits control
| -H --hashsize=PRIME | set symbol lookup hash table size (default 509) |
| -L -nesting-limit=NUMBER | change artificial nesting limit (default 250) |
Debugging
| -d --debug=FLAGS | set debug level (no FLAGS implies `aeq') |
| -t --trace=NAME | trace NAME when it will be defined |
| -l --arglength=NUMBER | restrict macro tracing size |
| -o --error-output=FILE | redirect debug and trace output |
Flags are any of:
| t | trace for all macro calls, not only debugging-on'ed |
| a | show actual arguments |
| e | show expansion |
| c | show before collect, after collect and after call |
| x | add a unique macro call id, useful with c flag |
| f | say current input file name |
| l | say current input line number |
| p | show results of path searches |
| i | show changes in input files |
| V | shorthand for all of the above flags |
Description
The mp4h software is a macro-processor, which means that keywords are
replaced by other text. This chapter describes all primitives.
As mp4h has been specially designed for HTML documents, its syntax is
very similar to HTML, with tags and attributes. One important feature
has no equivalent in HTML: comments until end of line. All text
following three colons is discarded until end of line, like
;;; This is a comment
Function Macros
Note:
All examples in this documentation are processed through mp4h with
expansion flags set to zero (see a description of possible expansion
flags at the end of document), it is why simple tags contain a trailing
slash. But mp4h can output plain HTML files with other expansion
flags.
The definition of new tags is the most common task provided by mp4h.
As with HTML, macro names are case insensitive, unless -c
option is used to change this default behaviour. In this documentation,
only lowercase letters are used.
There are two kinds of tags: simple and complex. A simple tag has the
following form:
<name [attributes] >
whereas a complex tag looks like:
<name [attributes]>
body
</name>
Since version 0.9.1, mp4h knows XHTML syntax too, so your input file
may conform to HTML or XHTML syntax. In this manual, we adopt the
latter, which is why simple tags have a trailing slash in attributes.
If you want to produce HTML files with this input file, you may either
choose an adequate --expansion flag or use a post-processor like
tidy.
When a simple tag is defined by mp4h, it can be parsed even if the
trailing slash is omitted, because mp4h knows that this tag is
simple. But it is a good practice to always append a trailing slash to
simple tags.
In macro descriptions below, a slash indicates a simple tag, and a V
letter that attributes are read verbatim (without expansion) (see the
chapter on macro expansion for further details).
| | | define-tag | | name | | [attributes=verbatim] | | [endtag=required] | | [whitespace=delete] |
|
|
|
This function lets you define your own tags. First argument is the
command name. Replacement text is the function body.
| Source |
<define-tag foo>bar</define-tag>
<foo>
|
| Output |
bar |
Even if spaces have usually few incidence on HTML syntax, it is
important to note that
<define-tag foo>bar</define-tag>
and
<define-tag foo>
bar
</define-tag>
are not equivalent, the latter form contains two newlines that were not
present in the former.
- whitespace=delete
Some spaces are suppressed in replacement text, in particular any
leading or trailing spaces, and newlines not enclosed within angle
brackets.
- endtag=required
Define a complex tag
| Source |
<define-tag foo>bar</define-tag>
<foo>
|
| Output |
bar |
| Source |
<define-tag bar endtag=required>;;;
body is: %body</define-tag>
<bar>Here it is</bar>
|
| Output |
body is: Here it is |
- attributes=verbatim
By default attributes are expanded before text is replaced. If this
attribute is used, attributes are inserted into replacement text without
expansion.
| Source |
<define-tag foo>quux</define-tag>
<define-tag bar attributes=verbatim endtag=required>
Body: %Ubody
Attributes: %Uattributes
</define-tag>
<bar txt="<foo>">Here we go</bar>
|
| Output |
Body: Here we go
Attributes: txt=<foo> |
| | | provide-tag | | name | | [attributes=verbatim] | | [endtag=required] | | [whitespace=delete] |
|
|
|
This command is similar to the previous one, except that no operation is
performed if this command was already defined.
Copy a function. This command is useful to save a macro definition
before redefining it.
| Source |
<define-tag foo>one</define-tag>
<let bar=foo>
<define-tag foo>two</define-tag>
<foo><bar>
|
| Output |
twoone |
Delete a command definition.
| Source |
<define-tag foo>one</define-tag>
<undef foo>
<foo>
|
| Output |
<foo> |
| | | set-hook | | name | | [position=before|after] | | [action=insert|append|replace] |
|
|
|
Add text to a predefined macro. This mechanism allows modifications
of existing macros without having to worry about its type, whether it is
complex or not.
| Source |
<let foo=add>
<set-hook foo position=before>
Before</set-hook>
<set-hook foo position=after>
After</set-hook>
<foo 1 2 3 4>
|
| Output |
Before10
After |
| S | | get-hook | | name | | [position=before|after] |
|
|
|
Print current hooks of a macro.
| Source |
Text inserted with position=before:<get-hook foo position=before>!
Text inserted with position=after:<get-hook foo position=after>!
|
| Output |
Text inserted with position=before:
Before!
Text inserted with position=after:
After! |
Like %attributes, except that attr=value pairs are
printed with double quotes surrounding attribute values, and a leading
space is added if some text is printed.
| Source |
<define-tag foo>;;;
%attributes
<img<attributes-quote %attributes>/>
</define-tag>
<foo id="logo" src="logo.gif" name="Logo" alt="Our logo">
<foo>
|
| Output |
id=logo src=logo.gif name=Logo alt=Our logo
<img id="logo" src="logo.gif" name="Logo" alt="Our logo"/>
<img/> |
| S | | attributes-extract | | name1 | | [,name2[,name3...]] | | %attributes |
|
|
|
Extract from %attributes the attr=value pairs for
names matching any of name1, name2....
| Source |
<define-tag img whitespace=delete>
<img* <attributes-extract name,src,alt %attributes> >
</define-tag>
<img id="logo" src="logo.gif" name="Logo" alt="Our logo" >
|
| Output |
<img src=logo.gif name=Logo alt=Our logo > |
| S | | attributes-remove | | name1 | | [,name2[,name3...]] | | %attributes |
|
|
|
Remove from %attributes the attr=value pairs for
names matching any of name1, name2....
| Source |
<define-tag img whitespace=delete>
<img* <attributes-quote <attributes-remove name,src,alt %attributes>>>
</define-tag>
<img id="logo" src="logo.gif" name="Logo" alt="Our logo" >
|
| Output |
<img id="logo" > |
Note:
The two previous functions are special, because unlike all other macros,
their expansion do not form a group. This is necessary to parse the
resulting list of attributes.
In those two functions, names of attributes may be regular expressions.
Main goal of these primitives is to help writing macros accepting any
kind of attributes without having to declare them. A canonical example
is
| Source |
<define-tag href whitespace=delete>
<preserve url name>
<set-var <attributes-extract url,name %attributes>>
<a <attributes-quote <attributes-remove url,name %attributes>>
href="<get-var url>"><get-var name></a>
<restore url name>
</define-tag>
<href class=web url="http://www.foo.com" name="Welcome" >
|
| Output |
<a class="web"
href="http://www.foo.com">Welcome</a> |
But we want now to add an image attribute. So we may write
| Source |
<define-tag href whitespace=delete>
<preserve url name image>
<set-var <attributes-extract url,name,image %attributes>>
<a <attributes-quote <attributes-remove url,name,image %attributes>>
href="<get-var url>">
<if <get-var image>
<img <attributes-quote <attributes-remove url,name,image %attributes>>
src="<get-var image>" alt="<get-var name>" border=0 >
<get-var name>>
</a>
<restore url name image>
</define-tag>
<href class=web url="http://www.foo.com" name="Welcome" image="foo.png">
|
| Output |
<a class="web"
href="http://www.foo.com"><img class="web"
src="foo.png" alt="Welcome" border=0 ></a> |
We need a mechanism to tell mp4h that some attributes refer to
specific HTML tags. A solution is to prepend attribute with tag name,
e.g.
| Source |
<define-tag href whitespace=delete>
<preserve url name image>
<set-var <attributes-extract url,name,image %attributes>>
<a <attributes-quote <attributes-extract a:.* %attributes>>
href="<get-var url>">
<if <get-var image>
<img <attributes-quote <attributes-extract img:.* %attributes>>
src="<get-var image>" alt="<get-var name>" >
<get-var name>>
</a>
<restore url name image>
</define-tag>
<href a:class=web img:id=logo img:border=1
url="http://www.foo.com" name="Welcome" image="foo.png">
|
| Output |
<a a:class="web"
href="http://www.foo.com"><img img:id="logo" img:border="1"
src="foo.png" alt="Welcome" ></a> |
This example shows that regular expressions may be used within
attributes names, but it is still incomplete, because we want to remove
prefix from attributes. One solution is with subst-in-string,
but there is a more elegant one:
| Source |
<define-tag href whitespace=delete>
<preserve url name image>
<set-var <attributes-extract url,name,image %attributes>>
<a <attributes-quote <attributes-extract :a:(.*) %attributes>>
href="<get-var url>">
<if <get-var image>
<img <attributes-quote <attributes-extract :img:(.*) %attributes>>
src="<get-var image>" alt="<get-var name>" >
<get-var name>>
</a>
<restore url name image>
</define-tag>
<href :a:class=web :img:id=logo :img:border=1
url="http://www.foo.com" name="Welcome" image="foo.png">
|
| Output |
<a class="web"
href="http://www.foo.com"><img id="logo" border="1"
src="foo.png" alt="Welcome" ></a> |
When there are subexpressions within regular expressions, they are
printed instead of the whole expression. Note also that i put a colon
before the prefix in order not to mix them with XML namespaces.
Entities
Entities are macros in the same way as tags, but they do not take
any arguments. Whereas tags are normally used to mark up text,
entities contain already marked up text. Also note that unlike tags,
entities are by default case sensitive.
An entity has the following form:
&entity;
This function lets you define your own entities.
First argument is the entity name. Replacement text is the function body.
| Source |
<define-entity foo>bar</define-entity>
&foo;
|
| Output |
bar |
Variables
Variables are a special case of simple tags, because they do not accept
attributes. In fact their use is different, because variables contain
text whereas macros act like operators.
A nice feature concerning variables is their manipulation as arrays.
Indeed variables can be considered like newline separated lists, which
will allow powerful manipulation functions as we will see below.
| S | | set-var | | name[=value] | | [name[=value]] ... |
|
|
|
This command sets variables.
| S | V | set-var-verbatim | | name[=value] | | [name[=value]] ... |
|
|
|
As above but attributes are read verbatim.
This command assigns a variable the value of the body of the
command. This is particularly useful when variable values contain
newlines and/or quotes.
Note that the variable can not be indexed with this command.
Note also, that this command behaves as set-var-verbatim: The body
is not expanded until the variable is shown with get-var.
Show variable contents. If a numeric value within square brackets is
appended to a variable name, it represents the index of an array.
The first index of arrays is 0 by convention.
| Source |
<set-var version="0.10.1">
This is version <get-var version>
<set-var-x name="osversion">Operating sytem is
"<include command="uname"><include command="uname -r">"</set-var-x>
<get-var osversion>
|
| Output |
This is version 0.10.1
Operating sytem is
"Linux
2.2.19-ide
" |
| Source |
<set-var foo="0
1
2
3">
<get-var foo[2] foo[0] foo>
|
| Output |
200
1
2
3 |
As above but attributes are not expanded.
| Source |
<define-tag foo>0.10.1</define-tag>
<set-var version="<foo>">;;;
Here is version <get-var version>
<set-var-verbatim version="<foo>">;;;
Here is version <get-var version>
<set-var-verbatim version="<foo>">;;;
Here is version <get-var-once version>
|
| Output |
Here is version 0.10.1
Here is version 0.10.1
Here is version <foo> |
All variables are global, there is no variable or macro scope.
For this reason a stack is used to preserve variables. When this
command is invoked, arguments are names of variables, whose values
are put at the top of the stack and variables are reset to an
empty string.
This is the opposite: arguments are names of variables, which are set to
the value found at the top of the stack, and stack is popped down.
Note:
The preserve tag pushes its last argument first, whereas
restore first pops its first argument.
| Source |
<define-tag foo whitespace=delete>
<preserve src name text>
<set-var %attributes>
Inside: src=<get-var src> name=<get-var name> text=<get-var text>
<restore src name text>
</define-tag>
<set-var src=foo.png text="Hello, World!">
Before: src=<get-var src> name=<get-var name> text=<get-var text>
<foo src=bar name=quux>
After: src=<get-var src> name=<get-var name> text=<get-var text>
|
| Output |
Before: src=foo.png name= text=Hello, World!
Inside: src=bar name=quux text=
After: src=foo.png name= text=Hello, World! |
Undefine variables.
Returns true when this variable exists.
Increment the variable whose name is the first argument. Default
increment is one.
- by=value
Change increment amount.
| Source |
<set-var i=10>
<get-var i>
<increment i><get-var i>
<increment i by="-3"><get-var i>
|
| Output |
10
11
8 |
Decrement the variable whose name is the first argument. Default
decrement is one.
- by=value
Change decrement amount.
| Source |
<set-var i=10>
<get-var i>
<decrement i><get-var i>
<decrement i by="3"><get-var i>
|
| Output |
10
9
6 |
Copy a variable into another.
| Source |
<set-var i=10>
<copy-var i j>
<get-var j>
|
| Output |
10 |
If this variable is not defined or is defined to an empty string, then
it is set to the second argument.
| Source |
<unset-var title>
<defvar title "Title"><get-var title>
<defvar title "New title"><get-var title>
|
| Output |
Title
Title |
Show informations on symbols. If it is a variable name, the STRING word is printed as well as the number of lines contained within
this variable.
If it is a macro name, one of the following messages is printed:
PRIM COMPLEX, PRIM TAG,
USER COMPLEX or USER TAG
| Source |
<set-var x="0\n1\n2\n3\n4">
<define-tag foo>bar</define-tag>
<define-tag bar endtag=required>quux</define-tag>
<symbol-info x>
<symbol-info symbol-info>
<symbol-info define-tag>
<symbol-info foo>
<symbol-info bar>
|
| Output |
STRING
5
PRIM TAG
PRIM COMPLEX
USER TAG
USER COMPLEX |
String Functions
Prints the length of the string.
| Source |
<set-var foo="0
1
2
3">;;;
<string-length <get-var foo>>
<set-var foo="0 1 2 3">;;;
<set-var l=<string-length <get-var foo>>>;;;
<get-var l>
|
| Output |
7
7 |
Convert to lowercase letters.
| Source |
<downcase "Does it work?">
|
| Output |
does it work? |
Convert to uppercase letters.
| Source |
<upcase "Does it work?">
|
| Output |
DOES IT WORK? |
Convert to a title, with a capital letter at the beginning of every
word.
| Source |
<capitalize "Does it work?">
|
| Output |
Does It Work? |
Extracts a substring from a string. First argument is original string,
second and third are respectively start and end indexes. By convention
first character has a null index.
| Source |
<set-var foo="abcdefghijk">
<substring <get-var foo> 4>
<substring <get-var foo> 4 6>
|
| Output |
efghijk
ef |
| S | | string-eq | | string1 | | string2 | | [caseless=true] |
|
|
|
Returns true if first two arguments are equal.
| Source |
1:<string-eq "aAbBcC" "aabbcc">
2:<string-eq "aAbBcC" "aAbBcC">
|
| Output |
1:
2:true |
- caseless=true
Comparison is case insensitive.
| Source |
1:<string-eq "aAbBcC" "aabbcc" caseless=true>
2:<string-eq "aAbBcC" "aAbBcC" caseless=true>
|
| Output |
1:true
2:true |
| S | | string-neq | | string1 | | string2 | | [caseless=true] |
|
|
|
Returns true if the first two arguments are not equal.
| Source |
1:<string-neq "aAbBcC" "aabbcc">
2:<string-neq "aAbBcC" "aAbBcC">
|
| Output |
1:true
2: |
- caseless=true
Comparison is case insensitive.
| Source |
1:<string-neq "aAbBcC" "aabbcc" caseless=true>
2:<string-neq "aAbBcC" "aAbBcC" caseless=true>
|
| Output |
1:
2: |
| S | | string-compare | | string1 | | string2 | | [caseless=true] |
|
|
|
Compares two strings and returns one of the values less,
greater or equal depending on this comparison.
| Source |
1:<string-compare "aAbBcC" "aabbcc">
2:<string-compare "aAbBcC" "aAbBcC">
|
| Output |
1:less
2:equal |
- caseless=true
Comparison is case insensitive.
| Source |
1:<string-compare "aAbBcC" "aabbcc" caseless=true>
|
| Output |
1:equal |
| S | | char-offsets | | string | | character | | [caseless=true] |
|
|
|
Prints an array containing indexes where the character appear in the
string.
- caseless=true
Comparison is case insensitive.
| Source |
1:<char-offsets "abcdAbCdaBcD" a>
2:<char-offsets "abcdAbCdaBcD" a caseless=true>
|
| Output |
1:0
8
2:0
4
8 |
Regular Expressions
Regular expression support is provided by the PCRE (Perl Compatible
Regular Expressions) library package, which is open source software,
copyright by the University of Cambridge.
This is a very nice piece of software, latest versions are available at
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/.
Before version 1.0.6, POSIX regular expressions were implemented.
For this reason, the following macros recognize two attributes,
caseless=true and singleline=true|false.
But Perl allows a much better control on regular expressions with so
called modifiers, which are assed to the new reflags
attribute. It may contain one or more modifiers:
| i | Matching is case insensitive |
| m | Treat string as multiple lines. When set, a ^ matches
any beginning of line, and $ any end of line. By default,
they match begin and end of string. |
| s | Treat string as single line. A dot (.) may also
match a newline, whereas it does not by default. |
| x | Allow formatted regular expression, that means whitespaces,
newlines and comments are removed from regular expression before
processing. |
Note:
Attribute singleline=true is a synonym for the s
modifier, whereas singleline=false is a synonym for the
m modifier. This behaviour was different up to mp4h 1.0.6.
| S | | subst-in-string | | string | | regexp | | [replacement] | | [caseless=true] | | [singleline=true|false] | | [reflags=[imsx]] |
|
|
|
Replace a regular expression in a string by a replacement text.
| Source |
<set-var foo="abcdefghijk">
<subst-in-string <get-var foo> "[c-e]">
<subst-in-string <get-var foo> "([c-e])" "\\1 ">
|
| Output |
abfghijk
abc d e fghijk |
| Source |
<set-var foo="abcdefghijk\nabcdefghijk\nabcdefghijk">
<subst-in-string <get-var foo> ".$" "">
<subst-in-string <get-var foo> ".$" "" singleline=false>
<subst-in-string <get-var foo> "
([a-c]) | [0-9]
" ":\\1:" reflags=x>
|
| Output |
abcdefghijk
abcdefghijk
abcdefghij
abcdefghij
abcdefghij
abcdefghij
:a::b::c:defghijk
:a::b::c:defghijk
:a::b::c:defghijk |
| S | | subst-in-var | | name | | regexp | | [replacement] | | [caseless=true] | | [singleline=true|false] | | [reflags=[imsx]] |
|
|
|
Performs substitutions inside variable content.
| S | | match | | string | | regexp | | [caseless=true] | | [singleline=true|false] | | [reflags=[imsx]] | | [action=report|extract|delete|startpos|endpos|length] |
|
|
|
- action=report
Prints true if string contains regexp.
- action=extract
Prints the expression matching regexp in string.
- action=delete
Prints the string without the expression matching regexp in string.
- action=startpos
Prints the first char of the expression matching regexp in string.
If there is no match, returns -1.
- action=endpos
Prints the last char of the expression matching regexp in string.
If there is no match, returns -1.
- action=length
Prints the length of the expression matching regexp in string.
| Source |
1:<match "abcdefghijk" "[c-e]+">
2:<match "abcdefghijk" "[c-e]+" action=extract>
3:<match "abcdefghijk" "[c-e]+" action=delete>
4:<match "abcdefghijk" "[c-e]+" action=startpos>
5:<match "abcdefghijk" "[c-e]+" action=endpos>
6:<match "abcdefghijk" "[c-e]+" action=length>
|
| Output |
1:true
2:cde
3:abfghijk
4:2
5:5
6:3 |
Arrays
With mp4h one can easily deal with string arrays. Variables can be
treated as a single value or as a newline separated list of strings.
Thus after defining
<set-var digits="0
1
2
3" >
one can view its content or one of these values:
| Source |
<get-var digits>
<get-var digits[2]>
|
| Output |
0
1
2
3
2 |
Returns an array size which is the number of lines present in the
variable.
| Source |
<array-size digits>
|
| Output |
4 |
Add a value (or more if this value contains newlines) at the end of an
array.
| Source |
<array-push digits "10\n11\n12">
<get-var digits>
|
| Output |
0
1
2
3
10
11
12 |
Remove the toplevel value of an array and returns this string.
Prints the last entry of an array.
| Source |
<array-topvalue digits>
|
| Output |
12 |
Add a value at the end of an array if this value is not already present
in this variable.
| Source |
<array-add-unique digits 2>
<get-var digits>
|
| Output |
0
1
2
3
10
11
12 |
- caseless=true
Comparison is case insensitive.
Concatenates all arrays into the first one.
| Source |
<set-var foo="foo">
<set-var bar="bar">
<array-concat foo bar><get-var foo>
|
| Output |
foo
bar |
If value is contained in array, returns its index otherwise returns -1.
| Source |
<array-member digits 11>
|
| Output |
5 |
- caseless=true
Comparison is case insensitive.
Shifts an array. If offset is negative, indexes below 0 are lost.
If offset is positive, first indexes are filled with empty strings.
| Source |
<array-shift digits 2>
Now: <get-var digits>
<array-shift digits -4>
And: <get-var digits>
|
| Output |
Now:
0
1
2
3
10
11
12
And: 2
3
10
11
12 |
- start=start
Change origin of shifts (default is 0).
| Source |
<array-shift digits -2 start=2><get-var digits>
|
| Output |
2
3
12 |
| S | | sort | | name | | [caseless=true] | | [numeric=true] | | [sortorder=reverse] |
|
|
|
Sort lines of an array in place. Default is to sort lines
alphabetically.
| Source |
<sort digits><get-var digits>
|
| Output |
12
2
3 |
- caseless=true
Comparison is case insensitive.
- numeric=true
Sort lines numerically
| Source |
<sort digits numeric=true><get-var digits>
|
| Output |
2
3
12 |
- sortorder=reverse
Reverse sort order
| Source |
<sort digits numeric=true sortorder=reverse>;;;
<get-var digits>
|
| Output |
12
3
2 |
Numerical operators
These operators perform basic arithmetic operations. When all operands
are integers result is an integer too, otherwise it is a float. These
operators are self-explanatory.
| S | | add | | number1 | | number2 | | [number3] ... |
|
|
|
| S | | substract | | number1 | | number2 | | [number3] ... |
|
|
|
| S | | multiply | | number1 | | number2 | | [number3] ... |
|
|
|
| S | | divide | | number1 | | number2 | | [number3] ... |
|
|
|
| S | | min | | number1 | | number2 | | [number3] ... |
|
|
|
| S | | max | | number1 | | number2 | | [number3] ... |
|
|
|
| Source |
<add 1 2 3 4 5 6>
<add 1 2 3 4 5 6.>
|
| Output |
21
21.000000 |
| Source |
<define-tag factorial whitespace=delete>
<ifeq %0 1 1 <multiply %0 "<factorial <substract %0 1>>">>
</define-tag>
<factorial 6>
|
| Output |
720 |
Unlike functions listed above the modulo function cannot handle more
than 2 arguments, and these arguments must be integers.
| Source |
<modulo 345 7>
|
| Output |
2 |
Those functions compare two numbers and returns true when this
comparison is true. If one argument is not a number, comparison
is false.
Returns true if first argument is greater than second.
Returns true if first argument is lower than second.
Returns true if arguments are equal.
Returns true if arguments are not equal.
Relational operators
Returns true if string is empty, otherwise returns an empty string.
Returns the last argument if all arguments are non empty.
Returns the first non empty argument.
Flow functions
| S | V | group | | expression | | [expression] ... | | [separator=string] |
|
|
|
This function groups multiple statements into a single one. Some
examples will be seen below with conditional operations.
A less intuitive but very helpful use of this macro is to preserve newlines
when whitespace=delete is specified.
| Source |
<define-tag text1>
Text on
3 lines without
whitespace=delete
</define-tag>
<define-tag text2 whitespace=delete>
Text on
3 lines with
whitespace=delete
</define-tag>
<define-tag text3 whitespace=delete>
<group "Text on
3 lines with
whitespace=delete">
</define-tag>
<text1>
<text2>
<text3>
|
| Output |
Text on
3 lines without
whitespace=delete
Text on3 lines withwhitespace=delete
Text on
3 lines with
whitespace=delete |
Note that newlines are suppressed in text2 and result is
certainly unwanted.
| | | compound | | expression | | [expression] ... | | [separator=string] |
|
|
|
Like group, but this tag is complex.
- separator=string
By default arguments are put aside. This attribute define a separator
inserted between arguments.
Does the opposite job to group, its argument is no more
treated as a single object when processed by another command.
Prints its arguments without expansion. They will never be expanded
unless the expand tag is used to cancel this noexpand tag.
Cancels the noexpand tag.
| Source |
<subst-in-string "=LT=define-tag foo>bar=LT=/define-tag>" "=LT=" "<">
<foo>
<subst-in-string "=LT=define-tag foo>quux=LT=/define-tag>" "=LT="
"<noexpand "<">">
<foo>
|
| Output |
bar
<define-tag foo>quux</define-tag>
bar |
| S | V | if | | string | | then-clause | | [else-clause] |
|
|
|
If string is non empty, second argument is evaluated otherwise third
argument is evaluated.
| Source |
<define-tag test whitespace=delete>
<if %0 "yes" "no">
</define-tag>
<test "string">
<test "">
|
| Output |
yes
no |
| S | V | ifeq | | string1 | | string2 | | then-clause | | [else-clause] |
|
|
|
If first two arguments are identical strings, third argument is evaluated
otherwise fourth argument is evaluated.
| S | V | ifneq | | string1 | | string2 | | then-clause | | [else-clause] |
|
|
|
If first two arguments are not identical strings, third argument is
evaluated otherwise fourth argument is evaluated.
When argument is not empty, its body is evaluated.
While condition is true, body function is evaluated.
| Source |
<set-var i=10>
<while <gt <get-var i> 0>>;;;
<get-var i> <decrement i>;;;
</while>
|
| Output |
10 9 8 7 6 5 4 3 2 1 |
| | | foreach | | variable | | array | | [start=start] | | [end=end] | | [step=pas] |
|
|
|
This macro is similar to the foreach Perl's macro:
a variable loops over array values and function body is evaluated for each
value.
first argument is a generic variable name, and second is the name of an
array.
| Source |
<set-var x="1\n2\n3\n4\n5\n6">
<foreach i x><get-var i> </foreach>
|
| Output |
1 2 3 4 5 6 |
- start=start
Skips first indexes.
| Source |
<set-var x="1\n2\n3\n4\n5\n6">
<foreach i x start=3><get-var i> </foreach>
|
| Output |
4 5 6 |
- end=end
Stops after index has reached that value.
| Source |
<set-var x="1\n2\n3\n4\n5\n6">
<foreach i x end=3><get-var i> </foreach>
|
| Output |
1 2 3 |
- step=step
Change index increment (default is 1).
If step is negative, array is treated in reverse order.
| Source |
<set-var x="1\n2\n3\n4\n5\n6">
<foreach i x step=2><get-var i> </foreach>
<foreach i x step=-2><get-var i> </foreach>
|
| Output |
1 3 5
6 4 2 |
| S | V | var-case | | var1=value1 action1 | | [var2=value2 action2 ... |
|
|
|
This command performs multiple conditions with a single instruction.
| Source |
<set-var i=0>
<define-tag test>
<var-case
x=1 <group <increment i> x<get-var i>>
x=2 <group <decrement i> x<get-var i>>
y=1 <group <increment i> y<get-var i>>
y=2 <group <decrement i> y<get-var i>>>
</define-tag>
<set-var x=1 y=2><test>
<set-var x=0 y=2><test>
|
| Output |
x1y0
y-1 |
Breaks the innermost while loop.
| Source |
<set-var i=10>
<while <gt <get-var i> 0>>;;;
<get-var i> <decrement i>;;;
<ifeq <get-var i> 5 <break>>;;;
</while>
|
| Output |
10 9 8 7 6 |
This command immediately exits from the innermost macro.
A message may also be inserted. But this macro changes token parsing
so its use may become very hazardous in some situations.
- up=number
This attribute determines how much levels have to be exited. By default
only one level is skipped. With a null value, all current macros are
exited from. A negative value do the same, and stops processing current
file.
Prints a warning on standard error.
| S | | exit | | [status=rc] | | [message=string] |
|
|
|
Immediately exits program.
- message=string
Prints a message to the standard error.
- status=rc
Selects the code returned by the program (-1 by default).
This is a special command: its content is stored and will be
expanded after end of input.
File functions
Returns a newline separated list of files contained in a given directory.
| Source |
<directory-contents . matching=".*\\.mp4h$">
|
| Output |
mp4h.mp4h |
Resolves all symbolic links, extra ``/'' characters and references
to /./ and /../ in pathname, and expands into the resulting absolute pathname.
All but the last component of pathname must exist when real-path is called.
This tag is particularly useful when comparing if file or directory names
are identical.
| Source |
<real-path pathname=<__file__>>
|
| Output |
/home/barbier/Projets/Wml/web/docs/backend/mp4h.mp4h |
Returns true if file exists.
Returns an array of informations on this file. These informations are:
size, type, ctime, mtime, atime, owner and group.
| Source |
<get-file-properties <__file__>>
|
| Output |
68246
FILE
1004486304
1004486304
1004486305
barbier
barbier |
| S | | include | | file=filename | command=command-line | | [alt=action] | | [verbatim=true] |
|
|
|
Insert the contents of a file in the file system - if the file
attribute is given -, or the output from executing a system command - if the
command attribute is given - into the input stream.
For backwards compatibility, if neither the file nor the
command attributes are given, the first argument is taken
as a file to include.
- file=filename
The given file is read and inserted into the input stream.
This attribute cannot be combined with the command attribute.
Files are first searched in current directory, then in
directories specified on command-line with the -I option, next
in directories listed in the MP4HPATH environment variable, and last
under the compile-time location (/usr/local/share/mp4h
by default).
- command=command-line
The given command line is executed on the operating system, and the output
of it is inserted in the input stream. This attribute cannot be combined
with the file attribute.
The given command line is executed using the
popen(3) standard C library routine. The command is executed using the standard
system shell, which on Posix compliant systems is sh(1).
- alt=action
If file is not found, this alternate action is handled. If this atribute
is not set and file is not found, then an error is raised. This attribute has no effect
when the command attribute is specified.
- verbatim=true
File content is included without expansion.
This is similar to using the m4 undivert macro with a filename as argument.
| Source |
<include command="uname -a">
|
| Output |
Linux liberte 2.2.19-ide #1 Sat Oct 20 18:31:37 EST 2001 i586 unknown |
Load definitions from a package file.
This tag does nothing, its body is simply discarded.
Change comment characters.
| S | | set-quotes | | [string string] | | [display=visible] |
|
|
|
By default, all characters between "" and "" pairs are read without
parsing. When called without argument, this macro inhibates this
feature. When called with two arguments, it redefines begin and end
delimiters. Begin delimiter must begin with a left-angle bracket, and
end delimiter must end with a right-angle bracket.
- display=visible
Delimiters are also written into output.
Diversion functions
Diversions are a way of temporarily saving output.
The output of mp4h can at any time be diverted to a temporary file,
and be reinserted into the output stream, undiverted, again at a later time.
Numbered diversions are counted from 0 upwards,
diversion number 0 being the normal output stream.
The number of simultaneous diversions is limited mainly by the memory used
to describe them, because mp4h tries to keep diversions in memory.
However, there is a limit to the overall memory usable by all diversions
taken altogether. When this maximum is about to be exceeded, a
temporary file is opened to receive the contents of the biggest
diversion still in memory, freeing this memory for other diversions.
So, it is theoretically possible that the number of diversions be
limited by the number of available file descriptors.
| S | | divert | | [ divnum=diversion-number ] |
|
|
|
Output is diverted using this tag, where diversion-number is the diversion
to be used. If the divnum attribute is left out, diversion-number is assumed
to be zero.
If output is diverted to a non-existent diversion, it is simply discarded.
This can be used to suppress unwanted output. See the example below.
When all mp4h input will have been processed, all existing diversions
are automatically undiverted, in numerical order.
Several calls of divert with the same argument do not overwrite the previous diverted text, but append to it.
| Source |
<divert divnum="-1">
This is sent nowhere...
<divert>
This is output.
|
| Output |
This is sent nowhere...
This is output. |
| S | | undivert | | [ divnum=diversion-number ] |
|
|
|
This tag explicitly undiverts diverted text saved in the diversion with the
specified number. If the divnum attribute is not given, all diversions
are undiverted, in numerical order.
When diverted text is undiverted, it is not reread by mp4h,
but rather copied directly to the current output. It is therefore
not an error to undivert into a diversion.
Unlike m4, the mp4h undivert tag does not allow a file name
as argument. The same can be accomplished with the include tag
with the verbatim="true" attribute.
| Source |
<divert divnum="1">
This text is diverted.
<divert>
This text is not diverted.
<undivert divnum="1">
|
| Output |
This text is diverted.
This text is not diverted. |
This tag expands to the number of the current diversion.
| Source |
Initial <divnum>
<divert divnum="1">
Diversion one: <divnum>
<divert divnum="2">
Diversion two: <divnum>
<divert>
|
| Output |
Initial 0
Diversion one: 1
Diversion two: 2 |
Debugging functions
When constructs become complex it could be hard to debug them.
Functions listed below are very useful when you could not figure what is
wrong. These functions are not perfect yet and must be improved in
future releases.
Prints the replacement text of a user defined macro. For instance, the
macro used to generate all examples of this documentation is
| Source |
<function-def example>
|
| Output |
<set-var-verbatim verb-body=%ubody>
<subst-in-var verb-body "&" "&">
<subst-in-var verb-body "<" "<">
<subst-in-var verb-body ">" ">">
<set-var body=%body>
<subst-in-var body "<(/?[a-z]*)[*]" "<\\1">
<subst-in-var body "&" "&">
<subst-in-var body "<" "<">
<subst-in-var body ">" ">">
<subst-in-var body "<three-colon>[^;\n]*\n[ \t]*" "">
<subst-in-var body "<three-colon>$" "" reflags=m>
<subst-in-var body "^\n*(.*?)\n*$" "\\1" reflags=s>
<table border=2 cellpadding=0 cellspacing=0 width="80%" summary="">
<tr><th bgcolor="#ccccff" align=left> Source</th></tr>
<tr><td bgcolor="#ccff99" width="80%"><dnl>
<pre><get-var-once verb-body></pre><dnl>
</td></tr>
<tr><th bgcolor="#ccccff" align=left> Output</th></tr>
<tr><td bgcolor="#ff99cc" width="80%"><dnl>
<pre><get-var-once body></pre><dnl>
</td></tr>
</table> |
This comand acts like the -d flag but can be ynamically
changed.