]> git.p6c8.net - template-class.git/commitdiff
Template-Klasse 2.5 hinzugefuegt
authorPatrick Canterino <patrick@patshaping.de>
Fri, 2 Dec 2011 20:07:26 +0000 (20:07 +0000)
committerPatrick Canterino <patrick@patshaping.de>
Fri, 2 Dec 2011 20:07:26 +0000 (20:07 +0000)
Template.pm [new file with mode: 0644]
class.Template.php [new file with mode: 0644]
doc/aufbau.htm [new file with mode: 0644]
doc/changes.htm [new file with mode: 0644]
doc/index.htm [new file with mode: 0644]
doc/parsen.htm [new file with mode: 0644]
doc/style.css [new file with mode: 0644]
doc/vonhand.htm [new file with mode: 0644]
license.txt [new file with mode: 0644]
readme.txt [new file with mode: 0644]
template.py [new file with mode: 0644]

diff --git a/Template.pm b/Template.pm
new file mode 100644 (file)
index 0000000..eb13acb
--- /dev/null
@@ -0,0 +1,993 @@
+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
diff --git a/class.Template.php b/class.Template.php
new file mode 100644 (file)
index 0000000..5b43d0b
--- /dev/null
@@ -0,0 +1,857 @@
+<?php\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
+class Template {\r
+    var $file;\r
+    var $template;\r
+    var $original;\r
+    var $old_parsing = 0;\r
+    var $vars = array();\r
+    var $defined_vars = array();\r
+    var $loop_vars = array();\r
+\r
+    # get_template()\r
+    #\r
+    # Kompletten Vorlagentext zurueckgeben\r
+    #\r
+    # Parameter: -keine-\r
+    #\r
+    # Rueckgabe: Kompletter Vorlagentext (String)\r
+\r
+    function get_template() {\r
+        return $this->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
+    function set_template($text) {\r
+        $this->template = $text;\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
+    function add_text($text) {\r
+        $this->set_template($this->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
+    function read_file($file,$not_include=0) {\r
+        $this->file = $file;\r
+\r
+        if(filesize($file) > 0) {\r
+            $fp = fopen($file,'r');\r
+            if(!$fp) die;\r
+            $content = fread($fp,filesize($file));\r
+            fclose($fp);\r
+        }\r
+        else $content = '';\r
+\r
+        $this->add_text($content);\r
+        $this->save_state();\r
+\r
+        if(!$not_include) $this->parse_includes();\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
+    function set_var($var,$content) {\r
+        $this->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
+    function get_var($var=false) {\r
+        if($var !== false) {\r
+            if(isset($this->vars[$var])) {\r
+                return $this->vars[$var];\r
+            }\r
+            else {\r
+                return false;\r
+            }\r
+        }\r
+        else {\r
+            return array_keys($this->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
+    function set_vars($vars) {\r
+        $this->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
+    function add_vars($vars) {\r
+        $this->vars = array_merge($this->vars,$vars);\r
+    }\r
+\r
+    # set_loop_data()\r
+    #\r
+    # Daten fuer eine Schleife setzen\r
+    #\r
+    # Parameter: 1. Name der Schleife\r
+    #            2. Array mit den Arrays mit den Variablen fuer\r
+    #               die Schleifendurchgaenge\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    function set_loop_data($loop,$data) {\r
+        $this->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. Array mit den Variablen fuer den\r
+    #               Schleifendurchgang\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    function add_loop_data($loop,$data) {\r
+        if(isset($this->loop_vars[$loop]) && is_array($this->loop_vars[$loop])) {\r
+            array_push($this->loop_vars[$loop],$data);\r
+        }\r
+        else {\r
+            $this->loop_vars[$loop] = array($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
+    function parse() {\r
+        if($this->old_parsing) return $this->parse_old();\r
+\r
+        # Zuerst die Schleifen parsen\r
+\r
+        if(is_array($this->loop_vars) && ($loops = array_keys($this->loop_vars))) {\r
+            foreach($loops as $loop) {\r
+                $this->parse_loop($loop);\r
+            }\r
+        }\r
+\r
+        # In Template-Datei definierte Variablen auslesen\r
+\r
+        $this->get_defined_vars();\r
+\r
+        # Variablen ersetzen\r
+\r
+        if(($vars = $this->get_var()) !== false && is_array($vars)) {\r
+            $this->parse_if_blocks();\r
+            $this->replace_vars();\r
+        }\r
+\r
+        # {TRIM}-Bloecke entfernen\r
+\r
+        $this->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
+    function parse_old() {\r
+        # Zuerst die Schleifen parsen\r
+\r
+        if(is_array($this->loop_vars) && ($loops = array_keys($this->loop_vars))) {\r
+            foreach($loops as $loop) {\r
+                $this->parse_loop($loop);\r
+            }\r
+        }\r
+\r
+        # Normale Variablen durchgehen\r
+\r
+        if(($vars = $this->get_var()) !== false && is_array($vars)) {\r
+            foreach($vars as $var) {\r
+                $val = $this->get_var($var);\r
+\r
+                $this->parse_if_block($var,$val);\r
+\r
+                if(is_array($val)) {\r
+                    $this->fillin_array($var,$val);\r
+                }\r
+                else {\r
+                    $this->fillin($var,$val);\r
+                }\r
+\r
+                unset($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
+        $this->get_defined_vars();\r
+\r
+        foreach($this->defined_vars as $var) {\r
+            $val = $this->get_var($var);\r
+\r
+            $this->parse_if_block($var,$val);\r
+            $this->fillin($var,$val);\r
+\r
+            unset($val);\r
+        }\r
+\r
+        # {TRIM}-Bloecke entfernen\r
+\r
+        $this->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
+    function fillin($var,$text) {\r
+        $template = $this->get_template();\r
+        $template = str_replace('{'.$var.'}',$text,$template);\r
+\r
+        $this->set_template($template);\r
+    }\r
+\r
+    # fillin_array()\r
+    #\r
+    # Variable durch Array ersetzen\r
+    #\r
+    # Parameter: 1. Variable zum Ersetzen\r
+    #            2. Array, durch das 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
+    function fillin_array($var,$array,$glue='') {\r
+        $this->fillin($var,implode($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
+    function replace_vars($valid=array()) {\r
+        $template = $this->get_template();\r
+\r
+        $valid_vars = (empty($valid)) ? $this->get_var() : $valid;\r
+\r
+        for($x=0;$x<strlen($template);$x++) {\r
+            if($template[$x] == '{') {\r
+                foreach($valid_vars as $var) {\r
+                    # Pruefen, ob hier eine gueltige Variable beginnt\r
+\r
+                    if(substr($template,$x+1,strlen($var)+1) == $var.'}') {\r
+                        if(is_array($this->get_var($var))) {\r
+                            $content = implode('',$this->get_var($var));\r
+                        }\r
+                        else {\r
+                            $content = $this->get_var($var);\r
+                        }\r
+\r
+                        # Daten vor und nach der Variable\r
+\r
+                        $pre  = substr($template,0,$x);\r
+                        $post = substr($template,strlen($pre)+2+strlen($var));\r
+\r
+                        # Alles neu zusammensetzen\r
+\r
+                        $template = $pre.$content.$post;\r
+\r
+                        # Zaehler aendern\r
+\r
+                        $x = strlen($pre.$content)-1;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        $this->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
+    function to_file($handle) {\r
+        return @fwrite($handle,$this->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
+    function reset() {\r
+        $this->template = $this->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
+    function save_state() {\r
+        $this->original = $this->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
+    function parse_loop($name) {\r
+        $template = $this->get_template();\r
+        if(strpos($template,'{LOOP '.$name.'}') === false) return;\r
+\r
+        $offset   = 0;\r
+        $name_len = strlen($name);\r
+\r
+        while(($begin = strpos($template,'{LOOP '.$name.'}',$offset)) !== false) {\r
+            if(($end = strpos($template,'{ENDLOOP}',$begin+6+$name_len)) !== false) {\r
+                $block   = substr($template,$begin,$end+9-$begin);\r
+                $content = substr($block,$name_len+7,-9);\r
+\r
+                $parsed_block = '';\r
+\r
+                for($x=0;$x<count($this->loop_vars[$name]);$x++) {\r
+                    $loop_data = $this->loop_vars[$name][$x];\r
+                    $loop_vars = array_keys($loop_data);\r
+\r
+                    $ctpl = new Template;\r
+                    $ctpl->set_template($content);\r
+\r
+                    foreach($loop_vars as $loop_var) {\r
+                        $ctpl->set_var($name.'.'.$loop_var,$loop_data[$loop_var]);\r
+                    }\r
+\r
+                    if($this->old_parsing) {\r
+                        $ctpl->parse_old();\r
+                    }\r
+                    else {\r
+                        $ctpl->parse();\r
+                    }\r
+\r
+                    $parsed_block .= $ctpl->get_template();\r
+\r
+                    unset($ctpl);\r
+                }\r
+\r
+                $template = str_replace($block,$parsed_block,$template);\r
+                $offset   = $begin+strlen($parsed_block);\r
+            }\r
+            else break;\r
+        }\r
+\r
+        $this->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
+        function get_defined_vars() {\r
+            $template = $this->get_template();\r
+            if(strpos($template,'{DEFINE ') === false) return;\r
+\r
+            $offset = 0;\r
+\r
+            while(strpos($template,'{DEFINE ',$offset) !== false) {\r
+                $begin  = strpos($template,'{DEFINE ',$offset)+8;\r
+                $offset = $begin;\r
+\r
+                $name    = '';\r
+                $content = '';\r
+\r
+                $var_open     = 0;\r
+                $name_found   = 0;\r
+                $define_block = 0;\r
+\r
+                for($x=$begin;$x<strlen($template);$x++) {\r
+                    if($template[$x] == "\012" || $template[$x] == "\015") {\r
+                        # Wenn in einem {DEFINE}-Block ein Zeilenumbruch gefunden wird,\r
+                        # brechen wir mit dem Parsen des Blockes ab\r
+\r
+                        break;\r
+                    }\r
+\r
+                    if($var_open == 1) {\r
+                        if($template[$x] == '"') {\r
+                            # Der Inhalt der Variable ist hier zu Ende\r
+\r
+                            $var_open = 0;\r
+\r
+                            if($template[$x+1] == '}') {\r
+                                # Hier ist der Block zu Ende\r
+\r
+                                if($this->get_var($name) === false) {\r
+                                    # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+                                    $this->set_var($name,$content);\r
+                                    array_push($this->defined_vars,$name);\r
+                                }\r
+\r
+                            # {DEFINE}-Block entfernen\r
+\r
+                            $pre  = substr($template,0,$begin-8);\r
+                            $post = substr($template,$x+2);\r
+\r
+                            $template = $pre.$post;\r
+\r
+                            # Fertig!\r
+\r
+                            $offset = strlen($pre);\r
+                            break;\r
+                        }\r
+                    }\r
+                    elseif($template[$x] == '\\') {\r
+                        # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen\r
+\r
+                        if($template[$x+1] == 'n') {\r
+                            # "\n" in Zeilenumbrueche umwandeln\r
+\r
+                            $content .= "\n";\r
+                        }\r
+                        else $content .= $template[$x+1];\r
+\r
+                        $x++;\r
+                    }\r
+                    else $content .= $template[$x];\r
+                }\r
+                else {\r
+                    if($name_found == 1) {\r
+                        if($var_open == 0) {\r
+                            if($template[$x] == '"') $var_open = 1;\r
+                            else break;\r
+                        }\r
+                    }\r
+                    else {\r
+                        # Variablennamen auslesen\r
+\r
+                        if($template[$x] == '}' && $name != '') {\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(($end = strpos($template,'{ENDDEFINE}',$x)) !== false) {\r
+                                $x++;\r
+\r
+                                $content = substr($template,$x,$end-$x);\r
+\r
+                                if($this->get_var($name) === false) {\r
+                                    # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+                                    $this->set_var($name,$content);\r
+                                    array_push($this->defined_vars,$name);\r
+                                }\r
+\r
+                                $pre  = substr($template,0,$begin-8);\r
+                                $post = substr($template,$end+11);\r
+\r
+                                $template = $pre.$post;\r
+\r
+                                # Fertig!\r
+\r
+                                $offset = strlen($pre);\r
+                                break;\r
+                            }\r
+                            else break;\r
+                        }\r
+                        elseif($template[$x] != ' ') {\r
+                            $name .= $template[$x];\r
+                        }\r
+                        elseif($name != '') {\r
+                            $name_found = 1;\r
+                        }\r
+                        else break;\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        $this->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
+    function parse_if_block($name,$state,$no_negate=0) {\r
+        $template = $this->get_template();\r
+\r
+        $count = 0;\r
+\r
+        while(strpos($template,'{IF '.$name.'}') !== false) {\r
+            # Das alles hier ist nicht wirklich elegant geloest...\r
+            # ... aber solange es funktioniert... ;-)\r
+\r
+            $count++;\r
+\r
+            $start    = strpos($template,'{IF '.$name.'}');\r
+            $tpl_tmp  = substr($template,$start);\r
+            $splitted = explode('{ENDIF}',$tpl_tmp);\r
+\r
+            $block = ''; # Kompletter bedingter Block\r
+            $ifs   = 0;  # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt)\r
+\r
+            # {IF}\r
+\r
+            for($x=0;$x<count($splitted);$x++) {\r
+                if($x == count($splitted)-1) die('Nesting error found while parsing IF block "'.$name.'" nr. '.$count.' in template file "'.$this->file.'"');\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
+                    break;\r
+                }\r
+            }\r
+\r
+            $if_block = substr($block,strlen($name)+5,-7); # Alles zwischen {IF} und {ENDIF}\r
+\r
+            # {ELSE}\r
+\r
+            $else_block = ''; # Alles ab {ELSE}\r
+            $ifs        = 0;  # IF-Zaehler\r
+\r
+            $splitted = explode('{ELSE}',$if_block);\r
+\r
+            for($x=0;$x<count($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($y=$x+1;$y<count($splitted);$y++) {\r
+                        $else_block .= '{ELSE}'.$splitted[$y];\r
+                    }\r
+\r
+                    if($else_block) {\r
+                        $if_block   = substr($if_block,0,strlen($if_block)-strlen($else_block));\r
+                        $else_block = substr($else_block,6);\r
+                    }\r
+\r
+                    break;\r
+                }\r
+            }\r
+\r
+            # Block durch die jeweiligen Daten ersetzen\r
+            \r
+            $replacement = ($state) ? $if_block : $else_block;\r
+\r
+            $template = str_replace($block,$replacement,$template);\r
+        }\r
+\r
+        $this->set_template($template);\r
+\r
+        # Evtl. verneinte Form parsen\r
+\r
+        if(!$no_negate) {\r
+            $this->parse_if_block('!'.$name,!$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
+    function parse_if_blocks($valid=array()) {\r
+        $valid_vars = (empty($valid)) ? $this->get_var() : $valid;\r
+\r
+        foreach($valid_vars as $valid_var) {\r
+            $this->parse_if_block($valid_var,$this->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
+    function parse_trim_blocks() {\r
+        $template = $this->get_template();\r
+        if(strpos($template,'{TRIM}') === false) return;\r
+\r
+        $offset = 0;\r
+\r
+        while(($begin = strpos($template,'{TRIM}',$offset)) !== false) {\r
+            if(($end = strpos($template,'{ENDTRIM}',$begin+6)) !== false) {\r
+                $block    = substr($template,$begin,$end+9-$begin);\r
+                $content  = substr($block,6,-9);\r
+\r
+                $trimmed  = trim($content);\r
+\r
+                $template = str_replace($block,$trimmed,$template);\r
+\r
+                $offset   = $begin+strlen($trimmed);\r
+            }\r
+            else break;\r
+        }\r
+\r
+        $this->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
+    function parse_condtag($condtag,$state) {\r
+        $template = $this->get_template();\r
+\r
+        while(strpos($template,'<'.$condtag.'>') !== false) {\r
+            $start = strpos($template,'<'.$condtag.'>');                                        # Beginn des Blocks\r
+            $end   = strpos($template,'</'.$condtag.'>')+strlen($condtag)+3;                    # Ende des Blocks\r
+\r
+            $extract = substr($template,$start,$end-$start);                                    # Kompletten Bedingungsblock extrahieren...\r
+\r
+            $replacement = ($state) ? substr($extract,strlen($condtag)+2,0-strlen($condtag)-3) : '';\r
+\r
+            $template = str_replace($extract,$replacement,$template);                           # Block durch neue Daten ersetzen\r
+        }\r
+\r
+        $this->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
+    function parse_includes() {\r
+        $template = $this->get_template();\r
+        if(strpos($template,'{INCLUDE ') === false) return;\r
+\r
+        $offset = 0;\r
+\r
+        $y = 0;\r
+\r
+        while(($begin = strpos($template,'{INCLUDE ',$offset)) !== false) {\r
+            $y++;\r
+\r
+            $start  = $begin+9;\r
+            $offset = $start;\r
+            $long   = 0;\r
+\r
+            if($template[$start] == '"') {\r
+                $long = 1;\r
+                $start++;\r
+            }\r
+\r
+            $file = '';\r
+            $skip = 0;\r
+\r
+            for($x=$start;$x<strlen($template);$x++) {\r
+                if($template[$x] == "\012" || $template[$x] == "\015") {\r
+                    $skip = 1;\r
+                    break;\r
+                }\r
+                elseif($long == 0 && $template[$x] == ' ') {\r
+                    $skip = 1;\r
+                    break;\r
+                }\r
+                elseif($long == 1 && $template[$x] == '"') {\r
+                    if($template[$x+1] != '}') $skip = 1;\r
+                    break;\r
+                }\r
+                elseif($long == 0 && $template[$x] == '}') {\r
+                    break;\r
+                }\r
+                else {\r
+                    $file .= $template[$x];\r
+                }\r
+            }\r
+\r
+            if($skip == 1) continue;\r
+\r
+            if($file != '') {\r
+                $filepath = $file;\r
+\r
+                $is_absolute = (strtoupper(substr(PHP_OS,0,3)) === 'WIN')\r
+                             ? preg_match('!^([a-z]:)?/!i',$file)\r
+                             : preg_match('!^/!',$file);\r
+\r
+                if(!$is_absolute) {\r
+                    if(!empty($this->file)) $dir = dirname($this->file);\r
+                    else $dir = '.';\r
+\r
+                    $dir = str_replace('\\','/',$dir);\r
+\r
+                    if(!preg_match('!/+$!',$dir)) $dir .= '/';\r
+\r
+                    $filepath = $dir.$file;\r
+                }\r
+\r
+                if(is_file($filepath)) {\r
+                    $inc = new Template;\r
+                    $inc->read_file($filepath);\r
+\r
+                    $end = ($long == 1)\r
+                         ? $start + strlen($file) + 2\r
+                         : $start + strlen($file) + 1;\r
+\r
+                    $pre  = substr($template,0,$begin);\r
+                    $post = substr($template,$end);\r
+\r
+                    $template = $pre.$inc->get_template().$post;\r
+                    $offset   = strlen($pre)+strlen($inc->get_template());\r
+\r
+                    unset($inc);\r
+                }\r
+            }\r
+        }\r
+\r
+        $this->set_template($template);\r
+    }\r
+}\r
+\r
+#\r
+### Ende ###\r
+\r
+?>
\ No newline at end of file
diff --git a/doc/aufbau.htm b/doc/aufbau.htm
new file mode 100644 (file)
index 0000000..81b147e
--- /dev/null
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Aufbau einer Template-Datei</title>\r
+<meta name="author" content="Patrick Canterino" />\r
+<link rel="stylesheet" href="style.css" type="text/css" />\r
+<base target="_self" />\r
+</head>\r
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#0000FF" alink="#0000FF">\r
+\r
+<h1><a name="top" id="top">Aufbau einer Template-Datei</a></h1>\r
+\r
+<ul id="content">\r
+<li><a href="#bemerkung">Bemerkung</a></li>\r
+<li><a href="#variablen">Variablen</a></li>\r
+<li><a href="#definitionen">Variablen-Definitionen</a></li>\r
+<li><a href="#bedingt">Bedingte Abschnitte</a></li>\r
+<li><a href="#schleifen">Schleifen</a></li>\r
+<li><a href="#includes">Includes</a></li>\r
+<li><a href="#trim"><code>{TRIM}</code>-Bl&ouml;cke</a></li>\r
+</ul>\r
+\r
+<h2><a name="bemerkung" id="bemerkung">Bemerkung</a></h2>\r
+\r
+<p>Beachten Sie bitte, dass der Template-Parser sehr streng ist! Wenn die Anweisungen nicht exakt die hier aufgef&uuml;hrte Syntax aufweisen, werden Sie vom Parser nicht verarbeitet.</p>\r
+\r
+<p>Ich wei&szlig;, dass dies vor allem bei den <a href="#definitionen">Variablen-Definitionen</a> f&uuml;r &Uuml;bersicht sorgen w&uuml;rde, aber ich habe momentan echt keine Lust darauf, mich damit herumzuschlagen, den Parser toleranter zu machen.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="variablen" id="variablen">Variablen</a></h2>\r
+\r
+<p>Variablen werden beim Parsen der Template-Datei durch Werte ersetzt. Die Variablen k&ouml;nnen entweder <a href="parsen.htm#variablen-setzen">im Script</a> oder <a href="#definitionen">direkt in der Template-Datei</a> definiert werden.</p>\r
+\r
+<p>Variablen sind ganz simpel aufgebaut, es ist einfach nur ein beliebiger Name, der von geschweiften Klammern umgeben ist:</p>\r
+\r
+<pre class="code">\r
+{Name}\r
+</pre>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="definitionen" id="definitionen">Variablen-Definitionen</a></h2>\r
+\r
+<p>Neben der M&ouml;glichkeit, Variablen &uuml;ber das Script zu setzen, haben Sie auch die M&ouml;glichkeit, direkt in der Template-Datei Variablen zu definieren. Allerdings haben die Variablen, die aus dem Script stammen, Vorrang gegen&uuml;ber den in der Template definierten.</p>\r
+\r
+<p>Es gibt zwei Varianten, in der Template-Datei Variablen zu definieren. Die erste Variante ist eher f&uuml;r k&uuml;rzere Texte gedacht:</p>\r
+\r
+<pre class="code">\r
+{DEFINE Name &quot;Wert&quot;}\r
+</pre>\r
+\r
+<p>Hierbei erh&auml;lt die Variable <i>Name</i> den Wert <i>Wert</i>. Der Name der Variable darf keine Leerzeichen oder Zeilenumbr&uuml;che oder das }-Zeichen enthalten.<br />\r
+Soll der Wert einen Zeilenumbruch verwenden, so m&uuml;ssen Sie diesen als <code>\n</code> angeben. Soll ein doppeltes Anf&uuml;hrungszeichen im Wert vorkommen, so m&uuml;ssen Sie diesem ebenfalls einen Backslash voranstellen (<code>\&quot;</code>).</p>\r
+\r
+<p>Die zweite Variante ist mehr f&uuml;r l&auml;ngere Werte gedacht:</p>\r
+\r
+<pre class="code">\r
+{DEFINE Name}Wert{ENDDEFINE}\r
+</pre>\r
+\r
+<p>Auch hier erh&auml;lt die Variable <i>Name</i> den Wert <i>Wert</i>. Der Name darf auch hier keine Leerzeichen oder Zeilenumbr&uuml;che oder das }-Zeichen enthalten. Der Wert darf jedes Zeichen, auch Zeilenumbr&uuml;che enthalten.</p>\r
+\r
+<p>Nach dem Auslesen wird jeweils der ganze <code>{DEFINE}</code>-Abschnitt entfernt.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="bedingt" id="bedingt">Bedingte Abschnitte</a></h2>\r
+\r
+<p>Mit Hilfe von bedingten Abschnitten k&ouml;nnen Sie testen, ob <a href="#variablen">Variablen</a> gesetzt sind oder nicht. Es sind also nur Wahr/Unwahr-Abfragen m&ouml;glich, echte Vergleiche (z.B. mit Gleich, Ungleich usw.) lassen sich leider (noch) nicht durchf&uuml;hren.<br />\r
+Ein bedingter Abschnitt wird von einem <code>{IF Name}</code> (wobei <i>Name</i> f&uuml;r den Namen einer Variable steht) und von einem <code>{ENDIF}</code> abschlossen.</p>\r
+\r
+<pre class="code">\r
+{IF Name}Das ist ein bedingter Abschnitt!{ENDIF}\r
+</pre>\r
+\r
+<p>Es ist &uuml;brigens m&ouml;glich, auch mehrere IF-Bl&ouml;cke ineinander zu verschachteln.<br />\r
+Weiterhin gibt es die M&ouml;glichkeit, <code>{ELSE}</code>-Abschnitte einzuf&uuml;gen. Die werden dann angezeigt, wenn die Bedingung nicht erf&uuml;llt, also <i>false</i> ist.</p>\r
+\r
+<pre class="code">\r
+{IF Name}Bedingung erf&uuml;llt!{ELSE}Bedingung nicht erf&uuml;llt!{ENDIF}\r
+</pre>\r
+\r
+<p>Es ist au&szlig;erdem m&ouml;glich, einen Block zu verneinen:</p>\r
+\r
+<pre class="code">\r
+{IF !Name}Bedingung nicht erf&uuml;llt!{ENDIF}\r
+</pre>\r
+\r
+<p>Verneinte Bl&ouml;cke werden automatisch verarbeitet.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="schleifen" id="schleifen">Schleifen</a></h2>\r
+\r
+<p>Schleifen sind Abschnitte, die mehrmals hintereinander ausgegeben werden. Dadurch k&ouml;nnen Sie darauf verzichten, f&uuml;r hintereinander auszugebende Abschnitte kleine Extra-Template-Dateien anzulegen.</p>\r
+\r
+<p>Schleifen werden durch ein <code>{LOOP}</code> und dem Namen der Schleife eingeleitet und durch ein <code>{ENDLOOP}</code> abgeschlossen:</p>\r
+\r
+<pre class="code">\r
+{LOOP Name}\r
+Dies ist die Schleife mit dem Namen &quot;Name&quot;!\r
+{ENDLOOP}\r
+</pre>\r
+\r
+<p>Sie haben nun die M&ouml;glichkeit, f&uuml;r jeden Schleifendurchgang einen Satz <a href="#variablen">Variablen</a> zu definieren (oder auch f&uuml;r alle auf einmal), bei denen man nat&uuml;rlich auch pr&uuml;fen kann, ob sie <a href="#bedingt">gesetzt</a> sind. Variablen f&uuml;r die Schleife sind etwas anders aufgebaut. Sie beginnen mit dem Namen der Schleife, dann kommt ein Punkt und dann der eigentliche Name der Variable. Dadurch gelten die Variablen wirklich nur f&uuml;r die Schleife.</p>\r
+\r
+<pre class="code">\r
+{LOOP Test}\r
+{IF Test.Variable}\r
+F&uuml;r diesen Schleifendurchgang wurde die Variable &quot;Variable&quot; gesetzt! Sie hat den Inhalt {Test.Variable}.\r
+{ELSE}\r
+Die Variable &quot;Variable&quot; wurde nicht gesetzt.\r
+{ENDIF}\r
+{ENDLOOP}\r
+</pre>\r
+\r
+<p><b>Vorsicht:</b> Es ist derzeit noch nicht m&ouml;glich, Schleifen ineinander zu verschachteln, d.h. in einer Schleife darf sich keine weitere Schleife befinden.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="includes" id="includes">Includes</a></h2>\r
+\r
+<p>Mit Hilfe von <code>{INCLUDE}</code>-Anweisungen k&ouml;nnen Sie den Inhalt einer anderen Datei in die Template-Datei einf&uuml;gen. Das ist zum Beispiel f&uuml;r immer wiederkehrende Abschnitte sinnvoll, beispielsweise Kopf und Fu&szlig; einer HTML-Datei.</p>\r
+\r
+<p>Um den Inhalt einer anderen Datei in die Template-Datei in die Template einzuf&uuml;gen, geben Sie einfach an der entsprechenden Stelle diese Anweisung an:</p>\r
+\r
+<pre class="code">\r
+{INCLUDE Dateiname}\r
+</pre>\r
+\r
+<p>Wenn der Dateiname Leerzeichen oder das }-Zeichen enth&auml;lt, so m&uuml;ssen Sie den Dateinamen in doppelte Anf&uuml;hrungszeichen setzen:</p>\r
+\r
+<pre class="code">\r
+{INCLUDE &quot;Andere Datei&quot;}\r
+</pre>\r
+\r
+<p>Wenn Sie einen relativen Dateipfad angeben, so gilt dieser relativ zur Template-Datei. In &auml;lteren Versionen der Template-Klasse (Versionsnummer kleiner als 2.0) waren relative Pfade relativ zum Script.</p>\r
+\r
+<p>Wenn sich in der einzubindenden Datei ebenfalls <code>{INCLUDE}</code>-Anweisungen befinden, so werden diese ebenfalls verarbeitet.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="trim" id="trim"><code>{TRIM}</code>-Bl&ouml;cke</a></h2>\r
+\r
+<p>Sie k&ouml;nnen bestimmte Abschnitte in <code>{TRIM}</code>...<code>{ENDTRIM}</code>-Bl&ouml;cke einschlie&szlig;en. Beim Parsen der Template-Datei werden bei den Bl&ouml;cken voran- oder nachgestellte Leerzeichen, Zeilenumbr&uuml;che (LF, CR, CRLF) und Tabulatoren entfernt, so als w&uuml;rde man in PHP die Funktion <code>trim()</code> oder in Python die String-Methode <code>strip()</code> auf den Block anwenden (in Perl wird das ganze mit zwei regul&auml;ren Ausdr&uuml;cken erreicht).</p>\r
+\r
+<p>Sinnvoll k&ouml;nnen die <code>{TRIM}</code>-Bl&ouml;cke zum Beispiel sein, wenn Sie in der Template-Datei viele Variablen definieren und nicht m&ouml;chten, dass nach dem Auslesen &uuml;berfl&uuml;ssige Leerzeichen &uuml;brigbleiben:</p>\r
+\r
+<pre class="code">\r
+{TRIM}\r
+{DEFINE name &quot;Homer Simpson&quot;}\r
+{DEFINE email &quot;homer.simpson@example.org&quot;}\r
+{ENDTRIM}\r
+</pre>\r
+\r
+<p>Ohne den <code>{TRIM}</code>-Block w&uuml;rden hier sinnlose Leerzeilen stehenbleiben.</p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p><a href="index.htm">Zur &Uuml;bersicht</a></p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p style="font-size:8pt">&copy;&nbsp;2002-2011 Patrick Canterino</p>\r
+\r
+<table border="0" cellspacing="0" style="font-size:8pt">\r
+<tr>\r
+<td>Homepage:</td>\r
+<td><a href="http://www.patshaping.de/">http://www.patshaping.de/</a></td>\r
+</tr>\r
+<tr>\r
+<td><a name="bottom" id="bottom">E-Mail:</a></td>\r
+<td><a href="mailto:patrick@patshaping.de">patrick@patshaping.de</a></td>\r
+</tr>\r
+</table>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/doc/changes.htm b/doc/changes.htm
new file mode 100644 (file)
index 0000000..87dfacb
--- /dev/null
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Versionshistorie</title>\r
+<meta name="author" content="Patrick Canterino" />\r
+<link rel="stylesheet" href="style.css" type="text/css" />\r
+</head>\r
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#0000FF" alink="#0000FF">\r
+\r
+<h1>Versionshistorie</h1>\r
+\r
+<p><b>Neu in Version&nbsp;2.5</b> (vom 27.11.2011)</p>\r
+\r
+<ul>\r
+<li><b>Variablen werden komplett anders ersetzt:</b><br />\r
+Der Vorgang des Ersetzens der Variablen wurde komplett ge&auml;ndert. Die Template-Klasse durchsucht den Template-Text nun Zeichen f&uuml;r Zeichen und ersetzt Variablen durch Text. Der Sinn hinter ist, dass auf diese Weise keine Variablen in Variablen mehr ersetzt werden k&ouml;nnen.<br />\r
+Dieses neue Verfahren ist deaktivierbar, d.h. man kann bei Problemen auf das alte Verfahren, das einfach nur Zeichenketten ersetzt, zur&uuml;ckgreifen.</li>\r
+<li><b><code>set_vars()</code> und <code>add_vars()</code>:</b><br />\r
+Mit den neuen Methoden <code>set_vars()</code> und <code>add_vars()</code> ist es nun m&ouml;glich, die interne Variablenliste komplett zu &uuml;berschreiben oder mit mehreren Variablen und Werten auf einmal zu erg&auml;nzen.</li>\r
+<li><b><code>{TRIM}</code>-Bl&ouml;cke in der Perl-Version funktionieren jetzt:</b><br />\r
+Das Verarbeiten der <code>{TRIM}</code>-Bl&ouml;cke hat in der Perl-Version nicht funktioniert, da eine falsche Variable verwendet wurde. Dieser Fehler wurde behoben.</li>\r
+<li><b>Anderer Programmierstil:</b><br />\r
+Der Programmierstil wurde ge&auml;ndert. Dies betrifft vor allem die Einr&uuml;ckungen.</li>\r
+<li><b>Dokumentation korrigiert:</b><br />\r
+In der Dokumentation war die Beschreibung f&uuml;r die <code>reset()</code>- und die <code>save_state()</code>-Methode unvollst&auml;ndig.</li>\r
+<li><b>Neue Lizenz:</b><br />\r
+Die Template-Klasse ist nun unter den Bedingungen der <a href="http://www.opensource.org/licenses/artistic-license-2.0.php">Artistic License 2.0</a> lizenziert.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;2.0</b> (vom 9.8.2006)</p>\r
+\r
+<ul>\r
+<li><b><code>get_var()</code>, <code>set_var()</code> und <code>parse()</code>:</b><br />\r
+Um die Arbeit mit der Template-Klasse etwas zu vereinfachen, wurde ein neues Interface f&uuml;r die Haupt-Arbeit eingef&uuml;hrt. Es besteht im Wesentlichen aus den drei neuen Methoden <code>get_var()</code>, <code>set_var()</code> und <code>parse()</code>.\r
+<ul>\r
+<li><code>get_var()</code> gibt den Wert einer Variablen zur&uuml;ck. Wenn kein Name angegeben wurde, gibt <code>get_var()</code> die Namen aller definierten Variablen zur&uuml;ck.</li>\r
+<li><code>set_var()</code> weist einer Variablen einen Wert zu.</li>\r
+<li><code>parse()</code> setzt die Variablen ein, verarbeitet die <code>{IF}</code>-Bl&ouml;cke, verarbeitet die Schleifen und liest die in der Template definierten Variablen aus.</li>\r
+</ul>\r
+</li>\r
+<li><b>Variablen direkt in der Template-Datei definieren:</b><br />\r
+Man kann nun mit Hilfe der neuen <code>{DEFINE}</code>-Bl&ouml;cke Variablen direkt in der Template-Datei definieren, so als h&auml;tte man sie mit <code>set_var()</code> definiert.<br />\r
+Es gibt hierbei zwei M&ouml;glichkeiten:\r
+<ol type="1">\r
+<li><code>{DEFINE Name &quot;Wert&quot;}</code>:<br />\r
+Hierbei erh&auml;lt die Variable &quot;Name&quot; den Wert &quot;Wert&quot;. Innerhalb des Blockes d&uuml;rfen keine Zeilenumbr&uuml;che vorkommen, ansonsten wird er ignoriert. Der Name der Variable darf keine Zeilenumbr&uuml;che oder Leerzeichen enthalten. Wenn der Wert ausgelesen wird, so wird <code>\n</code> durch einen Zeilenumbruch ersetzt.</li>\r
+<li><code>{DEFINE Name}Wert{ENDDEFINE}</code>:<br />\r
+Auch hier erh&auml;lt die Variable &quot;Name&quot; den Wert &quot;Wert&quot;. Der Name darf ebenfalls keine Zeilenumbr&uuml;che oder Leerzeichen enthalten, der Wert allerdings schon.</li>\r
+</ol>\r
+Die direkt mit <code>set_var()</code> haben allerdings Vorrang gegen&uuml;ber den erst &uuml;ber <code>{DEFINE}</code> definierten. Zus&auml;tzlich werden zweitere erst von <code>parse()</code> abgearbeitet, wenn erstere abgearbeitet wurden.</li>\r
+<li><b>Schleifen:</b><br />\r
+Es wurde eine einfache M&ouml;glichkeit zur Realisierung von Schleifen in einer Template-Datei hinzugef&uuml;gt.<br />\r
+Man kann einen Block jetzt in <code>{LOOP}</code>...<code>{ENDLOOP}</code>-Bl&ouml;cke einschlie&szlig;en. Dieser Block bekommt einen Namen, diesem Namen werden dann &uuml;ber die Methoden <code>add_loop_data()</code> und/oder <code>set_loop_data()</code> Variablen zugewiesen. Der Block wird dann f&uuml;r jeden Durchgang mit neuen Werten ausgegeben.<br />\r
+Der Vorteil hiervon ist, dass man so f&uuml;r sich wiederholende Bl&ouml;cke keine separate Template-Dateien erstellen muss.<br />\r
+Es ist zur Zeit leider noch nicht m&ouml;glich, Schleifen zu verschachteln!</li>\r
+<li><b><code>{TRIM}</code>-Bl&ouml;cke:</b><br />\r
+Man kann jetzt Textstellen in <code>{TRIM}</code>-Bl&ouml;cke einschlie&szlig;en. Beim Inhalt werden vorangestellte und abschlie&szlig;endende Leerzeichen und Zeilenumbr&uuml;che entfernt.</li>\r
+<li><b>Verhalten der <code>{INCLUDE}</code>-Anweisungen ver&auml;ndert:</b><br />\r
+Das Verhalten der <code>{INCLUDE}</code>-Anweisungen wurde in einigen F&auml;llen ge&auml;ndert:\r
+<ul>\r
+<li>Wenn man bei einer <code>{INCLUDE}</code>-Anweisung einen relativen Pfad angibt, so gilt dieser Pfad nun relativ zur <b>Template-Datei</b> und nicht mehr zum Script.<br />\r
+So wollte ich das eigentlich immer haben. Das alte Verhalten war eine Notl&ouml;sung, weil ich mir nicht anders zu helfen wusste...</li>\r
+<li>Die Dateinamen, die bei einer <code>{INCLUDE}</code>-Anweisung angegeben werden, k&ouml;nnen nun auch Leerzeichen oder das }-Zeichen enthalten. In diesem Fall muss man den Dateinamen aber in doppelte Anf&uuml;hrungszeichen setzen.</li>\r
+</ul>\r
+</li>\r
+<li><b>Template zur&uuml;cksetzen:</b><br />\r
+Mit Hilfe der neuen <code>reset()</code>-Methode k&ouml;nnen Sie den Template-Text in den Zustand zur&uuml;ckversetzen, den er nach dem Auslesen der Template-Datei hatte. Zus&auml;tzlich k&ouml;nnen Sie mit <code>save_state()</code> den aktuellen Zustand des Template-Textes sichern und diesen dann bei Bedarf eben mit <code>reset()</code> wiederherstellen.</li>\r
+<li><b>Alias-Funktionen entfernt:</b><br />\r
+In der Perl- und in der PHP-Version wurden die alten Alias-Funktionen <code>addtext()</code>, <code>as_string()</code>, <code>condtag()</code> und <code>readin()</code> entfernt.</li>\r
+<li><b>Kleine Korrekturen:</b><br />\r
+Es wurden verschiedene, unterschiedliche kleine Korrekturen durchgef&uuml;hrt:\r
+<ul>\r
+<li>Die Perl-Version verwendet jetzt nicht mehr <code>split()</code>, um eine Zeichenkette aufzuteilen. Stattdessen verwendet sie nun meine <a href="http://www.patshaping.de/hilfen_ta/codeschnipsel/perl-explode.htm" target="_blank">Portierung der <code>explode()</code>-Funktion von PHP</a>. Die Grund hierf&uuml;r ist ein Problem von <code>split()</code>, welches auch auf der verlinkten Seite beschrieben wird.</li>\r
+<li>Die Python-Version verwendet jetzt die Objektmethoden des String-Datentyps anstatt der Methoden aus dem <tt>string</tt>-Modul.</li>\r
+<li>Die Python-Version kommt jetzt vollst&auml;ndig ohne regul&auml;re Ausdr&uuml;cke aus.</li>\r
+</ul>\r
+</li>\r
+<li><b>Dokumentation neu strukturiert:</b><br />\r
+Die Dokumentation wurde komplett neu strukturiert. Sie befindet sich nun im Unterverzeichnis <i>doc</i> und besteht aus mehreren Dateien.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.5a</b> (vom 6.6.2005)</p>\r
+\r
+<ul>\r
+<li><b>PHP-Version nun ohne &quot;Notices&quot;:</b><br />\r
+Die PHP-Version der Template-Klasse hat eine &quot;Notice&quot; erzeugt, wenn f&uuml;r <code>error_reporting</code> der Wert <code>E_ALL</code> eingestellt war.</li>\r
+<li><b>Fehlermeldung bei komplett leerer Template-Datei:</b><br />\r
+Wenn die PHP-Version der Klasse eine Template-Datei mit einer Gr&ouml;&szlig;e von 0&nbsp;Bytes h&auml;tte einlesen sollen, hatte <code>fread()</code> eine Fehlermeldung erzeugt. Das ist nun behoben.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.5</b> (vom 5.5.2005)</p>\r
+\r
+<ul>\r
+<li><b><code>{IF}</code>-Bl&ouml;cke verneinen:</b><br />\r
+Man kann <code>{IF}</code>-Bl&ouml;cke nun verneinen, indem man vor den Namen des Blockes ein <code>!</code> stellt. Die Methode <code>parse_if_block()</code> verarbeitet diese Bl&ouml;cke automatisch, es sei denn man setzt den neuen dritten Parameter dieser Routine auf <i>true</i>.</li>\r
+<li><b>Fehlende <code>{INCLUDE}</code>-Dateien:</b><br />\r
+Wenn eine Datei &uuml;ber eine <code>{INCLUDE}</code>-Anweisung eingebunden werden soll und die Datei existiert nicht, so wird diese Anweisung nicht mehr aus dem Vorlagentext entfernt.</li>\r
+<li><b>Python-Version:</b><br />\r
+Es existiert nun ebenfalls eine <a href="http://www.python.org/" target="_blank">Python</a>-Version der Template-Klasse. Von den Perl- und PHP-Versionen unterscheidet sie sich lediglich dadurch, dass sie nicht die Alias-Methoden bereitstellt (Methodennamen vor Version&nbsp;1.2).</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.4a</b> (vom 21.3.2005)</p>\r
+\r
+<ul>\r
+<li><b>Mehrere <code>{ENDIF}</code> am Ende des Vorlagentextes:</b><br />\r
+Wenn der Vorlagentext mit mehr als einem <code>{ENDIF}</code> endete, hat der <code>{IF}</code>-Parser der Perl-Version diese nicht gefunden und das Script wegen eines Verschachtelungsfehlers beendet.</li>\r
+<li><b>(Mal wieder) Nicht funktionierender Alias in PHP-Fassung:</b><br />\r
+F&uuml;r die Methode <code>add_text()</code> existiert aus Kompatibilit&auml;tsgr&uuml;nden ein Alias namens <code>addtext()</code>. In der PHP-Version der Klasse wurden die Argumente, die <code>addtext()</code> &uuml;bergeben wurden, nicht an <code>add_text()</code> weitergegeben.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.4</b> (vom 5.2.2005)</p>\r
+\r
+<ul>\r
+<li><b>Verschachtelungsfehler bei <code>{IF}</code>-Bl&ouml;cken:</b><br />\r
+Bisher geriet der <code>{IF}</code>-Parser immer in eine Endlosschleife, wenn die <code>{IF}</code>-Bl&ouml;cke nicht korrekt verschachtelt waren.<br />\r
+Das d&uuml;rfte jetzt behoben sein. Der Parser pr&uuml;ft jetzt, ob intern das letzte <code>{ENDIF}</code> &uuml;berschritten wurde. In diesem Fall wird das Script sofort mit einer Fehlermeldung beendet.</li>\r
+<li><b>Suchen von <code>{IF}</code>-Bl&ouml;cken in <code>{IF}</code>-Bl&ouml;cken</b>:<br />\r
+Um einen weiteren <code>{IF}</code>-Block in einem <code>{IF}</code>-Block zu erkennen, wird jetzt nicht mehr nach <code>{IF</code>, sondern nach <code>{IF&nbsp;</code> gesucht.<br />\r
+Das ist zwar immer noch nicht das, was ich eigentlich will, aber es ist etwas besser als die alte Methode. Ich w&uuml;rde es ja gerne mit einem regul&auml;ren Ausdruck l&ouml;sen, der nach <code>\{IF&nbsp;.+?\}</code> oder so sucht, aber das hat nur noch mehr Probleme bereitet.</li>\r
+<li><b>Einfache Anf&uuml;hrungszeichen statt doppelter:</b><br />\r
+Es wurden, wo es angebracht war, alle doppelten Anf&uuml;hrungszeichen durch einfache ersetzt. Das bringt hoffentlich einen Geschwindigkeitsgewinn.</li>\r
+<li><b>Name der Template-Datei in den Objekteigenschaften:</b><br />\r
+Der Name der von <code>read_file()</code> eingelesenen Template-Datei wird jetzt in den Objekteigenschaften gespeichert.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.3</b> (vom 20.5.2004)</p>\r
+\r
+<ul>\r
+<li><b><code>{INCLUDE}</code>-Anweisungen:</b><br />\r
+Es ist nun m&ouml;glich, in einer Vorlage <code>{INCLUDE Dateiname}</code>-Anweisungen einzubauen. Die Anweisungen werden beim Einlesen der Vorlagen-Datei durch den Inhalt der angegebenen Datei ersetzt.<br />\r
+Das Verarbeiten der <code>{INCLUDE}</code>-Anweisungen l&auml;sst sich auch von Hand durchf&uuml;hren und das automatische Verarbeiten beim Lesen einer Datei l&auml;sst sich auch verhindern.</li>\r
+<li><b><code>to_file()</code>:</b><br />\r
+Mit der neuen Methode <code>to_file()</code> ist es m&ouml;glich, den kompletten Vorlagentext in eine zuvor ge&ouml;ffnete Datei zu schreiben.</li>\r
+<li><b>Nicht funktionierender Alias in PHP-Fassung:</b><br />\r
+F&uuml;r die Methode <code>add_text()</code> existiert aus Kompatibilit&auml;tsgr&uuml;nden ein Alias namens <code>addtext()</code>. In der PHP-Version der Klasse rief dieser Alias jedoch nicht <code>add_text()</code> auf, sondern die nicht existierende Methode <code>add_template()</code>.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.2a</b> (vom 12.9.2003)</p>\r
+\r
+<ul>\r
+<li><b>Fehler in <code>substr_count()</code>:</b><br />\r
+Die von der Perl-Version der Klasse emulierte PHP-Funktion <code>substr_count()</code> enthielt einen Fehler. Wenn sich der zu suchende am Ende des zu durchsuchenden Strings befand, wurde er nicht gefunden.<br />\r
+Die richtige Methode, Strings in Strings zu z&auml;hlen, wurde <tt>perlfaq4</tt> entnommen.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.2</b> (vom 9.9.2003)</p>\r
+\r
+<ul>\r
+<li><b>Methoden umbenannt:</b><br />\r
+(Fast) Alle Methoden dieser Klasse haben neue, intelligentere Namen erhalten. Hier die neuen Namen im Einzelnen:<br />\r
+<code>addtext()</code> =&gt; <code>add_text()</code><br />\r
+<code>as_string()</code> =&gt; <code>get_template()</code><br />\r
+<code>condtag()</code> =&gt; <code>parse_condtag()</code><br />\r
+<code>readin()</code> =&gt; <code>read_file()</code><br />\r
+Die alten Namen lassen sich selbstverst&auml;ndlich weiterhin verwenden. Das k&ouml;nnte sich aber irgendwann &auml;ndern.</li>\r
+<li><b>ELSE hinzugef&uuml;gt:</b><br />\r
+Die IF-Syntax versteht nun auch <code>{ELSE}</code>-Abschnitte, die angezeigt werden, wenn die Bedingung nicht erf&uuml;llt ist.</li>\r
+<li><b>Variablen durch Array ersetzen:</b><br />\r
+Mit der neuen Funktion <code>fillin_array()</code> ist es nun m&ouml;glich, Variablen durch Arrays zu ersetzen.</li>\r
+<li><b><code>get_template()</code> und <code>set_template()</code>:</b><br />\r
+Mit Hilfe der neuen Methoden <code>get_template()</code> und <code>set_template()</code> ist es viel leichter geworden, auf den in den Objekt-Eigenschaften gespeicherten Vorlagentext zuzugreifen.</li>\r
+<li><b>Emuliertes <code>substr_count()</code> &uuml;berarbeitet:</b><br />\r
+Die von der Perl-Fassung der Klasse emulierte PHP-Funktion <code>substr_count()</code> wurde ein wenig verbessert. Sie teilt zun&auml;chst die Zeichenkette mit der zu z&auml;hlenden Zeichenkette auf. Anschlie&szlig;end z&auml;hlt sie von der Anzahl der so entstandenen Array-Elemente 1 ab und gibt das Ergebnis zur&uuml;ck.</li>\r
+<li><b>Keine regul&auml;re Ausdr&uuml;cke mehr in der PHP-Version:</b><br />\r
+Die PHP-Version der Klasse verwendet nun keine regul&auml;re Ausdr&uuml;cke mehr, was hoffentlich zu einer Geschwindigkeitsverbesserung f&uuml;hrt.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.1</b> (vom 21.7.2003)</p>\r
+\r
+<ul>\r
+<li><b>Neue IF-Syntax:</b><br />\r
+Es wird jetzt eine viel &uuml;bersichtlichere Syntax f&uuml;r bedingte Abschnitte verwendet. Diese Abschnitte werden mit einem <code>{IF}</code> eingeleitet und von einem <code>{ENDIF}</code> abgeschlossen.</li>\r
+<li><b>CondTag am Anfang:</b><br />\r
+Wenn ein CondTag-Abschnitt am Anfang eines Textes war, hat die PHP-Version diesen nicht erkannt, da die 0 als <i>false</i> interpretiert wurde.</li>\r
+</ul>\r
+\r
+<p><b>Neu in Version&nbsp;1.0</b> (vom 3.6.2003)</p>\r
+\r
+<ul>\r
+<li><b>Erste Version:</b><br />\r
+Dies ist die erste Version der Template-Klasse. Sie erschien mit der Version&nbsp;1.3 des <a href="http://www.patshaping.de/redirector/redirect.php?page=guestbook" target="_blank"><i>Guestbook</i></a> und wurde nicht offiziell zum Download angeboten.</li>\r
+</ul>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p><a href="index.htm">Zur &Uuml;bersicht</a></p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p style="font-size:8pt">&copy;&nbsp;2002-2011 Patrick Canterino</p>\r
+\r
+<table border="0" cellspacing="0" style="font-size:8pt">\r
+<tr>\r
+<td>Homepage:</td>\r
+<td><a href="http://www.patshaping.de/">http://www.patshaping.de/</a></td>\r
+</tr>\r
+<tr>\r
+<td><a name="bottom" id="bottom">E-Mail:</a></td>\r
+<td><a href="mailto:patrick@patshaping.de">patrick@patshaping.de</a></td>\r
+</tr>\r
+</table>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/doc/index.htm b/doc/index.htm
new file mode 100644 (file)
index 0000000..7dbaad5
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Dokumentation der Template-Klasse</title>\r
+<meta name="author" content="Patrick Canterino" />\r
+<link rel="stylesheet" href="style.css" type="text/css" />\r
+<base target="_self" />\r
+</head>\r
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#0000FF" alink="#0000FF">\r
+\r
+<h1><a name="top" id="top">Dokumentation der Template-Klasse</a></h1>\r
+\r
+<p>\r
+<a href="aufbau.htm">Aufbau einer Template-Datei</a><br />\r
+<a href="parsen.htm">Templates parsen</a><br />\r
+<a href="vonhand.htm">Templates &quot;von Hand&quot; parsen</a><br />\r
+<a href="changes.htm">Versionshistorie</a>\r
+</p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p style="font-size:8pt">&copy;&nbsp;2002-2011 Patrick Canterino</p>\r
+\r
+<table border="0" cellspacing="0" style="font-size:8pt">\r
+<tr>\r
+<td>Homepage:</td>\r
+<td><a href="http://www.patshaping.de/">http://www.patshaping.de/</a></td>\r
+</tr>\r
+<tr>\r
+<td><a name="bottom" id="bottom">E-Mail:</a></td>\r
+<td><a href="mailto:patrick@patshaping.de">patrick@patshaping.de</a></td>\r
+</tr>\r
+</table>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/doc/parsen.htm b/doc/parsen.htm
new file mode 100644 (file)
index 0000000..30cb3b3
--- /dev/null
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Templates parsen</title>\r
+<meta name="author" content="Patrick Canterino" />\r
+<link rel="stylesheet" href="style.css" type="text/css" />\r
+<base target="_self" />\r
+</head>\r
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#0000FF" alink="#0000FF">\r
+\r
+<h1><a name="top" id="top">Templates parsen</a></h1>\r
+\r
+<ul id="content">\r
+<li><a href="#laden-einlesen">Klasse laden und Template einlesen</a></li>\r
+<li><a href="#variablen-setzen">Variablen setzen</a></li>\r
+<li><a href="#schleifen-setzen">Daten f&uuml;r Schleifen setzen</a></li>\r
+<li><a href="#parsen">Templates parsen</a></li>\r
+</ul>\r
+\r
+<h2><a name="laden-einlesen" id="laden-einlesen">Klasse laden und Template einlesen</a></h2>\r
+\r
+<p>Erstmal ist es wichtig, die Klasse in Ihre Scripts einzubinden:</p>\r
+\r
+<pre class="code">\r
+# PHP:\r
+\r
+include(&quot;class.Template.php&quot;);\r
+\r
+# Perl:\r
+\r
+use Template;\r
+\r
+# Python:\r
+\r
+import template\r
+</pre>\r
+\r
+<p>Ggf. m&uuml;ssen Sie andere Pfade angeben, oder in Perl zun&auml;chst mit <code>use lib</code> einen weiteren Pfad f&uuml;r Perl-Module hinzuf&uuml;gen. Andererseits k&ouml;nnen Sie die Klassen auch direkt in Ihre Scripts einbetten.</p>\r
+\r
+<p>Nun m&uuml;ssen Sie ein neues Objekt der Klasse anlegen:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl = new Template;\r
+\r
+# Python:\r
+\r
+tpl = template.Template()\r
+</pre>\r
+\r
+<p>Dadurch stellt die Variable <code>$tpl</code> bzw. <code>tpl</code> ein neues Objekt der Template-Klasse dar (wird in den nachfolgenden Beispielen auch verwendet). &Uuml;ber das Objekt k&ouml;nnen Sie auf die verschiedenen Methoden der Klasse zugreifen.</p>\r
+\r
+<p>Das Wichtigste ist, erstmal eine Datei einzulesen. Das geschieht &uuml;ber die Methode <code>read_file()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;read_file(Datei);\r
+\r
+# Python:\r
+\r
+tpl.read_file(Datei)\r
+</pre>\r
+\r
+<p>Dadurch wird die angegebene Datei eingelesen und die <a href="aufbau.htm#includes"><code>{INCLUDE}</code>-Anweisungen</a> verarbeitet. Der Inhalt der Datei wird anschlie&szlig;end in den Objekteigenschaften gespeichert.<br />\r
+Es ist auch m&ouml;glich, den Vorlagentext direkt einzugeben. Das k&ouml;nnen Sie mit Hilfe der Methoden <code>set_template()</code> und <code>add_text()</code> erreichen. Das einzige Argument dieser Funktionen, ist der Text, der in den Objeteigenschaften gespeichert werden soll. <code>set_template()</code> legt den kompletten Vorlagentext fest, <code>add_text()</code> h&auml;ngt den Text nur an (<code>read_file()</code> verwendet diese Methode intern auch). <code>{INCLUDE}</code>-Anweisungen werden hierbei allerdings nicht verarbeitet, Sie k&ouml;nnen dies jedoch manuell durch Aufruf der Methode <code>parse_includes()</code> durchf&uuml;hren.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="variablen-setzen" id="variablen-setzen">Variablen setzen</a></h2>\r
+\r
+<p>Eines der wichtigsten Merkmale von Templates ist die Tatsache, dass bestimmte Abschnitte variabel sind, d.h. hier werden Daten vom Script eingef&uuml;llt. F&uuml;r diese Klasse werden die variablen Abschnitte von geschweiften Klammern umschlossen. Eine Variable kann zum Beispiel so aussehen:<br />\r
+<code>{VARIABLE}</code><br />\r
+Um f&uuml;r eine Variable einen Wert festzulegen, k&ouml;nnen Sie ganz einfach die Methode <code>set_var()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;set_var(Variablenname,Wert);\r
+\r
+# Python:\r
+\r
+tpl.set_var(Variablenname,Wert)\r
+</pre>\r
+\r
+<p>Bei den Variablen wird zwischen Gro&szlig;- und Kleinschreibung unterschieden. Die Variable <code>variable</code> ist also eine andere als <code>VARIABLE</code>.</p>\r
+\r
+<p>Sie k&ouml;nnen als Variable auch ein Array angeben, dieses wird dann ganz einfach zusammengef&uuml;gt.</p>\r
+\r
+<p>Auf den Inhalt einer Variable k&ouml;nnen Sie jederzeit mit der Methode <code>get_var()</code> zugreifen. Wenn die Variable nicht existiert, wird <code>false</code> zur&uuml;ckgegeben. Wenn Sie beim Aufruf von <code>get_var()</code> &uuml;berhaupt keinen Variablennamen angeben, wird ein Array mit den Namen s&auml;mtlicher definierten Variablen zur&uuml;ckgegeben.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="schleifen-setzen" id="schleifen-setzen">Daten f&uuml;r Schleifen setzen</a></h2>\r
+\r
+<p>Bei Schleifen haben Sie die M&ouml;glichkeit, entweder f&uuml;r jeden Abschnitt die Daten einzeln oder alle Daten auf einmal hinzuzuf&uuml;gen.<br />\r
+Dazu stehen Ihnen die Methoden <code>add_loop_data()</code> und <code>set_loop_data()</code> zur Verf&uuml;gung (erstere f&uuml;gt neue Daten hinzu, letztere setzt die Daten komplett). Beide Methoden verwenden dasselbe Schema. Als erster Parameter kommt der Name der Schleife, dann der Datensatz bzw. alle Daten. Der Datensatz besteht aus einem assoziativen Array bzw. Hash-Referenz bzw. Dictionary, bei dem die Schl&uuml;ssel den Namen der Variablen und der Wert eben den Wert der Variablen darstellen. Bei <code>set_loop_data()</code> m&uuml;ssen Sie die Datens&auml;tze als ein Array bzw. Array-Referenz bzw. Liste von Datens&auml;tzen &uuml;bergeben.</p>\r
+\r
+<p>Beispiel f&uuml;r <code>add_loop_data()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP:\r
+\r
+$tpl-&gt;add_loop_data('Test-Schleife',array('name' =&gt; 'Bart Simpson', 'email' =&gt; 'el-barto@example.org'));\r
+$tpl-&gt;add_loop_data('Test-Schleife',array('name' =&gt; 'Homer Simpson', 'email' =&gt; 'homer.simpson@example.org'));\r
+\r
+# Perl:\r
+\r
+$tpl-&gt;add_loop_data('Test-Schleife',{'name' =&gt; 'Bart Simpson', 'email' =&gt; 'el-barto@example.org'});\r
+$tpl-&gt;add_loop_data('Test-Schleife',{'name' =&gt; 'Homer Simpson', 'email' =&gt; 'homer.simpson@example.org'});\r
+\r
+# Python:\r
+\r
+tpl.add_loop_data('Test-Schleife',{'name': 'Bart Simpson', 'email': 'el-barto@example.org'})\r
+tpl.add_loop_data('Test-Schleife',{'name': 'Homer Simpson', 'email': 'homer.simpson@example.org'})\r
+</pre>\r
+\r
+<p>Beispiel f&uuml;r <code>set_loop_data()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP:\r
+\r
+$tpl-&gt;set_loop_data('Test-Schleife',array(array('name' =&gt; 'Bart Simpson', 'email' =&gt; 'el-barto@example.org'),\r
+                                          array('name' =&gt; 'Homer Simpson', 'email' =&gt; 'homer.simpson@example.org')));\r
+\r
+# Perl:\r
+\r
+$tpl-&gt;set_loop_data('Test-Schleife',[{'name' =&gt; 'Bart Simpson', 'email' =&gt; 'el-barto@example.org'},\r
+                                     {'name' =&gt; 'Homer Simpson', 'email' =&gt; 'homer.simpson@example.org'}]);\r
+\r
+# Python:\r
+\r
+tpl.set_loop_data('Test-Schleife',[{'name': 'Bart Simpson', 'email': 'el-barto@example.org'},\r
+                                   {'name': 'Homer Simpson', 'email': 'homer.simpson@example.org'}])\r
+</pre>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="parsen" id="parsen">Templates parsen</a></h2>\r
+\r
+<p>Wenn Sie alle Variablen und Schleifen-Daten gesetzt haben, ist es an der Zeit, diese Daten auch auf die Template-Datei anzuwenden. Dies geschieht mit Hilfe der Methode <code>parse()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse();\r
+\r
+# Python:\r
+\r
+tpl.parse()\r
+</pre>\r
+\r
+<p>Dadurch werden alle <a href="aufbau.htm#variablen">Variablen</a> durch Text ersetzt, <a href="aufbau.htm#bedingt">bedingte Bl&ouml;cke</a> und <a href="aufbau.htm#schleifen">Schleifen</a> verarbeitet und in der Template-Datei <a href="aufbau.htm#definitionen">definierte Variablen</a> ausgelesen und auf die Template-Datei angewendet.</p>\r
+\r
+<p>Zu guter letzt k&ouml;nnen Sie noch die verarbeiteten Daten zur&uuml;ckgeben lassen:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$template = $tpl-&gt;get_template();\r
+\r
+# Python:\r
+\r
+template = tpl.get_template()\r
+</pre>\r
+\r
+<p>Dadurch enth&auml;lt die Variable <code>$template</code> bzw. <code>template</code> die nun verarbeitete Template-Datei (sie k&ouml;nnen <code>get_template()</code> &uuml;brigens jederzeit verwenden, um an den Vorlagentext heranzukommen).</p>\r
+\r
+<p>Weiterhin k&ouml;nnen Sie den kompletten Vorlagentext auch in eine Datei schreiben. Diese muss allerdings bereits ge&ouml;ffnet sein. Verwenden Sie dazu die Methode <code>to_file()</code> und geben Sie als Parameter das Handle der ge&ouml;ffneten Datei an.</p>\r
+\r
+<pre class="code">\r
+# PHP:\r
+\r
+$handle = fopen(&quot;datei.htm&quot;,&quot;w&quot;);\r
+$tpl-&gt;to_file($handle);\r
+fclose($handle);\r
+\r
+# Perl:\r
+\r
+open(HANDLE,&quot;&gt;datei.htm&quot;);\r
+$tpl-&gt;to_file(\*HANDLE);\r
+close(HANDLE);\r
+\r
+# Python:\r
+\r
+handle = open(&quot;datei.htm&quot;,&quot;w&quot;)\r
+tpl.to_file(handle)\r
+handle.close()\r
+</pre>\r
+\r
+<p><b>Achtung:</b><br />\r
+Mit Version&nbsp;2.5 der Template-Klasse hat sich der komplette Vorgang des Parsens ver&auml;ndert. Falls Sie merken, dass sich dadurch das Ergebnis des endg&uuml;tigen Textes von dem, was Sie gewohnt sind, unterscheidet, k&ouml;nnen Sie wieder auf den alten Parsing-Vorgang umschalten. F&uuml;gen Sie dazu irgendwo <b>vor</b> dem Aufruf von <code>parse()</code> folgende Zeile ein:</p>\r
+\r
+<pre class="code">\r
+# PHP:\r
+\r
+$tpl-&gt;old_parsing = 1;\r
+\r
+# Perl:\r
+\r
+$tpl-&gt;{'old_parsing'} = 1;\r
+\r
+# Python:\r
+\r
+tpl.old_parsing = 1\r
+</pre>\r
+\r
+<p>Durch diese Anweisung aktivieren Sie den alten Parsing-Mechanismus. Wenn Sie zu dieser Ma&szlig;nahme greifen m&uuml;ssen (was ich nat&uuml;rlich nicht hoffe), w&uuml;rde ich mich freuen, wenn Sie mir eine kurze Mail schicken, damit wir uns dieses Problem evtl. gemeinsam mal ansehen k&ouml;nnen.</p>\r
+\r
+<p class="upanddown"><a href="#top">Nach oben</a></p>\r
+\r
+<h2><a name="parsen" id="parsen">Zustand sichern und wiederherstellen</a></h2>\r
+\r
+<p>Falls Sie den Template-Text wieder in den Zustand zur&uuml;ckversetzen m&ouml;chten, den er direkt nach dem Einlesen der Template-Datei hatte, m&uuml;ssen Sie diese nicht wieder neu einlesen. Sie k&ouml;nnen ganz einfach die Methode <code>reset()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;reset()\r
+\r
+# Python:\r
+\r
+tpl.reset()\r
+</pre>\r
+\r
+<p>Umgekehrt k&ouml;nnen Sie den aktuellen Status des Template-Textes auch sichern, um sp&auml;ter diesen Status wiederherstellen zu k&ouml;nnen. Dies geschieht mit der Methode <code>save_state()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;save_state()\r
+\r
+# Python:\r
+\r
+tpl.save_state()\r
+</pre>\r
+\r
+<p>Dadurch k&ouml;nnen Sie diesen Status mit <code>reset()</code> wiederherstellen. Es ist dadurch allerdings nicht mehr m&ouml;glich den Zustand, den der Template-Text direkt nach dem Einlesen hatte, wiederherzustellen.</p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p><a href="index.htm">Zur &Uuml;bersicht</a></p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p style="font-size:8pt">&copy;&nbsp;2002-2011 Patrick Canterino</p>\r
+\r
+<table border="0" cellspacing="0" style="font-size:8pt">\r
+<tr>\r
+<td>Homepage:</td>\r
+<td><a href="http://www.patshaping.de/">http://www.patshaping.de/</a></td>\r
+</tr>\r
+<tr>\r
+<td><a name="bottom" id="bottom">E-Mail:</a></td>\r
+<td><a href="mailto:patrick@patshaping.de">patrick@patshaping.de</a></td>\r
+</tr>\r
+</table>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/doc/style.css b/doc/style.css
new file mode 100644 (file)
index 0000000..b4d460d
--- /dev/null
@@ -0,0 +1,86 @@
+#content, #content ul\r
+{\r
+ list-style-type: none;\r
+ margin-left: 0cm;\r
+}\r
+.upanddown\r
+{\r
+ font-size: 8pt;\r
+ background-color: #E8E8E8;\r
+ padding: 3px;\r
+ margin-left: 0.5cm;\r
+ margin-right: 0.5cm;\r
+ white-space: nowrap;\r
+}\r
+a:link, a:visited, a:active, a:focus\r
+{\r
+ font-weight: normal;\r
+ text-decoration: none;\r
+ color: #0000FF;\r
+}\r
+a:link:hover, a:visited:hover, a:active:hover, a:focus:hover\r
+{\r
+ font-weight: normal;\r
+ text-decoration: underline;\r
+ color: #0000FF;\r
+}\r
+body\r
+{\r
+ font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;\r
+ font-size: 10pt;\r
+ color: #000000;\r
+ background-color: #FFFFFF;\r
+}\r
+code\r
+{\r
+ font-family: 'Courier New', Courier, monospace;\r
+ font-size: 10pt;\r
+ color: #0000B0;\r
+}\r
+h1\r
+{\r
+ font-size: 18pt;\r
+ font-weight: bold;\r
+}\r
+h2\r
+{\r
+ font-size: 13pt;\r
+ font-weight: bold;\r
+ padding-left: 0.2cm;\r
+ padding-right: 0.2cm;\r
+}\r
+li\r
+{\r
+ margin-top: 3px;\r
+}\r
+ol, ul\r
+{\r
+ padding-left: 0.5cm;\r
+ padding-right: 0.5cm;\r
+ margin-left: 1cm;\r
+}\r
+p\r
+{\r
+ padding-left: 0.5cm;\r
+ padding-right: 0.5cm;\r
+}\r
+pre.code\r
+{\r
+ font-family: 'Courier New', Courier, monospace;\r
+ font-size: 10pt;\r
+ color: #0000B0;\r
+ background-color: #FFEEEE;\r
+ margin-left: 0.5cm;\r
+ margin-right: 0.5cm;\r
+ padding: 0.3cm;\r
+}\r
+table\r
+{\r
+ font-size: 10pt;\r
+ margin-left: 0.5cm;\r
+ margin-right: 0.5cm;\r
+}\r
+td\r
+{\r
+ vertical-align: top;\r
+}
\ No newline at end of file
diff --git a/doc/vonhand.htm b/doc/vonhand.htm
new file mode 100644 (file)
index 0000000..67242a9
--- /dev/null
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+\r
+<html xmlns="http://www.w3.org/1999/xhtml">\r
+<head>\r
+<title>Templatates &quot;von Hand&quot; parsen</title>\r
+<meta name="author" content="Patrick Canterino" />\r
+<link rel="stylesheet" href="style.css" type="text/css" />\r
+<base target="_self" />\r
+</head>\r
+<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#0000FF" alink="#0000FF">\r
+\r
+<h1><a name="top" id="top">Templatates &quot;von Hand&quot; parsen</a></h1>\r
+\r
+<p>Neben den herk&ouml;mmlichen Methoden, die die Template-Dateien weitgehend automatisch verarbeiten, haben Sie auch die M&ouml;glichkeit, die Template-Dateien sozusagen &quot;von Hand&quot; zu verarbeiten. Sie haben hierbei genaue Kontrolle &uuml;ber die zu ersetzenden Variablen, die zu verarbeitenden <code>{IF}</code>-Bl&ouml;cke usw.</p>\r
+\r
+<p>Um eine <a href="aufbau.htm#variablen">Variable</a> sofort durch Text zu ersetzen, k&ouml;nnen Sie die Methode <code>fillin()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;fillin(Variablenname,Wert);\r
+\r
+# Python:\r
+\r
+tpl.fillin(Variablenname,Wert)\r
+</pre>\r
+\r
+<p>Sie haben weiterhin die M&ouml;glichkeit, mit Hilfe der Methode <code>fillin_array()</code> eine Variable durch ein Array zu ersetzen (unter Perl k&ouml;nnen Sie eine Array-Referenz verwenden). Dabei werden die einzelnen Array-Elemente zusammengef&uuml;gt. Die Syntax dieser Methode entspricht der von <code>fillin()</code>, Sie k&ouml;nnen als optionalen dritten Parameter die Zeichenkette angeben, mit der die Array-Elemente verbunden werden sollen (die Vorgabe ist eine leere Zeichenkette, also <code>''</code>).</p>\r
+\r
+<p>Wenn Sie die Variablen mit <code>set_var()</code> definiert haben und diese im Template-Text nun nacheinander durch die definierten Werte ersetzen m&ouml;chten, so wie es ein Aufruf von <code>parse()</code> tut, k&ouml;nnen Sie die Methode <code>replace_vars()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;replace_vars();\r
+\r
+# Python:\r
+\r
+tpl.replace_vars()\r
+</pre>\r
+\r
+<p>Optional k&ouml;nnen Sie hier noch ein Array als Parameter mitgeben, das die Variablen, die ersetzt werden sollen, einschr&auml;nkt. Wird ein Array mitgegeben, werden nur die Variablen ersetzt, deren Namen sich in diesem Array befinden.</p>\r
+\r
+<p>Genauso k&ouml;nnen Sie auch mit den <a href="aufbau.htm#bedingt"><code>{IF}</code>-Bl&ouml;cken</a> verfahren:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse_if_block(Name,Bedingung);\r
+\r
+# Python:\r
+\r
+tpl.parse_if_block(Name,Bedingung)\r
+</pre>\r
+\r
+<p>Verneinte Bl&ouml;cke werden automatisch verarbeitet. Wenn Sie den optionalen dritten Parameter von <code>parse_if_block()</code> auf <i>true</i> setzen, werden diese Bl&ouml;cke nicht verarbeitet.</p>\r
+\r
+<p>Falls Sie die Verarbeitung einer <a href="aufbau.htm#schleifen">Schleife</a> von Hand ansto&szlig;en m&ouml;chten, k&ouml;nnen Sie die Methode <code>parse_loop()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse_loop(Name der Schleife);\r
+\r
+# Python:\r
+\r
+tpl.parse_loop(Name der Schleife)\r
+</pre>\r
+\r
+<p>Die Daten f&uuml;r die Schleifen werden allerdings weiterhin durch <a href="parsen.htm#schleifen-setzen"><code>add_loop_data()</code> und <code>set_loop_data()</code></a> eingef&uuml;gt.</p>\r
+\r
+<p>Um die mit Hilfe von <a href="aufbau.htm#definitionen"><code>{DEFINE}</code>-Anweisungen</a> definierten Variablen auszulesen, k&ouml;nnen Sie die Methode <code>get_defined_vars()</code> verwenden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;get_defined_vars();\r
+\r
+# Python:\r
+\r
+tpl.get_defined_vars()\r
+</pre>\r
+\r
+<p>Dadurch werden die Variablen ausgelesen und in den Objekt-Eigenschaften abgespeichert, so als w&auml;ren sie mit <a href="parsen.htm#variablen-setzen"><code>set_var()</code></a> gesetzt worden. Sie K&ouml;nnen Sie dann mit <code>get_var()</code> wieder auslesen. Die Namen aller Variablen, die in der Template-Datei definiert wurden, befinden sich in den Objekt-Eigenscaften im Array mit dem Namen <code>defined_vars</code> (unter Perl handelt es sich um eine Array-Referenz).</p>\r
+\r
+<p><a href="aufbau.htm#includes"><code>{INCLUDE}</code>-Anweisungen</a> k&ouml;nnen, wie bereits erw&auml;hnt, von <code>parse_includes()</code> verarbeitet werden:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse_includes();\r
+\r
+# Python:\r
+\r
+tpl.parse_includes()\r
+</pre>\r
+\r
+<p>Falls Sie die <a href="aufbau.htm#trim"><code>{TRIM}</code>-Anweisungen</a> manuell verarbeiten lassen m&ouml;chten, steht die Methode <code>parse_trim_blocks</code> zur Verf&uuml;gung:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse_trim_blocks();\r
+\r
+# Python:\r
+\r
+tpl.parse_trim_blocks()\r
+</pre>\r
+\r
+<p>Zus&auml;tzlich zu den normalen <code>{IF}</code>-Bl&ouml;cken steht noch eine &auml;ltere Variante zur Verf&uuml;gung. Diese soll eigentlich nicht mehr verwendet werden, da sie nicht soviele M&ouml;glichkeiten bietet und gerade bei HTML-Dokumenten f&uuml;r Un&uuml;bersicht sorgen kann. Der Vollst&auml;ndigkeit halber f&uuml;hre ich sie aber trotzdem hier auf, zumal sie vielleicht n&uuml;tzlich sein kann, sollte der Parser für die normalen <code>{IF}</code>-Bl&ouml;cke einen Bug aufweisen, die bei dieser alten Methode nicht auftritt.</p>\r
+\r
+<p>Konkret werden bei dieser Variante bedingte Bl&ouml;cke von HTML-Tags mit frei w&auml;hlbaren Namen (eigentlich wohl eher XML, die ganzen Freaks werden mich jetzt ganz sicher verpr&uuml;geln...) umschlossen -&nbsp;die Variante tr&auml;gt deswegen auch den Namen &quot;CondTag&quot;.<br />\r
+Das kann zum Beispiel so aussehen:</p>\r
+\r
+<pre class="code">\r
+&lt;Name&gt;Das ist ein bedingter Abschnitt!&lt;/Name&gt;\r
+</pre>\r
+\r
+<p>Auch hier ist es m&ouml;glich, mehrere Bl&ouml;cke ineinander zu verschachteln. Allerdings darf ein CondTag-Block nicht einen weiteren CondTag-Block mit dem selben Namen enthalten, weil die Funktion ansonsten ins Schleudern ger&auml;t.</p>\r
+\r
+<p>Verarbeitet werden die Bl&ouml;cke von der Funktion <code>parse_condtag()</code>:</p>\r
+\r
+<pre class="code">\r
+# PHP / Perl:\r
+\r
+$tpl-&gt;parse_condtag(Name,Bedingung);\r
+\r
+# Python:\r
+\r
+tpl.parse_condtag(Name,Bedingung)\r
+</pre>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p><a href="index.htm">Zur &Uuml;bersicht</a></p>\r
+\r
+<hr width="80%" noshade="noshade" />\r
+\r
+<p style="font-size:8pt">&copy;&nbsp;2002-2011 Patrick Canterino</p>\r
+\r
+<table border="0" cellspacing="0" style="font-size:8pt">\r
+<tr>\r
+<td>Homepage:</td>\r
+<td><a href="http://www.patshaping.de/">http://www.patshaping.de/</a></td>\r
+</tr>\r
+<tr>\r
+<td><a name="bottom" id="bottom">E-Mail:</a></td>\r
+<td><a href="mailto:patrick@patshaping.de">patrick@patshaping.de</a></td>\r
+</tr>\r
+</table>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/license.txt b/license.txt
new file mode 100644 (file)
index 0000000..a4810c5
--- /dev/null
@@ -0,0 +1,201 @@
+               The Artistic License 2.0\r
+\r
+        Copyright (c) 2000-2006, The Perl Foundation.\r
+\r
+     Everyone is permitted to copy and distribute verbatim copies\r
+      of this license document, but changing it is not allowed.\r
+\r
+Preamble\r
+\r
+This license establishes the terms under which a given free software\r
+Package may be copied, modified, distributed, and/or redistributed.\r
+The intent is that the Copyright Holder maintains some artistic\r
+control over the development of that Package while still keeping the\r
+Package available as open source and free software.\r
+\r
+You are always permitted to make arrangements wholly outside of this\r
+license directly with the Copyright Holder of a given Package.  If the\r
+terms of this license do not permit the full use that you propose to\r
+make of the Package, you should contact the Copyright Holder and seek\r
+a different licensing arrangement.\r
+\r
+Definitions\r
+\r
+    "Copyright Holder" means the individual(s) or organization(s)\r
+    named in the copyright notice for the entire Package.\r
+\r
+    "Contributor" means any party that has contributed code or other\r
+    material to the Package, in accordance with the Copyright Holder's\r
+    procedures.\r
+\r
+    "You" and "your" means any person who would like to copy,\r
+    distribute, or modify the Package.\r
+\r
+    "Package" means the collection of files distributed by the\r
+    Copyright Holder, and derivatives of that collection and/or of\r
+    those files. A given Package may consist of either the Standard\r
+    Version, or a Modified Version.\r
+\r
+    "Distribute" means providing a copy of the Package or making it\r
+    accessible to anyone else, or in the case of a company or\r
+    organization, to others outside of your company or organization.\r
+\r
+    "Distributor Fee" means any fee that you charge for Distributing\r
+    this Package or providing support for this Package to another\r
+    party.  It does not mean licensing fees.\r
+\r
+    "Standard Version" refers to the Package if it has not been\r
+    modified, or has been modified only in ways explicitly requested\r
+    by the Copyright Holder.\r
+\r
+    "Modified Version" means the Package, if it has been changed, and\r
+    such changes were not explicitly requested by the Copyright\r
+    Holder.\r
+\r
+    "Original License" means this Artistic License as Distributed with\r
+    the Standard Version of the Package, in its current version or as\r
+    it may be modified by The Perl Foundation in the future.\r
+\r
+    "Source" form means the source code, documentation source, and\r
+    configuration files for the Package.\r
+\r
+    "Compiled" form means the compiled bytecode, object code, binary,\r
+    or any other form resulting from mechanical transformation or\r
+    translation of the Source form.\r
+\r
+\r
+Permission for Use and Modification Without Distribution\r
+\r
+(1)  You are permitted to use the Standard Version and create and use\r
+Modified Versions for any purpose without restriction, provided that\r
+you do not Distribute the Modified Version.\r
+\r
+\r
+Permissions for Redistribution of the Standard Version\r
+\r
+(2)  You may Distribute verbatim copies of the Source form of the\r
+Standard Version of this Package in any medium without restriction,\r
+either gratis or for a Distributor Fee, provided that you duplicate\r
+all of the original copyright notices and associated disclaimers.  At\r
+your discretion, such verbatim copies may or may not include a\r
+Compiled form of the Package.\r
+\r
+(3)  You may apply any bug fixes, portability changes, and other\r
+modifications made available from the Copyright Holder.  The resulting\r
+Package will still be considered the Standard Version, and as such\r
+will be subject to the Original License.\r
+\r
+\r
+Distribution of Modified Versions of the Package as Source\r
+\r
+(4)  You may Distribute your Modified Version as Source (either gratis\r
+or for a Distributor Fee, and with or without a Compiled form of the\r
+Modified Version) provided that you clearly document how it differs\r
+from the Standard Version, including, but not limited to, documenting\r
+any non-standard features, executables, or modules, and provided that\r
+you do at least ONE of the following:\r
+\r
+    (a)  make the Modified Version available to the Copyright Holder\r
+    of the Standard Version, under the Original License, so that the\r
+    Copyright Holder may include your modifications in the Standard\r
+    Version.\r
+\r
+    (b)  ensure that installation of your Modified Version does not\r
+    prevent the user installing or running the Standard Version. In\r
+    addition, the Modified Version must bear a name that is different\r
+    from the name of the Standard Version.\r
+\r
+    (c)  allow anyone who receives a copy of the Modified Version to\r
+    make the Source form of the Modified Version available to others\r
+    under\r
+\r
+    (i)  the Original License or\r
+\r
+    (ii)  a license that permits the licensee to freely copy,\r
+    modify and redistribute the Modified Version using the same\r
+    licensing terms that apply to the copy that the licensee\r
+    received, and requires that the Source form of the Modified\r
+    Version, and of any works derived from it, be made freely\r
+    available in that license fees are prohibited but Distributor\r
+    Fees are allowed.\r
+\r
+\r
+Distribution of Compiled Forms of the Standard Version\r
+or Modified Versions without the Source\r
+\r
+(5)  You may Distribute Compiled forms of the Standard Version without\r
+the Source, provided that you include complete instructions on how to\r
+get the Source of the Standard Version.  Such instructions must be\r
+valid at the time of your distribution.  If these instructions, at any\r
+time while you are carrying out such distribution, become invalid, you\r
+must provide new instructions on demand or cease further distribution.\r
+If you provide valid instructions or cease distribution within thirty\r
+days after you become aware that the instructions are invalid, then\r
+you do not forfeit any of your rights under this license.\r
+\r
+(6)  You may Distribute a Modified Version in Compiled form without\r
+the Source, provided that you comply with Section 4 with respect to\r
+the Source of the Modified Version.\r
+\r
+\r
+Aggregating or Linking the Package\r
+\r
+(7)  You may aggregate the Package (either the Standard Version or\r
+Modified Version) with other packages and Distribute the resulting\r
+aggregation provided that you do not charge a licensing fee for the\r
+Package.  Distributor Fees are permitted, and licensing fees for other\r
+components in the aggregation are permitted. The terms of this license\r
+apply to the use and Distribution of the Standard or Modified Versions\r
+as included in the aggregation.\r
+\r
+(8) You are permitted to link Modified and Standard Versions with\r
+other works, to embed the Package in a larger work of your own, or to\r
+build stand-alone binary or bytecode versions of applications that\r
+include the Package, and Distribute the result without restriction,\r
+provided the result does not expose a direct interface to the Package.\r
+\r
+\r
+Items That are Not Considered Part of a Modified Version\r
+\r
+(9) Works (including, but not limited to, modules and scripts) that\r
+merely extend or make use of the Package, do not, by themselves, cause\r
+the Package to be a Modified Version.  In addition, such works are not\r
+considered parts of the Package itself, and are not subject to the\r
+terms of this license.\r
+\r
+\r
+General Provisions\r
+\r
+(10)  Any use, modification, and distribution of the Standard or\r
+Modified Versions is governed by this Artistic License. By using,\r
+modifying or distributing the Package, you accept this license. Do not\r
+use, modify, or distribute the Package, if you do not accept this\r
+license.\r
+\r
+(11)  If your Modified Version has been derived from a Modified\r
+Version made by someone other than you, you are nevertheless required\r
+to ensure that your Modified Version complies with the requirements of\r
+this license.\r
+\r
+(12)  This license does not grant you the right to use any trademark,\r
+service mark, tradename, or logo of the Copyright Holder.\r
+\r
+(13)  This license includes the non-exclusive, worldwide,\r
+free-of-charge patent license to make, have made, use, offer to sell,\r
+sell, import and otherwise transfer the Package with respect to any\r
+patent claims licensable by the Copyright Holder that are necessarily\r
+infringed by the Package. If you institute patent litigation\r
+(including a cross-claim or counterclaim) against any party alleging\r
+that the Package constitutes direct or contributory patent\r
+infringement, then this Artistic License to you shall terminate on the\r
+date that such litigation is filed.\r
+\r
+(14)  Disclaimer of Warranty:\r
+THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS\r
+IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED\r
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\r
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL\r
+LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL\r
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\r
+DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF\r
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
diff --git a/readme.txt b/readme.txt
new file mode 100644 (file)
index 0000000..04f991b
--- /dev/null
@@ -0,0 +1,2 @@
+Die Dokumentation für die Template-Klasse finden Sie unter\r
+doc/index.htm
\ No newline at end of file
diff --git a/template.py b/template.py
new file mode 100644 (file)
index 0000000..05c2345
--- /dev/null
@@ -0,0 +1,840 @@
+\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
+import os.path\r
+import sys\r
+\r
+class Template:\r
+\r
+    # __init__()\r
+    #\r
+    # Konstruktor\r
+    #\r
+    # Parameter: -keine-\r
+    #\r
+    # Rueckgabe: -nichts-\r
+\r
+    def __init__(self):\r
+        self.file         = ''\r
+        self.template     = ''\r
+        self.original     = ''\r
+        self.old_parsing  = 0\r
+        self.vars         = {}\r
+        self.defined_vars = []\r
+        self.loop_vars    = {}\r
+\r
+    # get_template()\r
+    #\r
+    # Kompletten Vorlagentext zurueckgeben\r
+    #\r
+    # Parameter: -keine-\r
+    #\r
+    # Rueckgabe: Kompletter Vorlagentext (String)\r
+\r
+    def get_template(self):\r
+        return str(self.template)\r
+\r
+    # set_template()\r
+    #\r
+    # Kompletten Vorlagentext aendern\r
+    #\r
+    # Parameter: Vorlagentext\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    def set_template(self,template):\r
+        self.template = str(template)\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
+    def add_text(self,text):\r
+        self.set_template(self.get_template()+str(text))\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
+    def read_file(self,file,not_include=0):\r
+        self.file = file\r
+\r
+        fp = open(file,'r')\r
+        content = fp.read()\r
+        fp.close()\r
+\r
+        self.add_text(content)\r
+        self.save_state()\r
+\r
+        if not not_include: self.parse_includes()\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
+    def set_var(self,var,content):\r
+        self.vars[var] = content\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
+    def get_var(self,var=None):\r
+        if var is not None:\r
+            if self.vars.has_key(var):\r
+                return self.vars[var]\r
+            else:\r
+                return None\r
+        else:\r
+            return self.vars.keys()\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
+    def set_vars(self,vars):\r
+        self.vars = vars\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
+    def add_vars(self,vars):\r
+        self.vars.update(vars)\r
+\r
+    # set_loop_data()\r
+    #\r
+    # Daten fuer eine Schleife setzen\r
+    #\r
+    # Parameter: 1. Name der Schleife\r
+    #            2. Array mit den Dictionaries mit den Variablen fuer\r
+    #               die Schleifendurchgaenge\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    def set_loop_data(self,loop,data):\r
+        self.loop_vars[loop] = data\r
+\r
+    # add_loop_data()\r
+    #\r
+    # Daten fuer einen Schleifendurchgang hinzufuegen\r
+    #\r
+    # Parameter: 1. Name der Schleife\r
+    #            2. Dictionary mit den Variablen fuer den\r
+    #               Schleifendurchgang\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    def add_loop_data(self,loop,data):\r
+        if self.loop_vars.has_key(loop) and type(self.loop_vars[loop]) is list:\r
+            self.loop_vars[loop].append(data)\r
+        else:\r
+            self.loop_vars[loop] = [data]\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
+    def parse(self):\r
+        if self.old_parsing: return self.parse_old()\r
+\r
+        # Zuerst die Schleifen parsen\r
+\r
+        if self.loop_vars and self.loop_vars.keys():\r
+            loops = self.loop_vars.keys()\r
+\r
+            for loop in loops:\r
+                self.parse_loop(loop)\r
+\r
+        # In Template-Datei definierte Variablen auslesen\r
+\r
+        self.get_defined_vars()\r
+\r
+        # Variablen ersetzen\r
+\r
+        vars = self.get_var()\r
+\r
+        if vars is not None and type(vars) is list:\r
+            self.parse_if_blocks()\r
+            self.replace_vars()\r
+\r
+        # {TRIM}-Bloecke entfernen\r
+\r
+        self.parse_trim_blocks()\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
+    def parse_old(self):\r
+        # Zuerst die Schleifen parsen\r
+\r
+        if self.loop_vars and self.loop_vars.keys():\r
+            loops = self.loop_vars.keys()\r
+\r
+            for loop in loops:\r
+                self.parse_loop(loop)\r
+\r
+        # Normale Variablen durchgehen\r
+\r
+        if self.get_var():\r
+            vars = self.get_var()\r
+\r
+            for var in vars:\r
+                val = self.get_var(var)\r
+\r
+                self.parse_if_block(var,val)\r
+\r
+                if type(val) is list:\r
+                    self.fillin_array(var,val)\r
+                else:\r
+                    self.fillin(var,val)\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
+        for var in self.defined_vars:\r
+            val = self.get_var(var)\r
+\r
+            self.parse_if_block(var,val)\r
+            self.fillin(var,val)\r
+\r
+        # {TRIM}-Bloecke entfernen\r
+\r
+        self.parse_trim_blocks()\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
+    def fillin(self,var,text):\r
+        if text is None: text = ''\r
+\r
+        template = self.get_template();\r
+        template = template.replace('{'+str(var)+'}',str(text));\r
+\r
+        self.set_template(template);\r
+\r
+    # fillin_array()\r
+    #\r
+    # Variable durch Array ersetzen\r
+    #\r
+    # Parameter: 1. Variable zum Ersetzen\r
+    #            2. Array, durch das 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
+    def fillin_array(self,var,array,glue=''):\r
+        self.fillin(var,str(glue).join(array))\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
+    def replace_vars(self,valid=None):\r
+        template = self.get_template()\r
+\r
+        if valid is None:\r
+            valid_vars = self.get_var()\r
+        else:\r
+            valid_vars = valid\r
+\r
+        x = 0\r
+\r
+        while x < len(template):\r
+            if template[x] == '{':\r
+                for var in valid_vars:\r
+                    # Pruefen, ob hier eine gueltige Variable beginnt\r
+\r
+                    if template[x+1:x+len(var)+2] == var + '}':\r
+                        if type(self.get_var(var)) is list:\r
+                            content = ''.join(self.get_var(var))\r
+                        else:\r
+                            # Muss es nochmal zum String machen\r
+                            # Hilft gegen den "ordinal not in range(128)"-Fehler\r
+                            # Habe aber keine Ahnung, welche neuen Probleme das verursachen koennte\r
+                            # Bin gespannt...\r
+                            content = str(self.get_var(var))\r
+\r
+                        if content is None: content = ''\r
+\r
+                        # Daten vor und nach der Variable\r
+\r
+                        pre  = template[0:x]\r
+                        post = template[len(pre)+2+len(var):]\r
+\r
+                        # Alles neu zusammensetzen\r
+\r
+                        template = pre + content + post\r
+\r
+                        # Zaehler aendern\r
+\r
+                        x = len(pre + content) - 1\r
+\r
+            x += 1\r
+\r
+        self.set_template(template)\r
+\r
+    # to_file()\r
+    #\r
+    # Template in Datei schreiben\r
+    #\r
+    # Parameter: Datei-Handle\r
+    #\r
+    # Rueckgabe: Status-Code (Boolean)\r
+\r
+    def to_file(self,handle):\r
+        return handle.write(self.get_template())\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
+    def reset(self):\r
+        self.template = self.original\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
+    def save_state(self):\r
+        self.original = self.template\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
+    def parse_loop(self,name):\r
+        template = self.get_template()\r
+        if template.find('{LOOP '+name+'}') == -1: return\r
+\r
+        offset     = 0\r
+        name_len = len(name)\r
+\r
+        while template.find('{LOOP '+name+'}',offset) != -1:\r
+            begin = template.find('{LOOP '+name+'}',offset)\r
+\r
+            if template.find('{ENDLOOP}',begin+6+name_len) != -1:\r
+                end = template.find('{ENDLOOP}',begin+6+name_len)\r
+\r
+                block    = template[begin:end+9]\r
+                content = block[name_len+7:-9]\r
+\r
+                parsed_block = ''\r
+\r
+                x = 0\r
+\r
+                while x < len(self.loop_vars[name]):\r
+                    loop_data = self.loop_vars[name][x]\r
+                    loop_vars = loop_data.keys()\r
+\r
+                    ctpl = Template()\r
+                    ctpl.set_template(content)\r
+\r
+                    for loop_var in loop_vars:\r
+                        ctpl.set_var(name+'.'+loop_var,loop_data[loop_var])\r
+\r
+                    if self.old_parsing:\r
+                        ctpl.parse_old()\r
+                    else:\r
+                        ctpl.parse()\r
+\r
+                    parsed_block += ctpl.get_template()\r
+\r
+                    del(ctpl)\r
+                    x += 1\r
+\r
+                template = template.replace(block,parsed_block)\r
+                offset   = begin+len(parsed_block)\r
+\r
+            else:\r
+                break\r
+\r
+        self.set_template(template)\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
+    def get_defined_vars(self):\r
+        template = self.get_template()\r
+        if template.find('{DEFINE ') == -1: return\r
+\r
+        offset = 0\r
+\r
+        while template.find('{DEFINE ',offset) != -1:\r
+            begin  = template.find('{DEFINE ',offset)+8\r
+            offset = begin\r
+\r
+            name    = ''\r
+            content = ''\r
+\r
+            var_open     = 0\r
+            name_found   = 0\r
+            define_block = 0\r
+\r
+            x = begin\r
+\r
+            while x < len(template):\r
+                if template[x] == '\012' or template[x] == '\015':\r
+                    # Wenn in einem {DEFINE}-Block ein Zeilenumbruch gefunden wird,\r
+                    # brechen wir mit dem Parsen des Blockes ab\r
+\r
+                    break\r
+\r
+                if var_open == 1:\r
+                    if template[x] == '"':\r
+                        # Der Inhalt der Variable ist hier zu Ende\r
+\r
+                        var_open = 0\r
+\r
+                        if template[x+1] == '}':\r
+                            # Hier ist der Block zu Ende\r
+\r
+                            if self.get_var(name) is None:\r
+                                # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+                                self.set_var(name,content)\r
+                                self.defined_vars.append(name)\r
+\r
+                            # {DEFINE}-Block entfernen\r
+\r
+                            pre  = template[0:begin-8]\r
+                            post = template[x+2:]\r
+\r
+                            template = pre+post\r
+\r
+                            # Fertig!\r
+\r
+                            offset = len(pre)\r
+                            break\r
+\r
+                    elif template[x] == '\\':\r
+                        # Ein Backslash wurde gefunden, er dient zum Escapen von Zeichen\r
+\r
+                        if template[x+1] == 'n':\r
+                            # "\n" in Zeilenumbrueche umwandeln\r
+\r
+                            content += "\n"\r
+                        else:\r
+                            content += template[x+1]\r
+\r
+                        x += 1\r
+\r
+                    else:\r
+                        content += template[x]\r
+\r
+                else:\r
+                    if name_found == 1:\r
+                        if var_open == 0:\r
+                            if template[x] == '"':\r
+                                var_open = 1\r
+                            else:\r
+                                break\r
+\r
+                    else:\r
+                        # Variablennamen auslesen\r
+\r
+                        if template[x] == '}' and name != '':\r
+                            # Wir haben einen {DEFINE}-Block\r
+\r
+                            name_found      = 1\r
+                            define_found = 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 template.find('{ENDDEFINE}',x) != -1:\r
+                                end = template.find('{ENDDEFINE}',x)\r
+                                x += 1\r
+\r
+                                content = template[x:end]\r
+\r
+                                if self.get_var(name) is None:\r
+                                    # Die Variable wird nur gesetzt, wenn sie nicht bereits gesetzt ist\r
+\r
+                                    self.set_var(name,content)\r
+                                    self.defined_vars.append(name)\r
+\r
+                                pre  = template[0:begin-8]\r
+                                post = template[end+11:]\r
+\r
+                                template = pre + post\r
+\r
+                                # Fertig!\r
+\r
+                                offset = len(pre)\r
+                                break\r
+\r
+                            else:\r
+                                break\r
+\r
+                        elif template[x] != ' ':\r
+                            name += template[x]\r
+\r
+                        elif template[x] != '':\r
+                            name_found = 1\r
+\r
+                        else:\r
+                            break\r
+\r
+                x += 1\r
+\r
+        self.set_template(template)\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
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    def parse_if_block(self,name,state,no_negate=0):\r
+        name     = str(name)\r
+        template = self.get_template()\r
+\r
+        count = 0;\r
+\r
+        while template.find('{IF '+name+'}') >= 0:\r
+            count += 1\r
+\r
+            start    = template.find('{IF '+name+'}')\r
+            tpl_tmp  = template[start:]\r
+            splitted = tpl_tmp.split('{ENDIF}')\r
+\r
+            block = '' # Kompletter bedingter Block\r
+            ifs      = 0  # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt)\r
+\r
+            # {IF}\r
+\r
+            x = 0\r
+\r
+            while x < len(splitted):\r
+                # Verschachtelungsfehler abfangen\r
+                if x == len(splitted)-1: raise TplClassIFNestingError(self.file,name,count)\r
+\r
+                ifs += splitted[x].count('{IF ') # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen\r
+                ifs -= 1                         # Zaehler um 1 erniedrigen\r
+                block += splitted[x]+'{ENDIF}'     # Daten zum Block hinzufuegen\r
+\r
+                x += 1\r
+\r
+                if ifs == 0:\r
+                    # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-))\r
+                    break\r
+\r
+            if_block = block[len(name)+5:-7] # Alles zwischen {IF} und {ENDIF}\r
+\r
+            # {ELSE}\r
+\r
+            else_block = '' # Alles ab {ELSE}\r
+            ifs        = 0    # IF-Zaehler\r
+\r
+            splitted = if_block.split('{ELSE}');\r
+\r
+            x = 0\r
+\r
+            while x < len(splitted):\r
+                ifs += splitted[x].count('{IF ')    # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen\r
+                ifs -= splitted[x].count('{ENDIF}') # Vom Zaehler jedes Vorkommen von ENDIF abziehen\r
+\r
+                x += 1\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
+                    y = x\r
+\r
+                    while y < len(splitted):\r
+                        else_block += '{ELSE}'+splitted[y]\r
+                        y += 1\r
+\r
+                    if else_block:\r
+                        if_block   = if_block[0:len(if_block)-len(else_block)]\r
+                        else_block = else_block[6:]\r
+\r
+                    break\r
+\r
+            if state:\r
+                replacement = if_block\r
+            else:\r
+                replacement = else_block\r
+\r
+            template = template.replace(block,replacement)\r
+\r
+        self.set_template(template)\r
+\r
+        # Evtl. verneinte Form parsen\r
+\r
+        if not no_negate:\r
+            self.parse_if_block('!'+name,not state,1)\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
+    def parse_if_blocks(self,valid=None):\r
+        if valid is None:\r
+            valid_vars = self.get_var()\r
+        else:\r
+            valid_vars = valid\r
+\r
+        for valid_var in valid_vars:\r
+            self.parse_if_block(valid_var,self.get_var(valid_var))\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
+    def parse_trim_blocks(self):\r
+        template = self.get_template()\r
+        if template.find('{TRIM}') == -1: return\r
+\r
+        offset = 0\r
+\r
+        while template.find('{TRIM}',offset) >= 0:\r
+            begin = template.find('{TRIM}',offset)\r
+\r
+            if template.find('{ENDTRIM}',begin+6) >= 0:\r
+                end = template.find('{ENDTRIM}',begin+6)\r
+\r
+                block    = template[begin:end+9]\r
+                content  = block[6:-9]\r
+\r
+                trimmed  = content.strip()\r
+\r
+                template = template.replace(block,trimmed)\r
+\r
+                offset   = begin+len(trimmed)\r
+            else:\r
+                break\r
+\r
+        self.set_template(template)\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
+    def parse_condtag(self,condtag,state):\r
+        condtag  = str(condtag)\r
+        template = self.get_template()\r
+\r
+        while template.find('<'+condtag+'>') >= 0:\r
+            start   = template.find('<'+condtag+'>')                 # Beginn des Blocks\r
+            end     = template.find('</'+condtag+'>')+len(condtag)+3 # Ende des Blocks\r
+\r
+            extract = template[start:end]                            # Kompletten Bedingungsblock extrahieren...\r
+\r
+            if state:\r
+                replacement = extract[len(condtag)+2:0-len(condtag)-3]\r
+            else:\r
+                replacement = ''\r
+\r
+            template = template.replace(extract,replacement)         # Block durch neue Daten ersetzen\r
+\r
+        self.set_template(template)\r
+\r
+    # parse_includes()\r
+    #\r
+    # {INCLUDE}-Anweisungen verarbeiten\r
+    #\r
+    # Parameter: -nichts-\r
+    #\r
+    # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)\r
+\r
+    def parse_includes(self):\r
+        template = self.get_template()\r
+        if template.find('{INCLUDE ') == -1: return\r
+\r
+        offset = 0\r
+\r
+        while template.find('{INCLUDE ',offset) >= 0:\r
+            begin = template.find('{INCLUDE ',offset)\r
+\r
+            start  = begin+9\r
+            offset = start\r
+            long   = 0\r
+\r
+            if template[start] == '"':\r
+                long = 1\r
+                start += 1\r
+\r
+            file = ''\r
+            skip = 0\r
+\r
+            x = start\r
+\r
+            while x < len(template):\r
+                if template[x] == '\012' or template[x] == '\015':\r
+                    skip = 1\r
+                    break\r
+                elif long == 0 and template[x] == ' ':\r
+                    skip = 1\r
+                    break\r
+                elif long == 1 and template[x] == '"':\r
+                    if template[x+1] != '}': skip = 1\r
+                    break\r
+                elif long == 0 and template[x] == '}':\r
+                    break\r
+                else:\r
+                    file += template[x]\r
+\r
+                x += 1\r
+\r
+            if skip == 1: continue\r
+\r
+            if file != '':\r
+                filepath = file\r
+\r
+                if not os.path.isabs(file):\r
+                    dir  = os.path.dirname(self.file)\r
+                    if not dir: dir = '.'\r
+                    filepath = os.path.normpath(dir+'/'+file)\r
+\r
+                if os.path.isfile(filepath):\r
+                    inc = Template()\r
+                    inc.read_file(file)\r
+\r
+                    if long == 1: end = start + len(file) + 2\r
+                    else:         end = start + len(file) + 1\r
+\r
+                    pre  = template[0:begin]\r
+                    post = template[end:]\r
+\r
+                    template = pre+inc.get_template()+post\r
+                    offset   = len(pre)+len(inc.get_template())\r
+\r
+                    del(inc)\r
+\r
+        self.set_template(template)\r
+\r
+# Klasse zum Erzeugen des Fehlers bei falsch verschachtelten\r
+# {IF}-Bloecken\r
+\r
+class TplClassIFNestingError:\r
+\r
+    def __init__(self,file,name,count):\r
+        self.file  = file\r
+        self.name  = name\r
+        self.count = count\r
+\r
+    def __str__(self):\r
+        return 'Nesting error found while parsing IF block "'+self.name+'" nr. '+str(self.count)+' in template file "'+self.file+'"'\r
+\r
+#\r
+### Ende ###
\ No newline at end of file

patrick-canterino.de