Documentation: Core / mp4h (Pass 2)

Introduction Frontends Backends Includes Auxilliaries

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

--helpdisplay an help message and exit
--versionoutput mp4h version information and exit
-E --fatal-warningsstop execution after first warning
-Q --quiet --silentsuppress some warnings for builtins
-S --safety-level=NUMBERdisable 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=DIRECTORYsearch this directory for includes and packages
-D --define=NAME[=VALUE]set variable NAME to VALUE, or empty
-U --undefine=COMMANDdelete builtin COMMAND
-s --synclinesgenerate `#line NO "FILE"' lines

Parser features

-c --caseless=NUMBERset 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=NAMEspecify document encoding. Valid options are `8bit' (default) or `utf8'.
-X --expansion=NUMBERset parser behaviour according to the bits of NUMBER

NUMBER is a combination of

1do not parse unknown tags
2unknown tags are assumed being simple
4trailing star in tag name do not make this tag simple
8an unmatched end tag closes all previous unmatched begin tags
16interpret backslashes as printf
32remove trailing slash in tag attributes
64do not remove trailing star in tag name
128do not remove leading star in tag name
256do not add a space before trailing slash in tag attributes
1024suppress warnings about bad nested tags
2048suppress warnings about missing trailing slash

In version 1.2.3, default value is 3114=2+8+32+1024+2048.

Limits control

-H --hashsize=PRIMEset symbol lookup hash table size (default 509)
-L -nesting-limit=NUMBERchange artificial nesting limit (default 250)

Debugging

-d --debug=FLAGSset debug level (no FLAGS implies `aeq')
-t --trace=NAMEtrace NAME when it will be defined
-l --arglength=NUMBERrestrict macro tracing size
-o --error-output=FILEredirect debug and trace output

Flags are any of:

ttrace for all macro calls, not only debugging-on'ed
ashow actual arguments
eshow expansion
cshow before collect, after collect and after call
xadd a unique macro call id, useful with c flag
fsay current input file name
lsay current input line number
pshow results of path searches
ishow changes in input files
Vshorthand 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.

 

  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.

 

S let
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

 

S undef
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

 

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!

 

S attributes-quote
%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/>

 

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;

 

  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.

 

S set-var
name[=value]
[name[=value]] ...

This command sets variables.

 

SVset-var-verbatim
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.

 

S get-var
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 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

 

SVget-var-once
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>

 

S preserve
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.

 

S restore
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!

 

S unset-var
name
[name] ...

Undefine variables.

 

S var-exists
name

Returns true when this variable exists.

 

S increment
name
[by=value]

Increment the variable whose name is the first argument. Default increment is one.

   Source
<set-var i=10>
<get-var i>
<increment i><get-var i>
<increment i by="-3"><get-var i>
   Output
10
11
8

 

S decrement
name
[by=value]

Decrement the variable whose name is the first argument. Default decrement is one.

   Source
<set-var i=10>
<get-var i>
<decrement i><get-var i>
<decrement i by="3"><get-var i>
   Output
10
9
6

 

S copy-var
src
dest

Copy a variable into another.

   Source
<set-var i=10>
<copy-var i j>
<get-var j>
   Output
10

 

S defvar
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

 

S symbol-info
name

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

 

S string-length
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

 

S downcase
string

Convert to lowercase letters.

   Source
<downcase "Does it work?">
   Output
does it work?

 

S upcase
string

Convert to uppercase letters.

   Source
<upcase "Does it work?">
   Output
DOES IT WORK?

 

S capitalize
string

Convert to a title, with a capital letter at the beginning of every word.

   Source
<capitalize "Does it work?">
   Output
Does It Work?

 

S substring
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

 

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
   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:
   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
   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.

   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:

iMatching is case insensitive
mTreat 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.
sTreat string as single line. A dot (.) may also match a newline, whereas it does not by default.
xAllow 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]
   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

 

S array-size
name

Returns an array size which is the number of lines present in the variable.

   Source
<array-size digits>
   Output
4

 

S array-push
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

 

S array-pop
name

Remove the toplevel value of an array and returns this string.

 

S array-topvalue
name

Prints the last entry of an array.

   Source
<array-topvalue digits>
   Output
12

 

S array-add-unique
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

 

S array-concat
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

 

S array-member
name
value
[caseless=true]

If value is contained in array, returns its index otherwise returns -1.

   Source
<array-member digits 11>
   Output
5

 

S array-shift
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

 

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

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

 

S modulo
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.

 

S gt
number1
number2

Returns true if first argument is greater than second.

 

S lt
number1
number2

Returns true if first argument is lower than second.

 

S eq
number1
number2

Returns true if arguments are equal.

 

S neq
number1
number2

Returns true if arguments are not equal.

Relational operators

 

S not
string

Returns true if string is empty, otherwise returns an empty string.

 

S and
string
[string] ...

Returns the last argument if all arguments are non empty.

 

S or
string
[string] ...

Returns the first non empty argument.

Flow functions

 

SVgroup
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.

 

S disjoin
expression

Does the opposite job to group, its argument is no more treated as a single object when processed by another command.

 

SVnoexpand
command
[command] ...

Prints its arguments without expansion. They will never be expanded unless the expand tag is used to cancel this noexpand tag.

 

S expand
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

 

SVif
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

 

SVifeq
string1
string2
then-clause
[else-clause]

If first two arguments are identical strings, third argument is evaluated otherwise fourth argument is evaluated.

 

SVifneq
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.

 

 Vwhile
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 

 

SVvar-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

 

S break

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 

 

S return
[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.

 

S warning
string

Prints a warning on standard error.

 

S exit
[status=rc]
[message=string]

Immediately exits program.

 

  at-end-of-file

This is a special command: its content is stored and will be expanded after end of input.

File functions

 

S directory-contents
dirname
[matching=regexp]

Returns a newline separated list of files contained in a given directory.

   Source
<directory-contents . matching=".*\\.mp4h$">
   Output
mp4h.mp4h

 

S real-path
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
/home/barbier/Projets/Wml/web/docs/backend/mp4h.mp4h

 

S file-exists
filename

Returns true if file exists.

 

S get-file-properties
filename

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.

   Source
<include command="uname -a">
   Output
Linux liberte 2.2.19-ide #1 Sat Oct 20 18:31:37 EST 2001 i586 unknown

 

S use
name=package

Load definitions from a package file.

 

  comment

This tag does nothing, its body is simply discarded.

 

S set-eol-comment
[string]

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.

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.

 

S divnum

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.

 

S function-def
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 "&" "&amp;">
<subst-in-var verb-body "<" "&lt;">
<subst-in-var verb-body ">" "&gt;">
<set-var body=%body>
<subst-in-var body "<(/?[a-z]*)[*]" "<\\1">
<subst-in-var body "&" "&amp;">
<subst-in-var body "<" "&lt;">
<subst-in-var body ">" "&gt;">
<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>&nbsp;&nbsp;&nbsp;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>&nbsp;&nbsp;&nbsp;Output</th></tr>
    <tr><td bgcolor="#ff99cc" width="80%"><dnl>
      <pre><get-var-once body></pre><dnl>
    </td></tr>
</table>

 

S debugmode
string

This comand acts like the -d flag but can be ynamically changed.