]> git.p6c8.net - devedit.git/blob - modules/Template.pm
- The abort() routine from the Output module is now also able to display a link
[devedit.git] / modules / Template.pm
1 package Template;
2
3 #
4 # Template (Version 1.3)
5 #
6 # Klasse zum Parsen von Templates
7 #
8 # Autor: Patrick Canterino <patshaping@gmx.net>
9 # Letzte Aenderung: 11.4.2004
10 #
11
12 use strict;
13
14 use Carp qw(croak);
15
16 # new()
17 #
18 # Konstruktor
19 #
20 # Parameter: -keine-
21 #
22 # Rueckgabe: Template-Objekt
23
24 sub new
25 {
26 my $class = shift;
27 my $self = {template => ''};
28 return bless($self,$class);
29 }
30
31 # get_template()
32 #
33 # Kompletten Vorlagentext zurueckgeben
34 #
35 # Parameter: -keine-
36 #
37 # Rueckgabe: Kompletter Vorlagentext (String)
38
39 sub get_template
40 {
41 return shift->{'template'};
42 }
43
44 # set_template()
45 #
46 # Kompletten Vorlagentext aendern
47 #
48 # Parameter: Vorlagentext
49 #
50 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
51
52 sub set_template($)
53 {
54 # Geht nur so...
55
56 my ($self,$template) = @_;
57 $self->{'template'} = $template;
58 }
59
60 # add_text()
61 #
62 # Vorlagentext ans Template-Objekt anhaengen
63 #
64 # Parameter: Vorlagentext
65 #
66 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
67
68 sub add_text($)
69 {
70 my ($self,$text) = @_;
71 $self->set_template($self->get_template.$text);
72 }
73
74 # read_file()
75 #
76 # Einlesen einer Vorlagendatei und {INCLUDE}-Anweisungen ggf. verarbeiten
77 # (Text wird an bereits vorhandenen Text angehaengt)
78 #
79 # Parameter: 1. Datei zum Einlesen
80 # 2. Status-Code (Boolean):
81 # true => {INCLUDE}-Anweisungen nicht verarbeiten
82 # false => {INCLUDE}-Anweisungen verarbeiten (Standard)
83 #
84 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
85
86 sub read_file($;$)
87 {
88 my ($self,$tfile,$not_include) = @_;
89 local *FILE;
90
91 open(FILE,"<$tfile") or croak "Open $tfile: $!";
92 read(FILE, my $content, -s $tfile);
93 close(FILE) or croak "Closing $tfile: $!";
94
95 $self->add_text($content);
96 $self->parse_includes unless($not_include);
97 }
98
99 # fillin()
100 #
101 # Variablen durch Text ersetzen
102 #
103 # Parameter: 1. Variable zum Ersetzen
104 # 2. Text, durch den die Variable ersetzt werden soll
105 #
106 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
107
108 sub fillin($$)
109 {
110 my ($self,$var,$text) = @_;
111
112 $var = quotemeta($var);
113 $text = "" unless defined $text; # Um Fehler zu vermeiden
114
115 my $template = $self->get_template;
116 $template =~ s/\{$var\}/$text/g;
117
118 $self->set_template($template);
119 }
120
121 # fillin_array()
122 #
123 # Variable durch Array ersetzen
124 #
125 # Parameter: 1. Variable zum Ersetzen
126 # 2. Array-Referenz, durch die die Variable ersetzt werden soll
127 # 3. Zeichenkette, mit der das Array verbunden werden soll
128 # (Standard: "")
129 #
130 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
131
132 sub fillin_array($$;$)
133 {
134 my ($self,$var,$array,$glue) = @_;
135 $glue = "" unless defined $glue;
136
137 $self->fillin($var,join($glue,@$array));
138 }
139
140 # to_file()
141 #
142 # Template in Datei schreiben
143 #
144 # Parameter: Datei-Handle
145 #
146 # Rueckgabe: Status-Code (Boolean)
147
148 sub to_file($)
149 {
150 my ($self,$handle) = @_;
151 return print $handle $self->get_template;
152 }
153
154 # parse_if_block()
155 #
156 # IF-Bloecke verarbeiten
157 #
158 # Parameter: 1. Name des IF-Blocks (das, was nach dem IF steht)
159 # 2. Status-Code (true => Inhalt anzeigen
160 # false => Inhalt nicht anzeigen
161 #
162 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
163
164 sub parse_if_block($$)
165 {
166 my ($self,$name,$state) = @_;
167 my $template = $self->get_template;
168
169 while(index($template,"{IF ".$name."}") >= 0)
170 {
171 # Das alles hier ist nicht wirklich elegant geloest...
172 # ... aber solange es funktioniert... ;-)
173
174 my $start = index($template,"{IF ".$name."}");
175 my $tpl_tmp = substr($template,$start);
176 my @splitted = split(/\{ENDIF\}/,$tpl_tmp);
177
178 my $block = ""; # Kompletter bedingter Block
179 my $ifs = 0; # IF-Zaehler (wird fuer jedes IF erhoeht und fuer jedes ENDIF erniedrigt)
180
181 # {IF}
182
183 for(my $x=0;$x<@splitted;$x++)
184 {
185 $ifs += substr_count($splitted[$x],"{IF"); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen
186 $ifs--; # Zaehler um 1 erniedrigen
187 $block .= $splitted[$x]."{ENDIF}"; # Daten zum Block hinzufuegen
188
189 if($ifs == 0)
190 {
191 # Zaehler wieder 0, also haben wir das Ende des IF-Blocks gefunden :-))
192
193 last;
194 }
195 }
196
197 my $if_block = substr($block,length($name)+5,-7); # Alles zwischen {IF} und {ENDIF}
198
199 # {ELSE}
200
201 my $else_block = ""; # Alles ab {ELSE}
202 $ifs = 0; # IF-Zaehler
203
204 @splitted = split(/\{ELSE\}/,$if_block);
205
206 for(my $x=0;$x<@splitted;$x++)
207 {
208 $ifs += substr_count($splitted[$x],"{IF"); # Zum Zaehler jedes Vorkommen von IF hinzuzaehlen
209 $ifs -= substr_count($splitted[$x],"{ENDIF}"); # Vom Zaehler jedes Vorkommen von ENDIF abziehen
210
211 if($ifs == 0)
212 {
213 # Zaehler 0, also haben wir das Ende des IF-Abschnitts gefunden
214
215 # Aus dem Rest den ELSE-Block zusammenbauen
216
217 for(my $y=$x+1;$y<@splitted;$y++)
218 {
219 $else_block .= "{ELSE}".$splitted[$y];
220 }
221
222 if($else_block)
223 {
224 $if_block = substr($if_block,0,length($if_block)-length($else_block));
225 $else_block = (length($else_block) > 6) ? substr($else_block,6) : ""; # Ansonsten gibt es Fehler
226 }
227
228 last;
229 }
230 }
231
232 my $replacement = ($state) ? $if_block : $else_block;
233
234 my $qmblock = quotemeta($block);
235
236 $template =~ s/$qmblock/$replacement/;
237 }
238
239 $self->set_template($template);
240 }
241
242 # parse_condtag()
243 #
244 # Bedingungstags in einem Vorlagentext verarbeiten
245 #
246 # Parameter: 1. Tagname
247 # 2. Status-Code (true => Tag-Inhalt anzeigen
248 # false => Tag-Inhalt nicht anzeigen
249 #
250 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
251
252 sub parse_condtag($$)
253 {
254 my ($self,$condtag,$state) = @_;
255
256 my $template = $self->get_template;
257
258 while(index($template,"<$condtag>") >= 0)
259 {
260 my $start = index($template,"<$condtag>"); # Beginn des Blocks
261 my $end = index($template,"</$condtag>")+length($condtag)+3; # Ende des Blocks
262
263 my $extract = substr($template,$start,$end-$start); # Kompletten Bedingungsblock extrahieren...
264
265 my $replacement = ($state) ? substr($extract,length($condtag)+2,0-length($condtag)-3) : "";
266
267 $extract = quotemeta($extract);
268
269 $template =~ s/$extract/$replacement/g; # Block durch neue Daten ersetzen
270 }
271 $self->set_template($template);
272 }
273
274 # parse_includes()
275 #
276 # {INCLUDE}-Anweisungen verarbeiten
277 #
278 # Parameter: -nichts-
279 #
280 # Rueckgabe: -nichts- (Template-Objekt wird modifiziert)
281
282 sub parse_includes
283 {
284 my $self = shift;
285 my $template = $self->get_template;
286
287 while($template =~ /(\{INCLUDE (\S+?)\})/)
288 {
289 my ($directive,$file) = ($1,$2);
290 my $qm_directive = quotemeta($directive);
291 my $replacement = "";
292
293 if(-f $file)
294 {
295 local *FILE;
296
297 open(FILE,"<$file") or croak "Open $file: $!";
298 read(FILE, $replacement, -s $file);
299 close(FILE) or croak "Closing $file: $!";
300 }
301
302 $template =~ s/$qm_directive/$replacement/g;
303 }
304
305 $self->set_template($template);
306 }
307
308 # ==================
309 # Private Funktion
310 # ==================
311
312 # substr_count()
313 #
314 # Zaehlt, wie oft ein String in einem String vorkommt
315 # (Emulation der PHP-Funktion substr_count())
316 #
317 # Parameter: 1. Zu durchsuchender String
318 # 2. Zu suchender String
319 #
320 # Rueckgabe: Anzahl der Vorkommnisse (Integer)
321
322 sub substr_count($$)
323 {
324 my ($haystack,$needle) = @_;
325 my $qmneedle = quotemeta($needle);
326
327 my $count = 0;
328
329 $count++ while($haystack =~ /$qmneedle/g);
330
331 return $count;
332 }
333
334 # ==================
335 # Alias-Funktionen
336 # ==================
337
338 sub addtext($)
339 {
340 shift->add_text(shift);
341 }
342
343 sub as_string
344 {
345 return shift->get_template;
346 }
347
348 sub condtag($$)
349 {
350 shift->parse_condtag(@_);
351 }
352
353 sub readin($)
354 {
355 shift->read_file(shift);
356 }
357
358 # it's true, baby ;-)
359
360 1;
361
362 #
363 ### Ende ###

patrick-canterino.de