ac7e2c541a
Signed-off-by: Thomas Hochstein <thh@inter.net>
811 lines
18 KiB
Perl
811 lines
18 KiB
Perl
#----------------------------------------------------------------------
|
||
package UVtemplate;
|
||
#----------------------------------------------------------------------
|
||
|
||
=head1 NAME
|
||
|
||
UVtemplate - Templateverarbeitung und String-Formatierungen
|
||
|
||
=head1 SYNOPSIS
|
||
|
||
use UVtemplate;
|
||
|
||
$plate = UVtemplate->new([%keys]);
|
||
|
||
$plate->setKey(%keys);
|
||
$item = $plate->addListItem($name, %keys);
|
||
|
||
$string = $plate->processTemplate($file);
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
Mit Hilfe von UVtemplate, wird die komplette Aufbereitung und
|
||
Formatierung der Programmausgaben nicht nur ausgelagert sondern
|
||
auch so flexibiliert, dass sie jederzeit angepasst werden kann,
|
||
ohne das im eigentlichen Programmcode veraendert werden muss.
|
||
|
||
Auf Programmseite wird eine Datenstruktur mit Schluessel-Wert
|
||
Paaren erzeugt. In den Template-Dateien werden dann spaeter die
|
||
jeweiligen Schluessel, durch ihre im Programm festgelegten
|
||
Werte ersetzt. Zusaetzlich ist es moeglich Schluessel zu Listen
|
||
zusammenzufassen.
|
||
|
||
Da es sich bei den Templates um Ascii-Texte handelt, gibt es
|
||
zusaetzlich die Moeglichkeit die Werte der Schluessel zuformatieren
|
||
um eine einheitliche Ausgabe zu ermoeglichen. D.h. es kann z.B. durch
|
||
das Anhaengen von Leerzeichen dafuer gesorgt werden, das ein Schluessel
|
||
einer Liste immer 60 Zeichen lang ist um ansehnliche Tabellen auszugeben.
|
||
|
||
=head1 FUNCTIONS
|
||
|
||
=over 3
|
||
|
||
=cut
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
use strict;
|
||
use vars qw( $VERSION $functions @dirs);
|
||
use UVconfig;
|
||
|
||
$VERSION = 0.1;
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
=item new
|
||
|
||
Eine neues Objekt vom Typ UVtemplate anlegen.
|
||
|
||
my $plate = UVtemplate->new();
|
||
|
||
Als Parameter koennen gleich beliebig viele Schluessel-Wert-Paare
|
||
uebergeben werden.
|
||
|
||
=cut
|
||
|
||
sub new{
|
||
my $class = shift;
|
||
my $self = {};
|
||
|
||
if (ref($class)){
|
||
$self->{FATHER} = $class;
|
||
bless($self, ref($class));
|
||
|
||
}else{
|
||
bless($self, $class);
|
||
}
|
||
|
||
$self->setKey(@_);
|
||
|
||
return $self;
|
||
}
|
||
|
||
=item setKey
|
||
|
||
Schluessel und zugehoerige Werte im Objekt speichern.
|
||
|
||
$plate->setKey( vote-addr => 'to-vote@dom.ain' );
|
||
$plate->setKey( datenschutz => 1);
|
||
|
||
Ist der zu speichernde Schluessel bereits vorhanden, wird er
|
||
durch den neuen Wert ueberschrieben.
|
||
|
||
=cut
|
||
|
||
sub setKey{
|
||
my $self = shift;
|
||
my %param = @_;
|
||
|
||
foreach my $key (keys(%param)){
|
||
$self->{KEYS}->{$key} = $param{$key};
|
||
}
|
||
}
|
||
|
||
=item addListItem
|
||
|
||
Erzeugt ein neues Objekt vom Typ UVtemplate und fuegt es der
|
||
angebenen Liste hinzu.
|
||
|
||
$plate->addListItem(name => 'Musterman', email => 'em@il');
|
||
|
||
Da sich Listen wie normale Schluessel-Wert Paare verhalten,
|
||
wird die Liste als Array ueber UVtemplate-Objekte unter dem
|
||
definiertem Schluessel abgelegt. Ist dieser Schluessel bereits
|
||
gesetzt und enthaehlt keinen Array, so bricht die Funktion ab.
|
||
|
||
=cut
|
||
|
||
sub addListItem{
|
||
my $self = shift;
|
||
my $list = shift;
|
||
|
||
# pruefen ob key angegeben ist und falls key vorhanden
|
||
# eine liste vorliegt
|
||
return unless ($list && (not($self->{KEYS}->{$list}) ||
|
||
UNIVERSAL::isa($self->{KEYS}->{$list}, 'ARRAY')));
|
||
|
||
# neues Element erzeugen
|
||
my $new = $self->new( @_ );
|
||
|
||
# an listen anhaengen
|
||
push(@{$self->{KEYS}->{$list}}, $new);
|
||
|
||
# referenz zurueckgeben
|
||
return $new;
|
||
}
|
||
|
||
=item getKey($key)
|
||
|
||
Den Wert eines Schluessel ermitteln.
|
||
|
||
my $value = $plate->getKey('email');
|
||
|
||
Ist der Wert im Objekt nicht gesetzt, wird - falls es sich um ein
|
||
Element einer Liste handelt - rekursiv beim Vater weiter gesucht.
|
||
|
||
So stehen allen Kindern auch die Schluessel-Wert Paare ihrer Eltern
|
||
zur Verfuegung.
|
||
|
||
Zum Schluss wird noch geprueft, ob der Schluessel in usevote.cfg
|
||
gesetzt wurde. Dadurch sind alle Konfigurationsoptionen direkt
|
||
in Templates nutzbar.
|
||
|
||
=cut
|
||
|
||
sub getKey{
|
||
my $self = shift;
|
||
my $key = $_[0];
|
||
|
||
my $value;
|
||
|
||
do{
|
||
$value = $self->{KEYS}->{$key};
|
||
$self = $self->{FATHER};
|
||
|
||
}while(!defined($value) && $self);
|
||
|
||
if (!defined($value) && defined($config{$key})) {
|
||
$value = $config{$key};
|
||
}
|
||
|
||
return $value;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
sub getRules{
|
||
my $self = shift;
|
||
|
||
do{
|
||
return $self->{RULES} if ($self->{RULES});
|
||
$self = $self->{FATHER};
|
||
}while($self);
|
||
|
||
return;
|
||
}
|
||
|
||
=item getConvKey{
|
||
|
||
Einen Format ermitteln.
|
||
|
||
my $value = $plate->getConvKey('email-adresse');
|
||
|
||
Diese Funktion ueberprueft ob eine Formatierung mit den entsprechenden
|
||
Schluessel definiert ist und ruft dementsprechend die dort definierten
|
||
Funktionen ueber der Datenstruktur auf.
|
||
|
||
Ist kein solches Format definiert, wird der Wert des Schluessel mit
|
||
einem solchen Namen zurueckgegeben. (Es wird intern getKey aufgerufen).
|
||
|
||
=cut
|
||
|
||
sub getConvKey{
|
||
my $self = shift;
|
||
my $key = $_[0] || return;
|
||
|
||
my $rules = $self->getRules();
|
||
my $value = $self->getKey($key);
|
||
|
||
$value = '' unless (defined($value));
|
||
|
||
if ($rules && ($rules->{$key})){
|
||
my @funcs = @{$rules->{$key}};
|
||
|
||
foreach my $func (@funcs){
|
||
my ($name, @params) = @$func;
|
||
|
||
if ($functions->{$name}){
|
||
$value = $functions->{$name}->($self, $value, @params);
|
||
|
||
}else{
|
||
print STDERR "format function '$name' not found!\n";
|
||
}
|
||
}
|
||
}
|
||
|
||
return $value;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
=item processTemplate
|
||
|
||
Daten des Objekts in ein Template einfuegen.
|
||
|
||
my $string = $plate->processTemplate('template/info.txt');
|
||
|
||
Die angebene Datei wird eingelesen, zerlegt und danach
|
||
die enstprechenden Platzhalter durch die (formatierten)
|
||
Werte aus der Datenstruktur ersetzt.
|
||
|
||
=cut
|
||
|
||
sub processTemplate{
|
||
my $self = shift;
|
||
my $file = $_[0] || return;
|
||
|
||
my ($rules, $body) = _split_file($file);
|
||
|
||
# konvertierungsregeln parsen
|
||
$self->{RULES} = _parse_rules($rules);
|
||
|
||
# template zerlegen (zuerst fuehrende leerzeilen entfernen!)
|
||
$body =~ s/^\n+//s;
|
||
my $token = UVtemplate::scan->new(string => $body);
|
||
|
||
# daten einsetzen
|
||
return $token->processData($self);
|
||
}
|
||
|
||
sub _split_file{
|
||
my $file = $_[0] || return;
|
||
|
||
my $fname = _complete_filename($file);
|
||
|
||
unless ($fname){
|
||
print STDERR "couldnt find '$file'\n";
|
||
return;
|
||
}
|
||
|
||
my (@rules, @body);
|
||
|
||
open(PLATE, $fname);
|
||
my @lines = <PLATE>;
|
||
close(PLATE);
|
||
|
||
my $body = 0;
|
||
|
||
foreach my $line (@lines){
|
||
if ($line =~ m/^== TEMPLATE/){
|
||
$body = 1;
|
||
|
||
}else{
|
||
if ($body){
|
||
push(@body, $line);
|
||
|
||
}else{
|
||
push(@rules, $line);
|
||
}
|
||
}
|
||
}
|
||
|
||
# falls kein Separator definiert war, wird der komplette Text
|
||
# als Body interpretiert. Es gibt keine Regeln!
|
||
|
||
unless ($body){
|
||
@body = @rules;
|
||
@rules = ();
|
||
}
|
||
|
||
# und nun wieder zu Strings zusammenpappen
|
||
return (join('', @rules), join('', @body));
|
||
}
|
||
|
||
sub _complete_filename{
|
||
my $file = $_[0] || return;
|
||
|
||
my $dirs = $UVconfig::config{templatedir};
|
||
@dirs = split(/\s*,\s*/, $dirs) if $dirs;
|
||
|
||
my $fname;
|
||
|
||
foreach my $dir (@dirs, '.'){
|
||
$fname = "$dir/$file";
|
||
return $fname if (-r $fname);
|
||
}
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
# Konvertierungs-Regeln
|
||
#----------------------------------------------------------------------
|
||
|
||
sub _parse_rules{
|
||
my $string = $_[0] || return;
|
||
|
||
my @stack;
|
||
my $rules = {};
|
||
|
||
my $this = [];
|
||
|
||
while (length($string) > 0){
|
||
_strip_chars(\$string);
|
||
|
||
my $token = _parse_token(\$string);
|
||
|
||
if ($token){
|
||
push(@stack, $token);
|
||
|
||
_strip_chars(\$string);
|
||
|
||
if ($string =~ s/^:=//){
|
||
# neuen Schluessel vom Stack holen
|
||
my $key = pop(@stack);
|
||
|
||
# restlichen Stack auf alten Schluessel packen
|
||
push(@$this, [ @stack ]);
|
||
@stack = ();
|
||
|
||
# neuen Schluessel anlegen
|
||
$rules->{$key} = $this = [];
|
||
|
||
}elsif($string =~ s/^\|//){
|
||
# stack auf schluessel packen
|
||
push(@$this, [ @stack ]);
|
||
@stack = ();
|
||
}
|
||
|
||
}else{
|
||
# fehlermeldung ausgeben (nacharbeiten!)
|
||
print STDERR "Syntaxerror in Definition\n";
|
||
return;
|
||
}
|
||
}
|
||
|
||
# den Rest vom Stack abarbeiten
|
||
push(@$this, [ @stack ]) if @stack;
|
||
|
||
return $rules;
|
||
}
|
||
|
||
sub _strip_chars{
|
||
my $line = $_[0] || return;
|
||
|
||
# f<>hrenden whitespace entfernen
|
||
$$line =~ s/^\s+//;
|
||
|
||
# kommentare bis zum n<>chsten Zeilenumbruch entfernen
|
||
$$line =~ s/^#.*$//m;
|
||
}
|
||
|
||
|
||
sub _parse_token{
|
||
my $string = shift;
|
||
|
||
if ($$string =~ s/^(["'])//){
|
||
return _parse_string($string, $1);
|
||
|
||
}else{
|
||
return _parse_ident($string);
|
||
}
|
||
}
|
||
|
||
|
||
sub _parse_string{
|
||
my ($string, $limit) = @_;
|
||
|
||
my $value;
|
||
|
||
while ($$string){
|
||
if ($$string =~ s/^$limit//){
|
||
$$string =~ s/^\s*//;
|
||
return $value;
|
||
|
||
}elsif($$string =~ s/^\\(.)//){
|
||
$value .= $1;
|
||
|
||
}else{
|
||
$$string =~ s/^[^$limit\\]*//;
|
||
$value .= $&;
|
||
}
|
||
}
|
||
|
||
# end of line
|
||
return $value;
|
||
}
|
||
|
||
|
||
sub _parse_ident{
|
||
my $string = shift;
|
||
|
||
if ($$string =~ s/^([A-Za-z0-9-]+)\s*//){
|
||
return $1;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
BEGIN{
|
||
$functions = \%UVconfig::functions;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
#----------------------------------------------------------------------
|
||
package UVtemplate::scan;
|
||
#----------------------------------------------------------------------
|
||
#----------------------------------------------------------------------
|
||
|
||
sub new{
|
||
my $class = shift;
|
||
my %param = @_;
|
||
|
||
my $self = {};
|
||
bless($self, $class);
|
||
|
||
$self->parseFile($param{file}) if defined($param{file});
|
||
$self->parseString($param{string}) if defined($param{string});
|
||
|
||
return $self;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
sub processData{
|
||
my $self = shift;
|
||
my $data = $_[0];
|
||
|
||
return _process_data($self->{toks}, $data);
|
||
}
|
||
|
||
sub _process_data{
|
||
my ($toref, $data) = @_;
|
||
|
||
my $string = '';
|
||
my $length = 0;
|
||
my $empty = 0;
|
||
|
||
foreach my $token (@$toref){
|
||
if (ref($token)){
|
||
my $before = length($string);
|
||
$empty = 0;
|
||
|
||
if ($token->[0] eq 'VAR'){
|
||
my $value = $data->getConvKey(_process_data($token->[1], $data));
|
||
|
||
if (defined($value) && length($value)){
|
||
$string .= $value;
|
||
|
||
}else{
|
||
$string .= _process_data($token->[2], $data);
|
||
}
|
||
|
||
}elsif($token->[0] eq 'IF'){
|
||
if ($data->getConvKey(_process_data($token->[1], $data))){
|
||
$string .= _process_data($token->[2], $data);
|
||
|
||
}else{
|
||
$string .= _process_data($token->[3], $data);
|
||
}
|
||
|
||
}elsif($token->[0] eq 'LOOP'){
|
||
my $nodes = $data->getConvKey(_process_data($token->[1], $data));
|
||
my @block;
|
||
|
||
if ($nodes && (UNIVERSAL::isa($nodes, 'ARRAY'))){
|
||
foreach my $node (@$nodes){
|
||
push(@block, _process_data($token->[2], $node));
|
||
}
|
||
|
||
$string .= join(_process_data($token->[3], $data), @block);
|
||
}
|
||
}
|
||
|
||
$length = length($string);
|
||
$empty = 1 if ($before == $length);
|
||
|
||
}else{
|
||
if ($empty && ($string =~ m/(\n|^)$/s)){
|
||
$empty = 0; # Falls die letzte Zeile nur aus einem Token
|
||
$token =~ s/^\n//s; # ohne Inhalt bestand, wird die Zeile entfernt
|
||
}
|
||
|
||
$string .= $token;
|
||
}
|
||
}
|
||
|
||
return $string;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
# Den String in einen Syntaxbaum abbilden
|
||
|
||
sub _parse_token_string{
|
||
my $self = shift;
|
||
my ($string, $intern) = @_;
|
||
|
||
my (@token, $toref);
|
||
my $data = '';
|
||
|
||
while ($string){
|
||
if ($intern && $string =~ m/^(\]|\|)/){
|
||
last;
|
||
|
||
}elsif ($string =~ s/^\[//){
|
||
my $orig = $string;
|
||
|
||
($toref, $string) = $self->_parse_token($string);
|
||
|
||
if (@$toref){
|
||
push (@token, $data) if $data;
|
||
$data = '';
|
||
|
||
push(@token, $toref)
|
||
}
|
||
|
||
if ($string !~ s/^\]//){
|
||
my $pos = $self->{lines} - _count_lines($orig) + 1;
|
||
|
||
print STDERR "Scanner: [$pos] missing right bracket\n";
|
||
return (\@token, $string);
|
||
}
|
||
|
||
}elsif($string =~ s/^\\n//s){
|
||
$data .= "\n";
|
||
|
||
}elsif($string =~ s/^\\(.)//s){
|
||
$data .= $1;
|
||
|
||
}elsif($intern){
|
||
$string =~ s/^([^\]\[\|\\]+)//s;
|
||
$data .= $1;
|
||
|
||
}else{
|
||
$string =~ s/^([^\[\\]+)//s;
|
||
$data .= $1;
|
||
}
|
||
}
|
||
|
||
push (@token, $data) if length($data);
|
||
return (\@token, $string)
|
||
}
|
||
|
||
|
||
sub _parse_token{
|
||
my $self = shift;
|
||
my $string = $_[0];
|
||
|
||
my @token = ();
|
||
|
||
if ($string =~ s/^\$//s){
|
||
# Variablen - Syntax: [$key[|<else>]]
|
||
push (@token, 'VAR');
|
||
|
||
}elsif ($string =~ s/^\?//s){
|
||
# Bedingung - Syntax: [?if|<then>[|<else>]]
|
||
push (@token, 'IF');
|
||
|
||
}elsif ($string =~ s/^\@//s){
|
||
# Schleifen - Syntax: [@key|<block>[|<sep>]]
|
||
push (@token, 'LOOP');
|
||
|
||
}elsif ($string =~ s/^#//s){
|
||
# Kommentare - Syntax: [# ... ]
|
||
$string = _parse_comment($string);
|
||
|
||
return (\@token, $string);
|
||
|
||
}else{
|
||
print STDERR "unknown token in template\n";
|
||
}
|
||
|
||
my $toref;
|
||
|
||
($toref, $string) = $self->_parse_token_string($string, 1);
|
||
push(@token, $toref);
|
||
|
||
while ($string =~ s/^\|//){
|
||
($toref, $string) = $self->_parse_token_string($string, 1);
|
||
push(@token, $toref);
|
||
}
|
||
|
||
return (\@token, $string);
|
||
}
|
||
|
||
|
||
sub _parse_comment{
|
||
my $string = $_[0];
|
||
my $count = 1;
|
||
|
||
while($string && $count) {
|
||
$string =~ s/^[^\[\]\\]+//s; # alles au<61>er Klammern und Backslash wegwerfen
|
||
$string =~ s/^\\.//; # alles gesperrte l<>schen
|
||
|
||
$count++ if $string =~ s/^\[//;
|
||
$count-- if $string =~ s/^\]//;
|
||
}
|
||
|
||
$string = ']'.$string if !$count;
|
||
return $string;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
|
||
sub parseString{
|
||
my $self = shift;
|
||
my $text = $_[0];
|
||
|
||
$self->{lines} = _count_lines($text);
|
||
my ($toref, $rest) = $self->_parse_token_string($text);
|
||
|
||
$self->{toks} = $toref;
|
||
}
|
||
|
||
|
||
sub _count_lines{
|
||
return 0 unless defined($_[0]);
|
||
|
||
my ($string, $count) = ($_[0], 1);
|
||
$count++ while($string =~ m/\n/sg);
|
||
|
||
return $count;
|
||
}
|
||
|
||
#----------------------------------------------------------------------
|
||
#----------------------------------------------------------------------
|
||
#----------------------------------------------------------------------
|
||
|
||
1;
|
||
|
||
=back
|
||
|
||
=head1 SYNTAX
|
||
|
||
Eine Templatedatei besteht aus zwei Teilen. Am Anfang werden die
|
||
Formatierungen bestimmter Schluessel definiert und nach einem
|
||
Trenner folgt der eigentlich Template-Koerper, der dann von Programm
|
||
bearbeitet und ausgegeben wird.
|
||
|
||
format-key := function1 param | function2 param
|
||
|
||
== TEMPLATE ====================================
|
||
|
||
Ich bin nun das eigentliche Template:
|
||
|
||
format-key: [$format-key]
|
||
|
||
Der Trenner beginnt mit den Zeichen '== TEMPLATE' danach koennen
|
||
beliebige Zeichen folgen um die beiden Sektionen optisch voneinander
|
||
abzugrenzen.
|
||
|
||
Wenn es keine Formatierungsanweisungen gibt, kann der Trenner auch
|
||
weggelassen werden. D.h. wenn kein Trenner gefunden wird, wird der
|
||
komplette Text als Template-Koerper betrachtet.
|
||
|
||
=head2 Template-Koerper
|
||
|
||
Im Template-Koerper werden die zu ersetzenden Token durch eckige
|
||
Klammern abgegrenzt. Sollen eckige Klammern im Text ausgegeben werden
|
||
muessen diese durch einen Backslash freigestellt werden.
|
||
|
||
[$termersetzung] [@schleife] nur eine \[ Klammer
|
||
|
||
=over 3
|
||
|
||
=item $ - Termersetzung
|
||
|
||
Ersetzt den Token durch den Wert des angegeben Schluessels.
|
||
|
||
[$formatierung] [$schluessel]
|
||
|
||
Es wird zuerst nach einer Formatierung mit den entsprechenden
|
||
Bezeichner gesucht. Ist dies der Fall werden die entsprechenden
|
||
Funktionen ausgefuehrt.
|
||
|
||
Kann kein Format gefunden, wird direkt in der Datenstruktur
|
||
nach einem Schhluessel mit dem angegeben Bezeichner gesucht
|
||
und sein Wert eingesetzt.
|
||
|
||
Schlussendlich ist es noch moeglich einen default-Wert zu
|
||
definieren, der eingesetzt wird, wenn keiner der obigen Wege
|
||
erfolgreich war.
|
||
|
||
Hallo [$name|Unbekannter]!
|
||
|
||
=item ? - bedingte Verzeigung
|
||
|
||
Ueberprueft ob der Wert des angegebenen Formats/Schluessel
|
||
boolsch WAHR ist. Dementsprechend wird der then oder else
|
||
Block eingefuegt.
|
||
|
||
[?if|then|else] oder auch nur [?if|then]
|
||
|
||
Die then/else Bloecke werden natuerlich auch auf Tokens
|
||
geparst und diese dementsprechend ersetzt.
|
||
|
||
=item @ - Schleifen/Listen
|
||
|
||
Der nachfolgende Textblock wird fuer alle Elemente des durch
|
||
den Schluessel bezeichneten Arrays ausgefuehrt und eingefuegt.
|
||
|
||
[@schluessel|block] oder [@schluessel|block|sep]
|
||
|
||
Als zweiter Parameter kann ein Separtor definiert werden, mit
|
||
dem sich z.B. kommaseparierte Listen erzeugen lassen, da der
|
||
Separator eben nur zwischen den Element eingefuegt wird.
|
||
|
||
Auch fuer Schleifen koennen Formatierungen genutzt werden.
|
||
Allerdings darf kein String zurueckgegeben werden, sondern
|
||
ein Array mit einer Menge von UVtemplate-Objekten.
|
||
|
||
=item # - Kommentare
|
||
|
||
Token die nach der Bearbeitungen entfernt werden.
|
||
|
||
[# mich sieht man nicht]
|
||
|
||
=item Sonstiges
|
||
|
||
Um in Listen einen Zeilenumbruch zu erzwingen, muss
|
||
lediglich ein '\n' eingefuegt werden, falls eine kompakte
|
||
Definition der Liste erfolgen soll.
|
||
|
||
[@names|[name] [email]\n]
|
||
|
||
=back
|
||
|
||
=head2 Formatierungen
|
||
|
||
Eine Formatierung besteht eigentlich nur aus dem entsprechenden
|
||
Namen und einer beliebigen Anzahl von Funktionsaufrufen:
|
||
|
||
format := funktion param1 "param 2" | funktion param
|
||
|
||
Aehnlich der Unix-Shell-Funktionalitaet, wird dabei die Ausgabe
|
||
einer Funktion an die folgende weitergeleitet. So ist es moeglich
|
||
verschiedenste simple Formatierungen zu kombinieren um nicht fuer
|
||
jeden Spezialfall eine neue Funktion schreiben zu muessen.
|
||
|
||
Die jeweilige Formatierungsfunktion erhaelt als Input die Datenstruktur,
|
||
den Output der vorherigen Funktion und die definierten Parameter in der
|
||
entsprechenden Reihenfolge.
|
||
|
||
Zahlen und einfache Bezeichner koennen direkt definiert werden. Sollen
|
||
Sonderzeichen oder Leerzeichen uebergeben werden muessen diese gequotet
|
||
werden. Dazu kann ' also auch " verwendet werden.
|
||
|
||
Die Funktionen geben im Allgemeinen einen String zurueck. Im Rahmen
|
||
von Listen k<>nnen auch Arrays uebergeben werden.
|
||
|
||
Die erste Funktion duerfte ueblicherweise 'value' sein. Sie gibt den
|
||
des angegeben Schluessel zurueck, der dann von den folgenden Funktionen
|
||
definiert wird.
|
||
|
||
name-60 := value name | fill-right 60
|
||
|
||
Das Format "name-60" definiert also den Wert des Schluessel "name" der
|
||
um Leerzeichen aufgefuellt wird, bis eine Laenge von 60 Zeichen
|
||
erreicht wird.
|
||
|
||
name-email := value name | justify-behind mail 72
|
||
|
||
"name-email" resultiert in einem String, der zwischen den Werten
|
||
von "name" und "email" genau so viele Leerzeichen enthaelt, damit
|
||
der gesamte String 72 Zeichen lang ist.
|
||
|
||
Wird dieses Format in einer Liste angewandt, erhaelt man eine Tabelle
|
||
in der die linke Spalte linksbuendig und die rechte Spalte entsprechend
|
||
rechtsbuendig ist.
|
||
|
||
Soweit ein kleiner Ueberblick ueber die Formatierungen.
|
||
Ausfuehrliche Funktionsbeschreibungen und weitere Beispiele finden
|
||
sich in der Dokumentation des Moduls UVformat.
|
||
|
||
=head1 SEE ALSO
|
||
|
||
L<UVformats>
|
||
|
||
=head1 AUTHOR
|
||
|
||
Cornell Binder <cobi@dex.de>
|