X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FTemplate.pm;h=3556dc49a6de3831ccb9e4427b92b9df88ad068a;hb=88e6dce2c094fa468e4397030d2f14289a265e62;hp=9e25f39ee0c43baaaa735cdee4732e9c410d8170;hpb=6534db924d0c874b31306d827ffb011f66a6e591;p=kivitendo-erp.git diff --git a/SL/Template.pm b/SL/Template.pm index 9e25f39ee..3556dc49a 100644 --- a/SL/Template.pm +++ b/SL/Template.pm @@ -5,9 +5,17 @@ # Web http://www.lx-office.org # #==================================================================== +# +# +# NOTE: strict checks are package global. don't check this file +# with perl -sc, it will only capture SimpleTemplate +# +# package SimpleTemplate; +use strict; + # Parameters: # 1. The template's file name # 2. A reference to the Form object @@ -28,12 +36,28 @@ sub new { sub _init { my $self = shift; - $self->{"source"} = shift; - $self->{"form"} = shift; - $self->{"myconfig"} = shift; - $self->{"userspath"} = shift; + $self->{source} = shift; + $self->{form} = shift; + $self->{myconfig} = shift; + $self->{userspath} = shift; + + $self->{error} = undef; + $self->{quot_re} = '"'; + + $self->set_tag_style('<%', '%>'); +} + +sub set_tag_style { + my $self = shift; + my $tag_start = shift; + my $tag_end = shift; - $self->{"error"} = undef; + $self->{tag_start} = $tag_start; + $self->{tag_end} = $tag_end; + $self->{tag_start_qm} = quotemeta $tag_start; + $self->{tag_end_qm} = quotemeta $tag_end; + + $self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}"; } sub cleanup { @@ -64,6 +88,133 @@ sub uses_temp_file { return 0; } +sub _get_loop_variable { + my $self = shift; + my $var = shift; + my $get_array = shift; + my @indices = @_; + + my $form = $self->{form}; + my $value; + + if (($get_array || @indices) && (ref $form->{TEMPLATE_ARRAYS} eq 'HASH') && (ref $form->{TEMPLATE_ARRAYS}->{$var} eq 'ARRAY')) { + $value = $form->{TEMPLATE_ARRAYS}->{$var}; + } else { + $value = $form->{$var}; + } + + for (my $i = 0; $i < scalar(@indices); $i++) { + last unless (ref($value) eq "ARRAY"); + $value = $value->[$indices[$i]]; + } + + return $value; +} + +sub substitute_vars { + my ($self, $text, @indices) = @_; + + my $form = $self->{"form"}; + + while ($text =~ /$self->{substitute_vars_re}/) { + my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]); + my ($var, @options) = split(/\s+/, $1); + + my $value = $self->_get_loop_variable($var, 0, @indices); + $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options)); + + substr($text, $tag_pos, $tag_len, $value); + } + + return $text; +} + +sub _parse_block_if { + $main::lxdebug->enter_sub(); + + my $self = shift; + my $contents = shift; + my $new_contents = shift; + my $pos_if = shift; + my @indices = @_; + + $$new_contents .= $self->substitute_vars(substr($$contents, 0, $pos_if), @indices); + substr($$contents, 0, $pos_if) = ""; + + if ($$contents !~ m/^$self->{tag_start_qm}if + \s* + (not\b|\!)? # $1 -- Eventuelle Negierung + \s+ + (\b.+?\b) # $2 -- Name der zu überprüfenden Variablen + ( # $3 -- Beginn des optionalen Vergleiches + \s* + ([!=]) # $4 -- Negierung des Vergleiches speichern + ([=~]) # $5 -- Art des Vergleiches speichern + \s* + ( # $6 -- Gequoteter String oder Bareword + $self->{quot_re} + (.*?)(?{quot_re} + | + (\b.+?\b) # $8 -- Bareword -- als Index für $form benutzen + ) + )? + \s* + $self->{tag_end_qm} + /x) { + $self->{"error"} = "Malformed $self->{tag_start}if$self->{tag_end}."; + $main::lxdebug->leave_sub(); + return undef; + } + + my $not = $1; + my $var = $2; + my $operator_neg = $4; # '=' oder '!' oder undef, wenn kein Vergleich erkannt + my $operator_type = $5; # '=' oder '~' für Stringvergleich oder Regex + my $quoted_word = $7; # nur gültig, wenn quoted string angegeben (siehe unten); dann "value" aus <%if var == "value" %> + my $bareword = $8; # undef, falls quoted string angegeben wurde; andernfalls "othervar" aus <%if var == othervar %> + + $not = !$not if ($operator_neg && $operator_neg eq '!'); + + substr($$contents, 0, length($&)) = ""; + + my $block; + ($block, $$contents) = $self->find_end($$contents, 0, $var, $not); + if (!$block) { + $self->{"error"} = "Unclosed $self->{tag_start}if$self->{tag_end}." unless ($self->{"error"}); + $main::lxdebug->leave_sub(); + return undef; + } + + my $value = $self->_get_loop_variable($var, 0, @indices); + my $hit = 0; + + if ($operator_type) { + my $compare_to = $bareword ? $self->_get_loop_variable($bareword, 0, @indices) : $quoted_word; + if ($operator_type eq '=') { + $hit = ($not && !($value eq $compare_to)) || (!$not && ($value eq $compare_to)); + } else { + $hit = ($not && !($value =~ m/$compare_to/i)) || (!$not && ($value =~ m/$compare_to/i)); + } + + } else { + $hit = ($not && ! $value) || (!$not && $value); + } + + if ($hit) { + my $new_text = $self->parse_block($block, @indices); + if (!defined($new_text)) { + $main::lxdebug->leave_sub(); + return undef; + } + $$new_contents .= $new_text; + } + + $main::lxdebug->leave_sub(); + + return 1; +} + 1; #### @@ -76,42 +227,21 @@ use vars qw(@ISA); @ISA = qw(SimpleTemplate); +use strict; + sub new { my $type = shift; - return $type->SUPER::new(@_); + my $self = $type->SUPER::new(@_); + + return $self; } sub format_string { my ($self, $variable) = @_; my $form = $self->{"form"}; - my %replace = - ('order' => [quotemeta("\\"), - '', - '&', quotemeta("\n"), - '"', '\$', '%', '_', '#', quotemeta('^'), - '{', '}', '<', '>', '£', "\r" - ], - quotemeta("\\") => '\\textbackslash ', - '' => '', - '"' => "''", - '&' => '\&', - '\$' => '\$', - '%' => '\%', - '_' => '\_', - '#' => '\#', - '{' => '\{', - '}' => '\}', - '<' => '$<$', - '>' => '$>$', - '£' => '\pounds ', - "\r" => "", - quotemeta('^') => '\^\\', - quotemeta("\n") => '\newline ' - ); - - map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} }); + $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable); # Allow some HTML markup to be converted into the output format's # corresponding markup code, e.g. bold or italic. @@ -124,27 +254,9 @@ sub format_string { $variable =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi; } - return $variable; -} - -sub substitute_vars { - my ($self, $text, @indices) = @_; - - my $form = $self->{"form"}; - - while ($text =~ /<\%(.*?)\%>/) { - my ($var, @options) = split(/\s+/, $1); - my $value = $form->{$var}; - - for (my $i = 0; $i < scalar(@indices); $i++) { - last unless (ref($value) eq "ARRAY"); - $value = $value->[$indices[$i]]; - } - $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options)); - substr($text, $-[0], $+[0] - $-[0]) = $value; - } + $variable =~ s/[\x00-\x1f]//g; - return $text; + return $variable; } sub parse_foreach { @@ -152,34 +264,36 @@ sub parse_foreach { my ($form, $new_contents) = ($self->{"form"}, ""); - my $ary = $form->{$var}; - for (my $i = 0; $i < scalar(@indices); $i++) { - last unless (ref($ary) eq "ARRAY"); - $ary = $ary->[$indices[$i]]; - } + my $ary = $self->_get_loop_variable($var, 1, @indices); - my $sum = 0; - my $current_page = 1; + my $sum = 0; + my $current_page = 1; my ($current_line, $corrent_row) = (0, 1); + my $description_array = $self->_get_loop_variable("description", 1); + my $longdescription_array = $self->_get_loop_variable("longdescription", 1); + my $linetotal_array = $self->_get_loop_variable("linetotal", 1); + + $form->{TEMPLATE_ARRAYS}->{cumulatelinetotal} = []; + + # forech block hasn't given us an array. ignore + return $new_contents unless ref $ary eq 'ARRAY'; for (my $i = 0; $i < scalar(@{$ary}); $i++) { - $form->{"__first__"} = $i == 0; - $form->{"__last__"} = ($i + 1) == scalar(@{$ary}); - $form->{"__odd__"} = (($i + 1) % 2) == 1; + # do magic markers + $form->{"__first__"} = $i == 1; + $form->{"__last__"} = ($i + 1) == scalar(@{$ary}); + $form->{"__odd__"} = (($i + 1) % 2) == 1; $form->{"__counter__"} = $i + 1; - if ((scalar(@{$form->{"description"}}) == scalar(@{$ary})) && - $self->{"chars_per_line"}) { - my $lines = - int(length($form->{"description"}->[$i]) / $self->{"chars_per_line"}); + if ( ref $description_array eq 'ARRAY' + && scalar @{$description_array} == scalar @{$ary} + && $self->{"chars_per_line"} != 0) + { + my $lines = int(length($description_array->[$i]) / $self->{"chars_per_line"}); my $lpp; - $form->{"description"}->[$i] =~ s/(\\newline\s?)*$//; - my $_description = $form->{"description"}->[$i]; - while ($_description =~ /\\newline/) { - $lines++; - $_description =~ s/\\newline//; - } + $description_array->[$i] =~ s/(\\newline\s?)*$//; + $lines++ while ($description_array->[$i] =~ m/\\newline/g); $lines++; if ($current_page == 1) { @@ -189,16 +303,18 @@ sub parse_foreach { } # Yes we need a manual page break -- or the user has forced one - if ((($current_line + $lines) > $lpp) || - ($form->{"description"}->[$i] =~ //)) { + if ( (($current_line + $lines) > $lpp) + || ($description_array->[$i] =~ //) + || ( ref $longdescription_array eq 'ARRAY' + && $longdescription_array->[$i] =~ //)) { my $pb = $self->{"pagebreak_block"}; # replace the special variables <%sumcarriedforward%> # and <%lastpage%> my $psum = $form->format_amount($self->{"myconfig"}, $sum, 2); - $pb =~ s/<%sumcarriedforward%>/$psum/g; - $pb =~ s/<%lastpage%>/$current_page/g; + $pb =~ s/$self->{tag_start_qm}sumcarriedforward$self->{tag_end_qm}/$psum/g; + $pb =~ s/$self->{tag_start_qm}lastpage$self->{tag_end_qm}/$current_page/g; my $new_text = $self->parse_block($pb, (@indices, $i)); return undef unless (defined($new_text)); @@ -209,13 +325,14 @@ sub parse_foreach { } $current_line += $lines; } - if ($i < scalar(@{$form->{"linetotal"}})) { - $sum += $form->parse_amount($self->{"myconfig"}, - $form->{"linetotal"}->[$i]); + + if ( ref $linetotal_array eq 'ARRAY' + && $i < scalar(@{$linetotal_array})) { + $sum += $form->parse_amount($self->{"myconfig"}, $linetotal_array->[$i]); } - - $form->{"cumulatelinetotal"}[$i] = $form->format_amount($self->{"myconfig"}, $sum, 2); - + + $form->{TEMPLATE_ARRAYS}->{cumulatelinetotal}->[$i] = $form->format_amount($self->{"myconfig"}, $sum, 2); + my $new_text = $self->parse_block($text, (@indices, $i)); return undef unless (defined($new_text)); $new_contents .= $start_tag . $new_text . $end_tag; @@ -228,36 +345,43 @@ sub parse_foreach { sub find_end { my ($self, $text, $pos, $var, $not) = @_; + my $tag_start_len = length $self->{tag_start}; + my $depth = 1; $pos = 0 unless ($pos); while ($pos < length($text)) { $pos++; - next if (substr($text, $pos - 1, 2) ne '<%'); + next if (substr($text, $pos - 1, length($self->{tag_start})) ne $self->{tag_start}); + + my $keyword_pos = $pos - 1 + $tag_start_len; - if ((substr($text, $pos + 1, 2) eq 'if') || (substr($text, $pos + 1, 3) eq 'for')) { + if ((substr($text, $keyword_pos, 2) eq 'if') || (substr($text, $keyword_pos, 3) eq 'for')) { $depth++; - } elsif ((substr($text, $pos + 1, 4) eq 'else') && (1 == $depth)) { + } elsif ((substr($text, $keyword_pos, 4) eq 'else') && (1 == $depth)) { if (!$var) { - $self->{"error"} = '<%else%> outside of <%if%> / <%ifnot%>.'; + $self->{"error"} = + "$self->{tag_start}else$self->{tag_end} outside of " + . "$self->{tag_start}if$self->{tag_end} / " + . "$self->{tag_start}ifnot$self->{tag_end}."; return undef; } my $block = substr($text, 0, $pos - 1); substr($text, 0, $pos - 1) = ""; - $text =~ s!^<\%[^\%]+\%>!!; - $text = '<%if' . ($not ? " " : "not ") . $var . '%>' . $text; + $text =~ s!^$self->{tag_start_qm}.+?$self->{tag_end_qm}!!; + $text = $self->{tag_start} . 'if' . ($not ? " " : "not ") . $var . $self->{tag_end} . $text; return ($block, $text); - } elsif (substr($text, $pos + 1, 3) eq 'end') { + } elsif (substr($text, $keyword_pos, 3) eq 'end') { $depth--; if ($depth == 0) { my $block = substr($text, 0, $pos - 1); substr($text, 0, $pos - 1) = ""; - $text =~ s!^<\%[^\%]+\%>!!; + $text =~ s!^$self->{tag_start_qm}.+?$self->{tag_end_qm}!!; return ($block, $text); } @@ -275,8 +399,8 @@ sub parse_block { my $new_contents = ""; while ($contents ne "") { - my $pos_if = index($contents, '<%if'); - my $pos_foreach = index($contents, '<%foreach'); + my $pos_if = index($contents, $self->{tag_start} . 'if'); + my $pos_foreach = index($contents, $self->{tag_start} . 'foreach'); if ((-1 == $pos_if) && (-1 == $pos_foreach)) { $new_contents .= $self->substitute_vars($contents, @indices); @@ -287,8 +411,8 @@ sub parse_block { $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices); substr($contents, 0, $pos_foreach) = ""; - if ($contents !~ m|^<\%foreach (.*?)\%>|) { - $self->{"error"} = "Malformed <\%foreach\%>."; + if ($contents !~ m|^$self->{tag_start_qm}foreach (.+?)$self->{tag_end_qm}|) { + $self->{"error"} = "Malformed $self->{tag_start}foreach$self->{tag_end}."; $main::lxdebug->leave_sub(); return undef; } @@ -300,7 +424,7 @@ sub parse_block { my $block; ($block, $contents) = $self->find_end($contents); if (!$block) { - $self->{"error"} = "Unclosed <\%foreach\%>." unless ($self->{"error"}); + $self->{"error"} = "Unclosed $self->{tag_start}foreach$self->{tag_end}." unless ($self->{"error"}); $main::lxdebug->leave_sub(); return undef; } @@ -313,46 +437,103 @@ sub parse_block { $new_contents .= $new_text; } else { - $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices); - substr($contents, 0, $pos_if) = ""; - - if ($contents !~ m|^<\%if\s*(not)?\s+(.*?)\%>|) { - $self->{"error"} = "Malformed <\%if\%>."; + if (!$self->_parse_block_if(\$contents, \$new_contents, $pos_if, @indices)) { $main::lxdebug->leave_sub(); return undef; } + } + } - my ($not, $var) = ($1, $2); + $main::lxdebug->leave_sub(); - substr($contents, 0, length($&)) = ""; + return $new_contents; +} - ($block, $contents) = $self->find_end($contents, 0, $var, $not); - if (!$block) { - $self->{"error"} = "Unclosed <\%if${not}\%>." unless ($self->{"error"}); - $main::lxdebug->leave_sub(); - return undef; - } +sub parse_first_line { + my $self = shift; + my $line = shift || ""; - my $value = $self->{"form"}->{$var}; - for (my $i = 0; $i < scalar(@indices); $i++) { - last unless (ref($value) eq "ARRAY"); - $value = $value->[$indices[$i]]; - } + if ($line =~ m/([^\s]+)set-tag-style([^\s]+)/) { + if ($1 eq $2) { + $self->{error} = "The tag start and end markers must not be equal."; + return 0; + } - if (($not && !$value) || (!$not && $value)) { - my $new_text = $self->parse_block($block, @indices); - if (!defined($new_text)) { - $main::lxdebug->leave_sub(); - return undef; - } - $new_contents .= $new_text; - } + $self->set_tag_style($1, $2); + } + + return 1; +} + +sub _parse_config_option { + my $self = shift; + my $line = shift; + + $line =~ s/^\s*//; + $line =~ s/\s*$//; + + my ($key, $value) = split m/\s*=\s*/, $line, 2; + + if ($key eq 'tag-style') { + $self->set_tag_style(split(m/\s+/, $value, 2)); + } +} + +sub _parse_config_lines { + my $self = shift; + my $lines = shift; + + my ($comment_start, $comment_end) = ("", ""); + + if (ref $self eq 'LaTeXTemplate') { + $comment_start = '\s*%'; + } elsif (ref $self eq 'HTMLTemplate') { + $comment_start = '\s*