Merge branch 'master' of vc.linet-services.de:public/lx-office-erp
[kivitendo-erp.git] / SL / Template / Simple.pm
1 #====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #====================================================================
8
9 package SL::Template::Simple;
10
11 use strict;
12
13 use Scalar::Util qw(blessed);
14
15 # Parameters:
16 #   1. The template's file name
17 #   2. A reference to the Form object
18 #   3. A reference to the myconfig hash
19 #
20 # Returns:
21 #   A new template object
22 sub new {
23   my $type = shift;
24   my $self = {};
25
26   bless($self, $type);
27   $self->_init(@_);
28
29   return $self;
30 }
31
32 sub _init {
33   my $self = shift;
34
35   $self->{source}    = shift;
36   $self->{form}      = shift;
37   $self->{myconfig}  = shift;
38   $self->{userspath} = shift;
39
40   $self->{error}     = undef;
41   $self->{quot_re}   = '"';
42
43   $self->set_tag_style('<%', '%>');
44 }
45
46 sub set_tag_style {
47   my $self                    = shift;
48   my $tag_start               = shift;
49   my $tag_end                 = shift;
50
51   $self->{tag_start}          = $tag_start;
52   $self->{tag_end}            = $tag_end;
53   $self->{tag_start_qm}       = quotemeta $tag_start;
54   $self->{tag_end_qm}         = quotemeta $tag_end;
55
56   $self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}";
57 }
58
59 sub cleanup {
60   my ($self) = @_;
61 }
62
63 # Parameters:
64 #   1. A typeglob for the file handle. The output will be written
65 #      to this file handle.
66 #
67 # Returns:
68 #   1 on success and undef or 0 if there was an error. In the latter case
69 #   the calling function can retrieve the error message via $obj->get_error()
70 sub parse {
71   my $self = $_[0];
72   local *OUT = $_[1];
73
74   print(OUT "Hallo!\n");
75 }
76
77 sub get_error {
78   my $self = shift;
79
80   return $self->{"error"};
81 }
82
83 sub uses_temp_file {
84   return 0;
85 }
86
87 sub _get_loop_variable {
88   my $self      = shift;
89   my $var       = shift;
90   my $get_array = shift;
91   my @indices   = @_;
92
93   my $form      = $self->{form};
94   my $value;
95
96   if ($var =~ m/\./) {
97     $value = $form;
98     for my $part (split(m/\./, $var)) {
99       if (ref($value) =~ m/^(?:Form|HASH)$/) {
100         $value = $value->{$part};
101       } elsif (blessed($value) && $value->can($part)) {
102         $value = $value->$part;
103       } else {
104         $value = '';
105         last;
106       }
107     }
108   } elsif (($get_array || @indices) && (ref $form->{TEMPLATE_ARRAYS} eq 'HASH') && (ref $form->{TEMPLATE_ARRAYS}->{$var} eq 'ARRAY')) {
109     $value = $form->{TEMPLATE_ARRAYS}->{$var};
110   } else {
111     $value = $form->{$var};
112   }
113
114   for (my $i = 0; $i < scalar(@indices); $i++) {
115     last unless (ref($value) eq "ARRAY");
116     $value = $value->[$indices[$i]];
117   }
118
119   return $value;
120 }
121
122 sub substitute_vars {
123   my ($self, $text, @indices) = @_;
124
125   my $form = $self->{"form"};
126
127   while ($text =~ /$self->{substitute_vars_re}/) {
128     my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
129     my ($var, @options)     = split(/\s+/, $1);
130
131     my $value               = $self->_get_loop_variable($var, 0, @indices);
132     $value                  = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
133
134     substr($text, $tag_pos, $tag_len, $value);
135   }
136
137   return $text;
138 }
139
140 sub _parse_block_if {
141   $main::lxdebug->enter_sub();
142
143   my $self         = shift;
144   my $contents     = shift;
145   my $new_contents = shift;
146   my $pos_if       = shift;
147   my @indices      = @_;
148
149   $$new_contents .= $self->substitute_vars(substr($$contents, 0, $pos_if), @indices);
150   substr($$contents, 0, $pos_if) = "";
151
152   if ($$contents !~ m/^$self->{tag_start_qm}if
153                      \s*
154                      (not\b|\!)?           # $1 -- Eventuelle Negierung
155                      \s+
156                      (\b.+?\b)             # $2 -- Name der zu überprüfenden Variablen
157                      (                     # $3 -- Beginn des optionalen Vergleiches
158                        \s*
159                        ([!=])              # $4 -- Negierung des Vergleiches speichern
160                        ([=~])              # $5 -- Art des Vergleiches speichern
161                        \s*
162                        (                   # $6 -- Gequoteter String oder Bareword
163                          $self->{quot_re}
164                          (.*?)(?<!\\)      # $7 -- Gequoteter String -- direkter Vergleich mit eq bzw. ne oder Patternmatching; Escapete Anführungs als Teil des Strings belassen
165                          $self->{quot_re}
166                        |
167                          (\b.+?\b)         # $8 -- Bareword -- als Index für $form benutzen
168                        )
169                      )?
170                      \s*
171                      $self->{tag_end_qm}
172                     /x) {
173     $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}.";
174     $main::lxdebug->leave_sub();
175     return undef;
176   }
177
178   my $not           = $1;
179   my $var           = $2;
180   my $comparison    = $3; # Optionaler Match um $4..$8
181   my $operator_neg  = $4; # '=' oder '!' oder undef, wenn kein Vergleich erkannt
182   my $operator_type = $5; # '=' oder '~' für Stringvergleich oder Regex
183   my $quoted_word   = $7; # nur gültig, wenn quoted string angegeben (siehe unten); dann "value" aus <%if var == "value" %>
184   my $bareword      = $8; # undef, falls quoted string angegeben wurde; andernfalls "othervar" aus <%if var == othervar %>
185
186   $not = !$not if ($operator_neg && $operator_neg eq '!');
187
188   substr($$contents, 0, length($&)) = "";
189
190   my $block;
191   ($block, $$contents) = $self->find_end($$contents, 0, "$var $comparison", $not);
192   if (!$block) {
193     $self->{"error"} = "Unclosed $self->{tag_start}if$self->{tag_end}." unless ($self->{"error"});
194     $main::lxdebug->leave_sub();
195     return undef;
196   }
197
198   my $value = $self->_get_loop_variable($var, 0, @indices);
199   my $hit   = 0;
200
201   if ($operator_type) {
202     my $compare_to = $bareword ? $self->_get_loop_variable($bareword, 0, @indices) : $quoted_word;
203     if ($operator_type eq '=') {
204       $hit         = ($not && !($value eq $compare_to))     || (!$not && ($value eq $compare_to));
205     } else {
206       $hit         = ($not && !($value =~ m/$compare_to/i)) || (!$not && ($value =~ m/$compare_to/i));
207     }
208
209   } else {
210     $hit           = ($not && ! $value)                     || (!$not &&  $value);
211   }
212
213   if ($hit) {
214     my $new_text = $self->parse_block($block, @indices);
215     if (!defined($new_text)) {
216       $main::lxdebug->leave_sub();
217       return undef;
218     }
219     $$new_contents .= $new_text;
220   }
221
222   $main::lxdebug->leave_sub();
223
224   return 1;
225 }
226
227 1;