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
FunctionMacrosNote: 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 "<URL:http://www.w3.org/People/Raggett/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.
• let "S"
"new=old"
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
• undef "S"
"name"
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
• get-hook "S"
"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!
• attributes-quote "S"
"%attributes"
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/>
• attributes-extract "S"
"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 />
• attributes-remove "S"
"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;
• define-entity
"name"
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.
• set-var "S"
"name[=value]" "[name[=value]] ..."
This command sets variables.
• set-var-verbatim "S""V"
"name[=value]" "[name[=value]] ..."
As above but attributes are read verbatim.
• set-var-x
"name=variable-name"
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.
• get-var "S"
"name" "[name] ..."
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 system is
"<include command="uname" />"</set-var-x>
<get-var osversion />
Output:
This is version 0.10.1
Operating system is
"Linux
"
Source:
<set-var foo="0
1
2
3" />
<get-var foo[2] foo[0] foo />
Output:
200
1
2
3
• get-var-once "S""V"
"name" "[name] ..."
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/>
• preserve "S"
"name" "[name] ..."
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.
• restore "S"
"name" "[name] ..."
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!
• unset-var "S"
"name" "[name] ..."
Undefine variables.
• var-exists "S"
"name"
Returns "true" when this variable exists.
• increment "S"
"name" "[by=value]"
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 "S"
"name" "[by=value]"
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-var "S"
"src" "dest"
Copy a variable into another.
Source:
<set-var i=10 />
<copy-var i j />
<get-var j />
Output:
10
• defvar "S"
"name" "value"
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
• symbol-info "S"
"name"
Show information 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
StringFunctions
• string-length "S"
"string"
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
• downcase "S"
"string"
Convert to lowercase letters.
Source:
<downcase "Does it work?" />
Output:
does it work?
• upcase "S"
"string"
Convert to uppercase letters.
Source:
<upcase "Does it work?" />
Output:
DOES IT WORK?
• capitalize "S"
"string"
Convert to a title, with a capital letter at the beginning of every word.
Source:
<capitalize "Does it work?" />
Output:
Does It Work?
• substring "S"
"string" "[start [end]]"
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
• string-eq "S"
"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
• string-neq "S"
"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:
• string-compare "S"
"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
• char-offsets "S"
"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
• printf "S"
"format" "string" "[string ...]"
Prints according to a given format. Currently only the %s flag character is recognized, and "$"
extension is supported to change order of arguments.
Source:
1:<printf "foo %s bar %s" baz 10 />
2:<printf "foo %2$s bar %1$s" baz 10 />
Output:
1:foo baz bar 10
2:foo 10 bar baz
RegularExpressions
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
"<URL: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.
• subst-in-string "S"
"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
• subst-in-var "S"
"name" "regexp" "[replacement]" "[caseless=true]" "[singleline=true|false]" "[reflags=[imsx]]"
Performs substitutions inside variable content.
• match "S"
"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
• array-size "S"
"name"
Returns an array size which is the number of lines present in the variable.
Source:
<array-size digits />
Output:
4
• array-push "S"
"name" "value"
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
• array-pop "S"
"name"
Remove the toplevel value of an array and returns this string.
• array-topvalue "S"
"name"
Prints the last entry of an array.
Source:
<array-topvalue digits />
Output:
12
• array-add-unique "S"
"name" "value" "[caseless=true]"
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.
• array-concat "S"
"name1" "[name2] ..."
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
• array-member "S"
"name" "value" "[caseless=true]"
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.
• array-shift "S"
"name" "offset" "[start=start]"
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
• sort "S"
"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
Numericaloperators
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.
• add "S"
"number1" "number2" "[number3] ..."
• substract "S"
"number1" "number2" "[number3] ..."
• multiply "S"
"number1" "number2" "[number3] ..."
• divide "S"
"number1" "number2" "[number3] ..."
• min "S"
"number1" "number2" "[number3] ..."
• max "S"
"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
• modulo "S"
"number1" "number2"
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.
• gt "S"
"number1" "number2"
Returns "true" if first argument is greater than second.
• lt "S"
"number1" "number2"
Returns "true" if first argument is lower than second.
• eq "S"
"number1" "number2"
Returns "true" if arguments are equal.
• neq "S"
"number1" "number2"
Returns "true" if arguments are not equal.
Relationaloperators
• not "S"
"string"
Returns "true" if string is empty, otherwise returns an empty string.
• and "S"
"string" "[string] ..."
Returns the last argument if all arguments are non empty.
• or "S"
"string" "[string] ..."
Returns the first non empty argument.
Flowfunctions
• group "S""V"
"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.
• disjoin "S"
"expression"
Does the opposite job to "group", its argument is no more treated as a single object when processed by
another command.
• noexpand "S""V"
"command" "[command] ..."
Prints its arguments without expansion. They will never be expanded unless the "expand" tag is used to
cancel this "noexpand" tag.
• expand "S"
"command" "[command] ..."
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
• if "S""V"
"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
• ifeq "S""V"
"string1" "string2" "then-clause" "[else-clause]"
If first two arguments are identical strings, third argument is evaluated otherwise fourth argument is
evaluated.
• ifneq "S""V"
"string1" "string2" "then-clause" "[else-clause]"
If first two arguments are not identical strings, third argument is evaluated otherwise fourth argument
is evaluated.
• when
"string"
When argument is not empty, its body is evaluated.
• while "V"
"cond"
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
• var-case "S""V"
"var1=value1action1" "[var2=value2action2 ..."
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
• break "S"
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
• return "S"
"[up=number]" "string"
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.
• warning "S"
"string"
Prints a warning on standard error.
• exit "S"
"[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).
• at-end-of-file
This is a special command: its content is stored and will be expanded after end of input.
Filefunctions
• directory-contents "S"
"dirname" "[matching=regexp]"
Returns a newline separated list of files contained in a given directory.
Source:
<directory-contents . matching=".*\\.mp4h$" />
Output:
mp4h.mp4h
• real-path "S"
"patname=pathname"
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:
/build/mp4h-MsMTo_/mp4h-1.3.1/doc/mp4h.mp4h
• file-exists "S"
"filename"
Returns "true" if file exists.
• get-file-properties "S"
"filename"
Returns an array of information on this file. These information are: size, type, ctime, mtime, atime,
owner and group.
Source:
<get-file-properties <__file__/> />
Output:
68604
FILE
1530057894
1530057894
1530057894
root
root
• include "S"
"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 "MP4HLIB" environment variable (it used to be
"MP4HPATH" for versions prior to 1.3), and last under the compile-time location
("/usr/local/lib/mp4h/1.3.1:/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 attribute 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 -s" />
Output:
Linux
• use "S"
"name=package"
Load definitions from a package file.
• comment
This tag does nothing, its body is simply discarded.
• set-eol-comment "S"
"[string]"
Change comment characters.
• set-quotes "S"
"[stringstring]" "[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.
Diversionfunctions
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.
• divert "S"
"[ 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.
• undivert "S"
"[ 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.
• divnum "S"
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
Debuggingfunctions
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.
• function-def "S"
"name"
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 "^\n*" "" /><subst-in-var verb-body "^" " " reflags=m /><set-var body=%body /><subst-in-var body "<three-colon/>[^;\n]*\n[ \t]*" "" /><subst-in-var body "<three-colon/>$" "" reflags=m /><subst-in-var body "^\n*" "" /><subst-in-var body "^" " " reflags=m /><group "Source:
<get-var-once verb-body />
Output:
<get-var-once body />
" />
• debugmode "S"
"string"
This command acts like the "-d" flag but can be ynamically changed.
• debugfile "S"
"filename"
Selects a file where debugging messages are diverted. If this filename is empty, debugging messages are
sent back to standard error, and if it is set to "-" these messages are discarded.
Note: There is no way to print these debugging messages into the document being processed.
• debugging-on "S"
"name" "[name] ..."
Declare these macros traced, i.e. information about these macros will be printed if "-d" flag or
"debugmode" macro are used.
• debugging-off "S"
"name" "[name] ..."
These macros are no more traced.
Miscellaneous
• __file__ "S"
"[name]"
Without argument this macro prints current input filename. With an argument, this macro sets the string
returned by future invocation of this macro.
• __line__ "S"
"[number]"
Without argument this macro prints current number line in input file. With an argument, this macro sets
the number returned by future invocation of this macro.
Source:
This is <__file__/>, line <__line__/>.
Output:
This is ./mp4h.mp4h, line 2201.
If you closely look at source code you will see that this number is wrong. Indeed the number line is the
end of the entire block containing this instruction.
• __version__ "S"
Prints the version of mp4h.
• dnl "S"
Discard all characters until newline is reached. This macro ensures that following string is a comment
and does not depend of the value of comment characters.
Source:
<dnl/>This is a comment
foo
<dnl/>This is a comment
bar
Output:
foo
bar
• date "S"
"[epoch]"
Prints local time according to the epoch passed on argument. If there is no argument, current local time
is printed.
"time"
An epoch time specification.
"format"
A format specification as used with the strftime(3) C library routine.
Source:
<date/>
<set-var info=<get-file-properties <__file__/> /> />
<date <get-var info[2] /> />
<date time="<get-var info[2] />" format="%Y-%m-%d %H:%M:%S" />
Output:
Wed Jun 27 00:04:54 2018
Wed Jun 27 00:04:54 2018
2018-06-27 00:04:54
• timer "S"
Prints the time spent since last call to this macro. The printed value is the number of clock ticks, and
so is dependent of your CPU.
Source:
<timer/>
The number of clock ticks since the beginning of the parsing of
this example by &mp4h; is:
<timer/>
Output:
user 23
sys 23
The number of clock ticks since the beginning of the parsing of
this example by mp4h is:
user 23
sys 23
• mp4h-l10n "S"
"name=value"
Set locale-specific variables. By default, the portable "C" locale is selected. As locales have
different names on different platforms, you must refer to your system documentation to find which values
are adapted to your system.
• mp4h-output-radix "S"
"number"
Change the output format of floats by setting the number of digits after the decimal point. Default is to
print numbers in the "%6.f" format.
Source:
<add 1.2 3.4 />
<mp4h-output-radix 2 />
<add 1.2 3.4 />
Output:
4.600000
4.60