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("misc")@
@RED("mnt")@
@RED("movies")@
@RED("opt")@
@RED("proc")@
@RED("rar")@
@RED("root")@
@RED("sbin")@
@RED("tftpboot")@
@RED("tmp")@
@RED("usr")@
@RED("var")@
|
System #2:
bin
boot
dev
etc
home
initrd
lib
lost+found
misc
mnt
movies
opt
proc
rar
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.
This directive behave exactly as the
EVAL macro do, the
main difference is that the code within INLINE and ENDINLINE shouldn't be
escaped (except the '@' char that should be expanded into '@AT@').
Source
@VAR=some value@
...
@INLINE@
my $v;
my $f = '';
for ($v = 0; $v < 10; $v++) {
$f .= ' ' . ($v * $v);
}
return "test code [$f @VAR@]";
@ENDINLINE@
...
Output
...
test code [ 0 1 4 9 16 25 36 49 64 81 some value]
...
INLINE perl code should be more readable than the equivalent EVAL version.
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(" \
my $str = ''; \
for(my $i = 0; $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(" \
my $str = ''; \
for(my $i = 0; $i < @LIMIT@; $i++) { \
$str .= \"@RANDOM()@ \"; \
} \
return $str; \
")@
Output
925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604 925896123251604
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(" \
my $str = ''; \
for(my $i = 0; $i < @LIMIT@; $i++) { \
$str .= WPP::call('RANDOM') . ' '; \
} \
return $str; \
")@
Output
282702544575105 552693847483994 825954597827899 0348399899902532 0734755209571354 185688667196175 827332481085275 978426656426585 627908420295714 43169042916287 23026833623997
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 '';").
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'
****