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'
****