+package Template;\r
+\r
+#\r
+# Template (Version 2.5)\r
+#\r
+# Klasse zum Parsen von Templates\r
+#\r
+# Autor: Patrick Canterino <patrick@patshaping.de>\r
+# Letzte Aenderung: 25.11.2011\r
+#\r
+# Copyright (C) 2002-2011 Patrick Canterino\r
+#\r
+# Diese Datei kann unter den Bedingungen der "Artistic License 2.0"\r
+# weitergegeben und / oder veraendert werden.\r
+# Siehe:\r
+# http://www.opensource.org/licenses/artistic-license-2.0\r
+#\r
+\r
+use strict;\r
+\r
+use Carp qw(croak);\r
+use File::Spec;\r
+\r
+# new()\r
+#\r
+# Konstruktor\r
+#\r
+# Parameter: -keine-\r
+#\r
+# Rueckgabe: Template-Objekt\r
+\r
+sub new {\r
+ my $class = shift;\r
+ my $self = {file => '', template => '', original => '', old_parsing => 0, vars => {}, defined_vars => [], loop_vars => {}};\r
+ return bless($self,$class);\r
+}\r
+\r
+# get_template()\r
+#\r
+# Kompletten Vorlagentext zurueckgeben\r
+#\r
+# Parameter: -keine-\r
+#\r
+# Rueckgabe: Kompletter Vorlagentext (String)\r
+\r
+sub get_template {\r
+ return shift->{'template'};\r
+}\r
+\r
+# set_template()\r
+#\r
+# Kompletten Vorlagentext aendern\r
+#\r
+# Parameter: Vorlagentext\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub set_template($) {\r
+ my ($self,$template) = @_;\r
+ $self->{'template'} = $template;\r
+}\r
+\r
+# add_text()\r
+#\r
+# Vorlagentext ans Template-Objekt anhaengen\r
+#\r
+# Parameter: Vorlagentext\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub add_text($) {\r
+ my ($self,$text) = @_;\r
+ $self->set_template($self->get_template.$text);\r
+}\r
+\r
+# read_file()\r
+#\r
+# Einlesen einer Vorlagendatei und {INCLUDE}-Anweisungen ggf. verarbeiten\r
+# (Text wird an bereits vorhandenen Text angehaengt)\r
+#\r
+# Parameter: 1. Datei zum Einlesen\r
+# 2. Status-Code (Boolean):\r
+# true => {INCLUDE}-Anweisungen nicht verarbeiten\r
+# false => {INCLUDE}-Anweisungen verarbeiten (Standard)\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub read_file($;$) {\r
+ my ($self,$file,$not_include) = @_;\r
+ local *FILE;\r
+\r
+ $self->{'file'} = $file;\r
+\r
+ open(FILE,'<'.$file) or croak "Open $file: $!";\r
+ read(FILE, my $content, -s $file);\r
+ close(FILE) or croak "Closing $file: $!";\r
+\r
+ $self->add_text($content);\r
+ $self->save_state;\r
+\r
+ $self->parse_includes unless($not_include);\r
+}\r
+\r
+# set_var()\r
+#\r
+# Wert einer Variable setzen\r
+#\r
+# Parameter: 1. Name der Variable\r
+# 2. Wert, den die Variable erhalten soll\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub set_var($$) {\r
+ my ($self,$var,$content) = @_;\r
+ $self->{'vars'}->{$var} = $content;\r
+}\r
+\r
+# get_var()\r
+#\r
+# Wert einer Variable zurueckgeben\r
+#\r
+# Parameter: (optional) Variablenname\r
+#\r
+# Rueckgabe: Wert der Variable;\r
+# wenn die Variable nicht existiert, false;\r
+# wenn kein Variablenname angegeben wurde, wird ein\r
+# Array mit den Variablennamen zurueckgegeben\r
+\r
+sub get_var(;$) {\r
+ my ($self,$var) = @_;\r
+\r
+ if(defined $var) {\r
+ if($self->{'vars'}->{$var}) {\r
+ return $self->{'vars'}->{$var};\r
+ }\r
+ else {\r
+ return undef;\r
+ }\r
+ }\r
+ else {\r
+ return keys %{$self->{'vars'}};\r
+ }\r
+}\r
+\r
+# set_vars()\r
+#\r
+# Komplettes Variablen-Array mit einem anderen Array ueberschreiben\r
+#\r
+# Parameter: Array\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub set_vars($) {\r
+ my ($self,$vars) = @_;\r
+ $self->{'vars'} = $vars;\r
+}\r
+\r
+# add_vars()\r
+#\r
+# Zum bestehenden Variablen-Array weitere Variablen in Form eines Arrays\r
+# hinzufuegen\r
+#\r
+# Parameter: Array\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub add_vars($) {\r
+ my ($self,$vars) = @_;\r
+ $self->{'vars'} = {(%{$self->{'vars'}}, %$vars)};\r
+\r
+ #while(my ($name,$content) = each(%$vars)) {\r
+ # $self->{'vars'}->{$name} = $content;\r
+ #}\r
+}\r
+\r
+# set_loop_data()\r
+#\r
+# Daten fuer eine Schleife setzen\r
+#\r
+# Parameter: 1. Name der Schleife\r
+# 2. Array-Referenz mit den Hash-Referenzen mit\r
+# den Variablen fuer die Schleifendurchgaenge\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub set_loop_data($$) {\r
+ my ($self,$loop,$data) = @_;\r
+ $self->{'loop_vars'}->{$loop} = $data;\r
+}\r
+\r
+# add_loop_data()\r
+#\r
+# Daten fuer einen Schleifendurchgang hinzufuegen\r
+#\r
+# Parameter: 1. Name der Schleife\r
+# 2. Hash-Referenz mit den Variablen fuer den\r
+# Schleifendurchgang\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub add_loop_data($$) {\r
+ my ($self,$loop,$data) = @_;\r
+\r
+ if($self->{'loop_vars'}->{$loop} && ref($self->{'loop_vars'}->{$loop}) eq 'ARRAY') {\r
+ push(@{$self->{'loop_vars'}->{$loop}},$data);\r
+ }\r
+ else {\r
+ $self->{'loop_vars'}->{$loop} = [$data];\r
+ }\r
+}\r
+\r
+# parse()\r
+#\r
+# In der Template definierte Variablen auslesen, Variablen\r
+# ersetzen, {IF}- und {TRIM}-Bloecke parsen\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse {\r
+ my $self = shift;\r
+ return $self->parse_old if($self->{'old_parsing'});\r
+\r
+ # Zuerst die Schleifen parsen\r
+\r
+ if($self->{'loop_vars'} && (my @loops = keys(%{$self->{'loop_vars'}}))) {\r
+ foreach my $loop(@loops) {\r
+ $self->parse_loop($loop);\r
+ }\r
+ }\r
+\r
+ # In Template-Datei definierte Variablen auslesen\r
+\r
+ $self->get_defined_vars;\r
+\r
+ # Variablen ersetzen\r
+\r
+ my @vars = $self->get_var;\r
+\r
+ if(defined(@vars) && scalar(@vars) > 0) {\r
+ $self->parse_if_blocks;\r
+ $self->replace_vars;\r
+ }\r
+\r
+ # {TRIM}-Bloecke entfernen\r
+ \r
+ $self->parse_trim_blocks;\r
+}\r
+\r
+# parse_old()\r
+#\r
+# In der Template definierte Variablen auslesen, Variablen\r
+# ersetzen, {IF}- und {TRIM}-Bloecke parsen\r
+# (alte Methode)\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_old {\r
+ my $self = shift;\r
+\r
+ # Zuerst die Schleifen parsen\r
+\r
+ if($self->{'loop_vars'} && (my @loops = keys(%{$self->{'loop_vars'}}))) {\r
+ foreach my $loop(@loops) {\r
+ $self->parse_loop($loop);\r
+ }\r
+ }\r
+\r
+ # Normale Variablen durchgehen\r
+\r
+ foreach my $var($self->get_var) {\r
+ my $val = $self->get_var($var);\r
+\r
+ $self->parse_if_block($var,$val);\r
+\r
+ if(ref($val) eq 'ARRAY') {\r
+ $self->fillin_array($var,$val);\r
+ }\r
+ else {\r
+ $self->fillin($var,$val);\r
+ }\r
+ }\r
+\r
+ # Jetzt dasselbe mit denen, die direkt in der Template-Datei definiert\r
+ # sind, machen. Ich weiss, dass das eine ziemlich unsaubere Loesung ist,\r
+ # aber es funktioniert\r
+\r
+ $self->get_defined_vars;\r
+\r
+ foreach my $var(@{$self->{'defined_vars'}}) {\r
+ my $val = $self->get_var($var);\r
+\r
+ $self->parse_if_block($var,$val);\r
+ $self->fillin($var,$val);\r
+ }\r
+\r
+ # {TRIM}-Bloecke entfernen\r
+\r
+ $self->parse_trim_blocks;\r
+}\r
+\r
+# fillin()\r
+#\r
+# Variablen durch Text ersetzen\r
+#\r
+# Parameter: 1. Variable zum Ersetzen\r
+# 2. Text, durch den die Variable ersetzt werden soll\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub fillin($$) {\r
+ my ($self,$var,$text) = @_;\r
+\r
+ $text = '' unless defined $text; # Um Fehler zu vermeiden\r
+\r
+ my $template = $self->get_template;\r
+ $template = str_replace('{'.$var.'}',$text,$template);\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# fillin_array()\r
+#\r
+# Variable durch Array ersetzen\r
+#\r
+# Parameter: 1. Variable zum Ersetzen\r
+# 2. Array-Referenz, durch die die Variable ersetzt werden soll\r
+# 3. Zeichenkette, mit der das Array verbunden werden soll\r
+# (Standard: '')\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub fillin_array($$;$) {\r
+ my ($self,$var,$array,$glue) = @_;\r
+ $glue = '' unless defined $glue;\r
+\r
+ $self->fillin($var,join($glue,@$array));\r
+}\r
+\r
+# replace_vars()\r
+#\r
+# Variablen eine nach der anderen ersetzen. Sollte in einer Variable eine\r
+# andere Variable auftauchen, so wird diese nicht ersetzt.\r
+#\r
+# Parameter: Array mit zu parsenden Variablen (optional)\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub replace_vars(;@) {\r
+ my ($self,@valid) = @_;\r
+ my $template = $self->get_template;\r
+\r
+ my @valid_vars = (@valid) ? @valid : $self->get_var;\r
+\r
+ for(my $x=0;$x<length($template);$x++) {\r
+ if(substr($template,$x,1) eq '{') {\r
+ foreach my $var(@valid_vars) {\r
+ # Pruefen, ob hier eine gueltige Variable beginnt\r
+\r
+ if(substr($template,$x+1,length($var)+1) eq $var.'}') {\r
+ my $content;\r
+ my $val = $self->get_var($var);\r
+\r
+ if(ref($val) eq 'ARRAY') {\r
+ $content = join('',@$val);\r
+ }\r
+ else {\r
+ $content = $val;\r
+ }\r
+\r
+ # Daten vor und nach der Variable\r
+\r
+ my $pre = substr($template,0,$x);\r
+ my $post = substr($template,length($pre)+2+length($var));\r
+\r
+ # Alles neu zusammensetzen\r
+\r
+ $template = $pre.$content.$post;\r
+\r
+ # Zaehler aendern\r
+\r
+ $x = length($pre.$content)-1;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# to_file()\r
+#\r
+# Template in Datei schreiben\r
+#\r
+# Parameter: Datei-Handle\r
+#\r
+# Rueckgabe: Status-Code (Boolean)\r
+\r
+sub to_file($) {\r
+ my ($self,$handle) = @_;\r
+ return print $handle $self->get_template;\r
+}\r
+\r
+# reset()\r
+#\r
+# Den gesicherten Stand des Template-Textes wiederherstellen\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub reset {\r
+ my $self = shift;\r
+ $self->{'template'} = $self->{'original'};\r
+}\r
+\r
+# save_state()\r
+#\r
+# Aktuellen Stand des Template-Textes sichern\r
+# (alte Sicherung wird ueberschrieben)\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub save_state {\r
+ my $self = shift;\r
+ $self->{'original'} = $self->{'template'};\r
+}\r
+\r
+# parse_loop()\r
+#\r
+# Eine Schleife parsen\r
+#\r
+# Parameter: Name der Schleife\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_loop($) {\r
+ my ($self,$name) = @_;\r
+\r
+ my $template = $self->get_template;\r
+ return if(index($template,'{LOOP '.$name.'}') == -1);\r
+\r
+ my $offset = 0;\r
+ my $name_len = length($name);\r
+\r
+ while((my $begin = index($template,'{LOOP '.$name.'}',$offset)) != -1) {\r
+ if((my $end = index($template,'{ENDLOOP}',$begin+6+$name_len)) != -1) {\r
+ my $block = substr($template,$begin,$end+9-$begin);\r
+ my $content = substr($block,$name_len+7,-9);\r
+\r
+ my $parsed_block = '';\r
+\r
+ for(my $x=0;$x<scalar @{$self->{'loop_vars'}->{$name}};$x++) {\r
+ my $loop_data = $self->{'loop_vars'}->{$name}->[$x];\r
+ my @loop_vars = keys(%$loop_data);\r
+\r
+ my $ctpl = new Template;\r
+ $ctpl->set_template($content);\r
+\r
+ foreach my $loop_var(@loop_vars) {\r
+ $ctpl->set_var($name.'.'.$loop_var,$loop_data->{$loop_var});\r
+ }\r
+\r
+ if($self->{'old_parsing'}) {\r
+ $ctpl->parse_old;\r
+ }\r
+ else {\r
+ $ctpl->parse;\r
+ }\r
+\r
+ $parsed_block .= $ctpl->get_template;\r
+\r
+ undef($ctpl);\r
+ }\r
+\r
+ $template = str_replace($block,$parsed_block,$template);\r
+ $offset = $begin+length($parsed_block);\r
+ }\r
+ else {\r
+ last;\r
+ }\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# get_defined_vars()\r
+#\r
+# In der Template-Datei definierte Variablen auslesen\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub get_defined_vars {\r
+ my $self = shift;\r
+\r
+ my $template = $self->get_template;\r
+ return if(index($template,'{DEFINE ') == -1);\r
+\r
+ my $offset = 0;\r
+\r
+ while(index($template,'{DEFINE ',$offset) != -1) {\r
+ my $begin = index($template,'{DEFINE ',$offset)+8;\r
+ $offset = $begin;\r
+\r
+ my $name = '';\r
+ my $content = '';\r
+\r
+ my $var_open = 0;\r
+ my $name_found = 0;\r
+ my $define_block = 0;\r
+\r
+ for(my $x=$begin;$x<length($template);$x++) {\r
+ if(substr($template,$x,1) eq "\012" || substr($template,$x,1) eq "\015") {\r
+ # Wenn in einem {DEFINE}-Block ein Zeilenumbruch gefunden wird,\r
+ # brechen wir mit dem Parsen des Blockes ab\r
+\r
+ last;\r
+ }\r
+\r
+ if($var_open == 1) {\r
+ if(substr($template,$x,1) eq '"') {\r
+ # Der Inhalt der Variable ist hier zu Ende\r
+\r
+ $var_open = 0;\r
+\r
+ if(substr($template,$x+1,1) eq '}') {\r
+ # Hier ist der Block zu Ende\r
+\r
+ if(not defined $self->get_var($name)) {\r
+ # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+ $self->set_var($name,$content);\r
+ push(@{$self->{'defined_vars'}},$name);\r
+ }\r
+\r
+ # {DEFINE}-Block entfernen\r
+\r
+ my $pre = substr($template,0,$begin-8);\r
+ my $post = substr($template,$x+2);\r
+\r
+ $template = $pre.$post;\r
+\r
+ # Fertig!\r
+\r
+ $offset = length($pre);\r
+ last;\r
+ }\r
+ }\r
+ elsif(substr($template,$x,1) eq '\\') {\r
+ # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen\r
+\r
+ if(substr($template,$x+1,1) eq 'n') {\r
+ # "\n" in Zeilenumbrueche umwandeln\r
+\r
+ $content .= "\n";\r
+ }\r
+ else {\r
+ $content .= substr($template,$x+1,1);\r
+ }\r
+\r
+ $x++;\r
+ }\r
+ else {\r
+ $content .= substr($template,$x,1);\r
+ }\r
+ }\r
+ else {\r
+ if($name_found == 1) {\r
+ if($var_open == 0) {\r
+ if(substr($template,$x,1) eq '"') {\r
+ $var_open = 1;\r
+ }\r
+ else {\r
+ last;\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ # Variablennamen auslesen\r
+\r
+ if(substr($template,$x,1) eq '}' && $name ne '') {\r
+ # Wir haben einen {DEFINE}-Block\r
+\r
+ $name_found = 1;\r
+ $define_block = 1;\r
+\r
+ # Alles ab hier sollte mit dem Teil verbunden werden, der das\r
+ # {DEFINE} in einer Zeile verarbeitet\r
+\r
+ # Der Parser fuer {DEFINE}-Bloecke ist nicht rekursiv, was auch\r
+ # nicht noetig sein sollte\r
+\r
+ if((my $end = index($template,'{ENDDEFINE}',$x)) != -1) {\r
+ $x++;\r
+\r
+ $content = substr($template,$x,$end-$x);\r
+\r
+ if(not defined $self->get_var($name)) {\r
+ # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+ $self->set_var($name,$content);\r
+ push(@{$self->{'defined_vars'}},$name);\r
+ }\r
+\r
+ my $pre = substr($template,0,$begin-8);\r
+ my $post = substr($template,$end+11);\r
+\r
+ $template = $pre.$post;\r
+\r
+ # Fertig!\r
+\r
+ $offset = length($pre);\r
+ last;\r
+ }\r
+ else {\r
+ last;\r
+ }\r
+ }\r
+ elsif(substr($template,$x,1) ne ' ') {\r
+ $name .= substr($template,$x,1);\r
+ }\r
+ elsif(substr($template,$x,1) ne '') {\r
+ $name_found = 1;\r
+ }\r
+ else {\r
+ last;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# parse_if_block()\r
+#\r
+# IF-Bloecke verarbeiten\r
+#\r
+# Parameter: 1. Name des IF-Blocks (das, was nach dem IF steht)\r
+# 2. Status-Code (true => Inhalt anzeigen\r
+# false => Inhalt nicht anzeigen\r
+# 3. true => Verneinten Block nicht parsen\r
+# false => Verneinten Block parsen (Standard)\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_if_block($$;$) {\r
+ my ($self,$name,$state,$no_negate) = @_;\r
+ my $template = $self->get_template;\r
+\r
+ my $count = 0;\r
+\r
+ while(index($template,'{IF '.$name.'}') >= 0) {\r
+ # Das alles hier ist nicht wirklich elegant geloest...\r
+ # ... aber solange es funktioniert... ;-)\r
+\r
+ $count++;\r
+\r
+ my $start = index($template,'{IF '.$name.'}');\r
+ my $tpl_tmp = substr($template,$start);\r
+ my @splitted = explode('{ENDIF}',$tpl_tmp);\r
+\r
+ my $block = ''; # Kompletter bedingter Block\r
+ my $ifs = 0; # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt)\r
+\r
+ # {IF}\r
+\r
+ for(my $x=0;$x<@splitted;$x++) {\r
+ croak 'Nesting error found while parsing IF block "'.$name.'" nr. '.$count.' in template file "'.$self->{'file'}.'"' if($x == $#splitted);\r
+\r
+ $ifs += substr_count($splitted[$x],'{IF '); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen\r
+ $ifs--; # Zaehler um 1 erniedrigen\r
+ $block .= $splitted[$x].'{ENDIF}'; # Daten zum Block hinzufuegen\r
+\r
+ if($ifs == 0) {\r
+ # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-))\r
+\r
+ last;\r
+ }\r
+ }\r
+\r
+ my $if_block = substr($block,length($name)+5,-7); # Alles zwischen {IF} und {ENDIF}\r
+\r
+ # {ELSE}\r
+\r
+ my $else_block = ''; # Alles ab {ELSE}\r
+ $ifs = 0; # IF-Zaehler\r
+\r
+ @splitted = explode('{ELSE}',$if_block);\r
+\r
+ for(my $x=0;$x<@splitted;$x++) {\r
+ $ifs += substr_count($splitted[$x],'{IF '); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen\r
+ $ifs -= substr_count($splitted[$x],'{ENDIF}'); # Vom Zaehler jedes Vorkommen von ENDIF abziehen\r
+\r
+ if($ifs == 0) {\r
+ # Zaehler 0, also haben wir das Ende des IF-Abschnitts gefunden\r
+\r
+ # Aus dem Rest den ELSE-Block zusammenbauen\r
+\r
+ for(my $y=$x+1;$y<@splitted;$y++) {\r
+ $else_block .= '{ELSE}'.$splitted[$y];\r
+ }\r
+\r
+ if($else_block) {\r
+ $if_block = substr($if_block,0,length($if_block)-length($else_block));\r
+ $else_block = (length($else_block) > 6) ? substr($else_block,6) : ''; # Ansonsten gibt es Fehler\r
+ }\r
+\r
+ last;\r
+ }\r
+ }\r
+\r
+ my $replacement = ($state) ? $if_block : $else_block;\r
+\r
+ $template = str_replace($block,$replacement,$template);\r
+ }\r
+\r
+ $self->set_template($template);\r
+\r
+ # Evtl. verneinte Form parsen\r
+\r
+ unless($no_negate) {\r
+ $self->parse_if_block('!'.$name,not($state),1);\r
+ }\r
+}\r
+\r
+# parse_if_blocks()\r
+#\r
+# IF-Bloecke zu allen definierten Variablen verarbeiten\r
+#\r
+# Parameter: Array mit zu verarbeitenden IF-Bloecken (optional)\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_if_blocks(;@) {\r
+ my ($self,@valid) = @_;\r
+\r
+ my @valid_vars = (@valid) ? @valid : $self->get_var;\r
+\r
+ foreach my $valid_var(@valid_vars) {\r
+ $self->parse_if_block($valid_var,$self->get_var($valid_var));\r
+ }\r
+}\r
+\r
+# parse_trim_blocks()\r
+#\r
+# {TRIM}-Bloecke parsen\r
+#\r
+# Dieser Parser ist nicht rekursiv, was auch nicht\r
+# noetig sein sollte.\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_trim_blocks {\r
+ my $self = shift;\r
+\r
+ my $template = $self->get_template;\r
+ return if(index($template,'{TRIM}') == -1);\r
+\r
+ my $offset = 0;\r
+\r
+ while((my $begin = index($template,'{TRIM}')) >= 0) {\r
+ if((my $end = index($template,'{ENDTRIM}',$begin+6)) >= 0) {\r
+ my $block = substr($template,$begin,$end+9-$begin);\r
+ my $content = substr($block,6,-9);\r
+\r
+ my $trimmed = $content;\r
+ $trimmed =~ s/^\s+//s;\r
+ $trimmed =~ s/\s+$//s;\r
+\r
+ $template = str_replace($block,$trimmed,$template);\r
+\r
+ $offset = $begin+length($trimmed);\r
+ }\r
+ else {\r
+ last;\r
+ }\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# parse_condtag()\r
+#\r
+# Bedingungstags in einem Vorlagentext verarbeiten\r
+#\r
+# Parameter: 1. Tagname\r
+# 2. Status-Code (true => Tag-Inhalt anzeigen\r
+# false => Tag-Inhalt nicht anzeigen\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_condtag($$) {\r
+ my ($self,$condtag,$state) = @_;\r
+\r
+ my $template = $self->get_template;\r
+\r
+ while(index($template,'<'.$condtag.'>') >= 0) {\r
+ my $start = index($template,'<'.$condtag.'>'); # Beginn des Blocks\r
+ my $end = index($template,'</'.$condtag.'>')+length($condtag)+3; # Ende des Blocks\r
+\r
+ my $extract = substr($template,$start,$end-$start); # Kompletten Bedingungsblock extrahieren...\r
+\r
+ my $replacement = ($state) ? substr($extract,length($condtag)+2,0-length($condtag)-3) : '';\r
+\r
+ $template = str_replace($extract,$replacement,$template); # Block durch neue Daten ersetzen\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# parse_includes()\r
+#\r
+# {INCLUDE}-Anweisungen verarbeiten\r
+#\r
+# Parameter: -nichts-\r
+#\r
+# Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+sub parse_includes {\r
+ my $self = shift;\r
+\r
+ my $template = $self->get_template;\r
+ return if(index($template,'{INCLUDE ') == -1);\r
+\r
+ my $offset = 0;\r
+\r
+ my $y = 0;\r
+\r
+ while((my $begin = index($template,'{INCLUDE ',$offset)) != -1) {\r
+ $y++;\r
+\r
+ my $start = $begin+9;\r
+ $offset = $start;\r
+ my $long = 0;\r
+\r
+ if(substr($template,$start,1) eq '"') {\r
+ $long = 1;\r
+ $start++;\r
+ }\r
+\r
+ my $file = '';\r
+ my $skip = 0;\r
+\r
+ for(my $x=$start;$x<length($template);$x++) {\r
+ my $c = substr($template,$x,1);\r
+\r
+ if($c eq "\012" && $c eq "\015") {\r
+ $skip = 1;\r
+ last;\r
+ }\r
+ elsif($long == 0 && $c eq ' ') {\r
+ $skip = 1;\r
+ last;\r
+ }\r
+ elsif($long == 1 && $c eq '"') {\r
+ $skip = 1 if(substr($template,$x+1,1) ne '}');\r
+ last;\r
+ }\r
+ elsif($long == 0 && $c eq '}') {\r
+ last;\r
+ }\r
+ else {\r
+ $file .= $c;\r
+ }\r
+ }\r
+\r
+ next if($skip == 1);\r
+\r
+ if($file ne '') {\r
+ my $filepath = $file;\r
+\r
+ unless(File::Spec->file_name_is_absolute($file)) {\r
+ my $dir = (File::Spec->splitpath($self->{'file'}))[1];\r
+ $dir = '.' unless($dir);\r
+ $filepath = File::Spec->catfile($dir,$file);\r
+ }\r
+\r
+ if(-f $filepath) {\r
+ my $inc = new Template;\r
+ $inc->read_file($filepath);\r
+\r
+ my $end = ($long == 1)\r
+ ? $start + length($file) + 2\r
+ : $start + length($file) + 1;\r
+\r
+ my $pre = substr($template,0,$begin);\r
+ my $post = substr($template,$end);\r
+\r
+ $template = $pre.$inc->get_template.$post;\r
+ $offset = length($pre)+length($inc->get_template);\r
+\r
+ undef($inc);\r
+ }\r
+ }\r
+ }\r
+\r
+ $self->set_template($template);\r
+}\r
+\r
+# ==================\r
+# Private Funktion\r
+# ==================\r
+\r
+# explode()\r
+#\r
+# Eine Zeichenkette ohne regulaere Ausdruecke auftrennen\r
+# (split() hat einen Bug, deswegen verwende ich es nicht)\r
+#\r
+# Parameter: 1. Trennzeichenkette\r
+# 2. Zeichenkette, die aufgetrennt werden soll\r
+# 3. Maximale Zahl von Teilen\r
+#\r
+# Rueckgabe: Aufgetrennte Zeichenkette (Array)\r
+\r
+sub explode($$;$) {\r
+ my ($separator,$string,$limit) = @_;\r
+ my @splitted;\r
+\r
+ my $x = 1;\r
+ my $offset = 0;\r
+ my $sep_len = length($separator);\r
+\r
+ while((my $pos = index($string,$separator,$offset)) >= 0 && (!$limit || $x < $limit)) {\r
+ my $part = substr($string,$offset,$pos-$offset);\r
+ push(@splitted,$part);\r
+\r
+ $offset = $pos+$sep_len;\r
+\r
+ $x++;\r
+ }\r
+\r
+ push(@splitted,substr($string,$offset,length($string)-$offset));\r
+\r
+ return @splitted;\r
+}\r
+\r
+# str_replace()\r
+#\r
+# Zeichenkette durch andere ersetzen\r
+#\r
+# Parameter: 1. Zu ersetzender Text\r
+# 2. Ersetzender Text\r
+# 3. Zeichenkette, in der ersetzt werden soll\r
+#\r
+# Rueckgabe: Bearbeitete Zeichenkette (String)\r
+\r
+sub str_replace($$$) {\r
+ my ($search,$replace,$subject) = @_;\r
+ $search = quotemeta($search);\r
+\r
+ $subject =~ s/$search/$replace/gs;\r
+\r
+ return $subject;\r
+}\r
+\r
+# substr_count()\r
+#\r
+# Zaehlt, wie oft ein String in einem String vorkommt\r
+# (Emulation der PHP-Funktion substr_count())\r
+#\r
+# Parameter: 1. Zu durchsuchender String\r
+# 2. Zu suchender String\r
+#\r
+# Rueckgabe: Anzahl der Vorkommnisse (Integer)\r
+\r
+sub substr_count($$) {\r
+ my ($haystack,$needle) = @_;\r
+ my $qmneedle = quotemeta($needle);\r
+\r
+ my $count = 0;\r
+\r
+ $count++ while($haystack =~ /$qmneedle/g);\r
+\r
+ return $count;\r
+}\r
+\r
+# it's true, baby ;-)\r
+\r
+1;\r
+\r
+#\r
+### Ende ###
\ No newline at end of file