I've developed WPP by keeping in mind that it had to be easy to use, possibly
faster than other solutions (i.e. writing a C or Perl program ad hoc)
and flexible. I've added some basic features and provided few useful macros
shipped with it. But in everyday work you may need extra features that WPP
doesn't have or simply you need a way for doing something during the
preprocessing and incorporating it's output.
The following built-in macros allows you to extend the capabilities of WPP by
writing more flexible and powerful macros.
The SYSTEM macro was the first way for allowing more complex jobs within
the preprocessing stage, the other way is through the
EVAL macro.
This macro allows you calling other programs or shell commands and
optionally parse the output through wpp.
Macro |
Expanded to |
@SYSTEM(CMD)@
|
The output of 'CMD' command.
|
@SYSTEM(CMD, DOPP)@
@SYSTEM_PP(CMD)@
|
The command output postprocessed through WPP if 'DOPP' isn't an empty
string. SYSTEM_PP is an alias for SYSTEM with postprocessed output.
|
The following example build a table with two lists obtained by the UNIX
"ls" command. Each line is passed through "sed" in order to put it
as argument for a RED macro. Please notice that in order to prevent the macro
parsing before the SYSTEM execution I have replaced the beginning and ending
'@' with the escaped version '@AT@'.

Source
@MACRO RED(TEXT)@
<span style="color: red;">@TEXT@</span>
@ENDMACRO@
@CMD=ls --color=no -1 / | sed 's|^| @AT@RED("|; s|/||g; s|$|")@AT@|g'@
<table>
<tr>
<td>
System #1:
<pre>
@SYSTEM("@CMD@")@
</pre>
</td>
<td>
System #2:
<pre>
@SYSTEM("@CMD@", "1")@
</pre>
</td>
</tr>
</table>
And a sample output may look like that:

Output
System #1:
@RED("bin")@
@RED("boot")@
@RED("dev")@
@RED("etc")@
@RED("home")@
@RED("initrd")@
@RED("lib")@
@RED("lost+found")@
@RED("MacOSX")@
@RED("mnt")@
@RED("opt")@
@RED("proc")@
@RED("root")@
@RED("sbin")@
@RED("tftpboot")@
@RED("tmp")@
@RED("usr")@
@RED("var")@
|
System #2:
bin
boot
dev
etc
home
initrd
lib
lost+found
MacOSX
mnt
opt
proc
root
sbin
tftpboot
tmp
usr
var
|
The first call of SYSTEM isn't postprocessed while the second is, in fact the
RED macro call was successfully expanded.
The EVAL macro was added in order to allow more sophisticated expansions and it
was a way for adding loops and complex controls without implementing them
directly (yeah, I'm a lazy boy!).
The argument string should be
a valid Perl expression,
otherwise wpp will warn you of syntax errors without stopping the parsing
process.
Macro |
Expanded to |
@EVAL(expr)@
|
The value returned by the Perl expression expr.
|
The following example shows a simple for loop (in Perl), it outputs a
sequence of numbers starting from 0 up to 10. Please notice how the '"' char
should be still escaped throgh '\"'.

Source
@EVAL(" \
for($i = 0, $str = ''; $i < 11; $i++) { \
$str .= $i . ' '; \
} \
return $str; \
")@

Output
0 1 2 3 4 5 6 7 8 9 10
The string passed as argument to the EVAL macro can contain wpp variables
and macros, they will be expanded before evaluation through Perl's eval.

Source
@LIMIT=11@
@EVAL(" \
for($i = 0, $str = ''; $i < @LIMIT@; $i++) { \
$str .= \"@RANDOM()@ \"; \
} \
return $str; \
")@

Output
297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024 297803867539024
If you run the previous example you can notice that the RANDOM() output is
always the same, that's because the evaluation of RANDOM() is done before the
eval call.
Within a evaluated string you could call wpp parser by using the function
WPP::call, which takes a macro name and it's arguments as input and
returns the parsed string.
In the following example I've modified the previous one in order to use
WPP::call.

Source
@LIMIT=11@
@EVAL(" \
for($i = 0, $str = ''; $i < @LIMIT@; $i++) { \
$str .= WPP::call('RANDOM') . ' '; \
} \
return $str; \
")@

Output
0538067178375705 363470595063511 181241116357516 764573079451026 882420272950935 870727557130415 92754659884783 488164470727881 0966769347851617 597927443423963 272674405494033
This is a bit more complex example, here I open and read a file
(/etc/group), for each line of it I call the macro TEST that simply print it
within square brackets.

Source
@MACRO TEST(TEXT)@
[@TEXT@]
@ENDMACRO@
@F=/etc/group@
@EVAL(" \
$str = ''; \
open(FH, '@F@'); \
while (<FH>) { \
chomp; \
$str .= WPP::call('TEST', $_) . \"\n\"; \
}; \
close(FH); \
return $str; \
")@

Output
[root:x:0:root]
[bin:x:1:root,bin,daemon]
[daemon:x:2:root,bin,daemon]
[sys:x:3:root,bin,adm]
[adm:x:4:root,adm,daemon]
[tty:x:5:]
[disk:x:6:root]
Here you can see how to use EVAL for test conditions.

Source
@TVAL=@EVAL("1 != 1")@@
@IF !TVAL@
EVAL ok!
@ENDIF@
@TVAL=@EVAL("1 == 1")@@
@IF TVAL@
EVAL ok!
@ENDIF@

Output
EVAL returns the value returned by the Perl expression, however if you don't
want return a value, just because you've already done it with a print or
something similar inside the Perl expression, you have to return explicitly an
empty string (tipically a "return '';"). Note that
the print
statement could be effectively printed before the text preceding the EVAL
call, that's because WPP buffers its output, so
don't use print or
printf, instead output data within a string and return it at the end of the
computation process.
The second line of the example shows a safer way for outputing data.

Source
@EVAL("print 'TEST ' . (1 == 1); return '';")@
@EVAL("return 'TEST ' . (1 == 1);")@
The following and last example shows an invalid expression that raise an
EVAL error, the parsing doesn't stop but a warning is printed by WPP.

test_eval_err.raw
@HEAD@
@TAIL@
$Date$
@EVAL("1+1'A'")@
And here is shown the output of wpp.
[ko]$ wpp - < test_eval_err.raw
W2: EVAL error 'String found where operator expected at (eval 2) line 1, near "1'A'"' (EVAL(v1):-:4)
W2: EVAL error
****
1+1'A'
****
W2: EVAL error ' (Missing operator before 'A'?)' (EVAL(v1):-:4)
W2: EVAL error
****
1+1'A'
****
W2: EVAL error 'syntax error at (eval 2) line 1, near "1'A'"' (EVAL(v1):-:4)
W2: EVAL error
****
1+1'A'
****