X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;ds=inline;f=SL%2FTemplate%2FLaTeX.pm;h=352f793e12fc25d6aa81a2a399efc06eebed7a36;hb=31e6d33a8e4ec4cf11a25ad63696948bc55f63bc;hp=2df7e8cfbc574f9eaea1afdc36324090764aa485;hpb=6ae13887a4bd2fb056010ae7bd22b652c8c5d116;p=kivitendo-erp.git
diff --git a/SL/Template/LaTeX.pm b/SL/Template/LaTeX.pm
index 2df7e8cfb..352f793e1 100644
--- a/SL/Template/LaTeX.pm
+++ b/SL/Template/LaTeX.pm
@@ -4,9 +4,98 @@ use parent qw(SL::Template::Simple);
use strict;
+use Carp;
use Cwd;
+use English qw(-no_match_vars);
+use File::Basename;
+use File::Temp;
+use HTML::Entities ();
+use List::MoreUtils qw(any);
use Unicode::Normalize qw();
+use SL::DB::Default;
+
+my %text_markup_replace = (
+ b => 'textbf',
+ i => 'textit',
+ u => 'underline',
+);
+
+sub _format_text {
+ my ($self, $content, %params) = @_;
+
+ $content = $::locale->quote_special_chars('Template/LaTeX', $content);
+
+ # Allow some HTML markup to be converted into the output format's
+ # corresponding markup code, e.g. bold or italic.
+ foreach my $key (keys(%text_markup_replace)) {
+ my $new = $text_markup_replace{$key};
+ $content =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
+ }
+
+ $content =~ s/[\x00-\x1f]//g;
+
+ return $content;
+}
+
+my %html_replace = (
+ '
' => "\n\n",
+ '' => "\\begin{itemize} ",
+ '
' => "\\end{itemize} ",
+ '' => "\\begin{enumerate} ",
+ '
' => "\\end{enumerate} ",
+ '' => "\\item ",
+ '' => " ",
+ '' => "\\textbf{",
+ '' => "}",
+ '' => "\\textbf{",
+ '' => "}",
+ '' => "\\textit{",
+ '' => "}",
+ '' => "\\textit{",
+ '' => "}",
+ '' => "\\underline{",
+ '' => "}",
+ '' => "\\sout{",
+ '' => "}",
+ '' => "\\textsubscript{",
+ '' => "}",
+ '' => "\\textsuperscript{",
+ '' => "}",
+ '
' => "\\newline ",
+ '
' => "\\newline ",
+);
+
+sub _format_html {
+ my ($self, $content, %params) = @_;
+
+ $content =~ s{ \r+ }{}gx;
+ $content =~ s{ \n+ }{ }gx;
+ $content =~ s{ (?:\ |\s)+ }{ }gx;
+ $content =~ s{ (?:\ |\s)+$ }{}gx;
+ $content =~ s{ (?:
)+$ }{}gx;
+
+ my @parts = grep { $_ } map {
+ if (substr($_, 0, 1) eq '<') {
+ s{ +}{}g;
+ $html_replace{$_} || '';
+
+ } else {
+ $::locale->quote_special_chars('Template/LaTeX', HTML::Entities::decode_entities($_));
+ }
+ } split(m{(<.*?>)}x, $content);
+
+ $content = join '', @parts;
+ $content =~ s{ (?: [\n\s] | \\newline )+$ }{}gx;
+
+ return $content;
+}
+
+my %formatters = (
+ html => \&_format_html,
+ text => \&_format_text,
+);
+
sub new {
my $type = shift;
@@ -16,25 +105,14 @@ sub new {
}
sub format_string {
- my ($self, $variable) = @_;
- my $form = $self->{"form"};
-
- $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.
- my %markup_replace = ('b' => 'textbf',
- 'i' => 'textit',
- 'u' => 'underline');
-
- foreach my $key (keys(%markup_replace)) {
- my $new = $markup_replace{$key};
- $variable =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
- }
+ my ($self, $content, $variable) = @_;
- $variable =~ s/[\x00-\x1f]//g;
+ my $formatter =
+ $formatters{ $self->{variable_content_types}->{$variable} }
+ // $formatters{ $self->{default_content_type} }
+ // $formatters{ text };
- return $variable;
+ return $formatter->($self, $content, variable => $variable);
}
sub parse_foreach {
@@ -63,6 +141,7 @@ sub parse_foreach {
$form->{"__odd__"} = (($i + 1) % 2) == 1;
$form->{"__counter__"} = $i + 1;
+ #everything from here to the next marker should be removed after the release of 2.7.0
if ( ref $description_array eq 'ARRAY'
&& scalar @{$description_array} == scalar @{$ary}
&& $self->{"chars_per_line"} != 0)
@@ -103,6 +182,7 @@ sub parse_foreach {
}
$current_line += $lines;
}
+ #stop removing code here.
if ( ref $linetotal_array eq 'ARRAY'
&& $i < scalar(@{$linetotal_array})) {
@@ -189,15 +269,15 @@ sub parse_block {
$new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices);
substr($contents, 0, $pos_foreach) = "";
- if ($contents !~ m|^$self->{tag_start_qm}foreach (.+?)$self->{tag_end_qm}|) {
+ 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;
}
- my $var = $1;
+ my $var = $2;
- substr($contents, 0, length($&)) = "";
+ substr($contents, 0, length($1)) = "";
my $block;
($block, $contents) = $self->find_end($contents);
@@ -255,6 +335,9 @@ sub _parse_config_option {
if ($key eq 'tag-style') {
$self->set_tag_style(split(m/\s+/, $value, 2));
}
+ if ($key eq 'use-template-toolkit') {
+ $self->set_use_template_toolkit($value);
+ }
}
sub _parse_config_lines {
@@ -300,7 +383,7 @@ sub _force_mandatory_packages {
$used_packages{$1} = 1;
$last_usepackage_line = $i;
- } elsif ($lines->[$i] =~ m/\\begin{document}/) {
+ } elsif ($lines->[$i] =~ m/\\begin\{document\}/) {
$document_start_line = $i;
last;
@@ -311,7 +394,7 @@ sub _force_mandatory_packages {
: defined($last_usepackage_line) ? $last_usepackage_line
: scalar @{ $lines } - 1;
- foreach my $package (qw(textcomp)) {
+ foreach my $package (qw(textcomp ulem)) {
next if $used_packages{$package};
splice @{ $lines }, $insertion_point, 0, "\\usepackage{${package}}\n";
$insertion_point++;
@@ -324,10 +407,10 @@ sub parse {
my $form = $self->{"form"};
if (!open(IN, "$form->{templates}/$form->{IN}")) {
- $self->{"error"} = "$!";
+ $self->{"error"} = "$form->{templates}/$form->{IN}: $!";
return 0;
}
- binmode IN, ":utf8" if $::locale->is_utf8;
+ binmode IN, ":utf8";
my @lines = ;
close(IN);
@@ -337,30 +420,36 @@ sub parse {
my $contents = join("", @lines);
# detect pagebreak block and its parameters
- if ($contents =~ /$self->{tag_start_qm}pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*$self->{tag_end_qm}(.*?)$self->{tag_start_qm}end(\s*pagebreak)?$self->{tag_end_qm}/s) {
- $self->{"chars_per_line"} = $1;
- $self->{"lines_on_first_page"} = $2;
- $self->{"lines_on_second_page"} = $3;
- $self->{"pagebreak_block"} = $4;
+ if ($contents =~ /^(.*)($self->{tag_start_qm}pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*$self->{tag_end_qm}(.*?)$self->{tag_start_qm}end(\s*pagebreak)?$self->{tag_end_qm})/s) {
+ $self->{"chars_per_line"} = $3;
+ $self->{"lines_on_first_page"} = $4;
+ $self->{"lines_on_second_page"} = $5;
+ $self->{"pagebreak_block"} = $6;
- substr($contents, length($`), length($&)) = "";
+ substr($contents, length($1), length($2)) = "";
}
$self->{"forced_pagebreaks"} = [];
- my $new_contents = $self->parse_block($contents);
+ my $new_contents;
+ if ($self->{use_template_toolkit}) {
+ if ($self->{custom_tag_style}) {
+ $contents = "[% TAGS $self->{tag_start} $self->{tag_end} %]\n" . $contents;
+ }
+
+ $form->prepare_global_vars;
+
+ $::form->init_template->process(\$contents, $form, \$new_contents) || die $::form->template->error;
+ } else {
+ $new_contents = $self->parse_block($contents);
+ }
if (!defined($new_contents)) {
$main::lxdebug->leave_sub();
return 0;
}
- if ($::locale->is_utf8) {
- binmode OUT, ":utf8";
- print OUT Unicode::Normalize::normalize('C', $new_contents);
-
- } else {
- print OUT $new_contents;
- }
+ binmode OUT, ":utf8";
+ print OUT Unicode::Normalize::normalize('C', $new_contents);
if ($form->{"format"} =~ /postscript/i) {
return $self->convert_to_postscript();
@@ -376,6 +465,7 @@ sub convert_to_postscript {
my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
# Convert the tex file to postscript
+ local $ENV{TEXINPUTS} = ".:" . $form->{cwd} . "/" . $form->{templates} . ":" . $ENV{TEXINPUTS};
if (!chdir("$userspath")) {
$self->{"error"} = "chdir : $!";
@@ -392,8 +482,10 @@ sub convert_to_postscript {
$ENV{openin_any} = "p";
for (my $run = 1; $run <= 2; $run++) {
- system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
- "> $form->{tmpfile}.err");
+ if (system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
+ "> $form->{tmpfile}.err") == -1) {
+ die "system call to $latex failed: $!";
+ }
if ($?) {
$ENV{HOME} = $old_home;
$ENV{openin_any} = $old_openin_any;
@@ -404,12 +496,14 @@ sub convert_to_postscript {
$form->{tmpfile} =~ s/tex$/dvi/;
- system("dvips $form->{tmpfile} -o -q > /dev/null");
+ if (system("dvips $form->{tmpfile} -o -q > /dev/null") == -1) {
+ die "system call to dvips failed: $!";
+ }
$ENV{HOME} = $old_home;
$ENV{openin_any} = $old_openin_any;
if ($?) {
- $self->{"error"} = "dvips : $!";
+ $self->{"error"} = "dvips : $?";
$self->cleanup('dvips');
return 0;
}
@@ -425,6 +519,7 @@ sub convert_to_pdf {
my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
# Convert the tex file to PDF
+ local $ENV{TEXINPUTS} = ".:" . $form->{cwd} . "/" . $form->{templates} . ":" . $ENV{TEXINPUTS};
if (!chdir("$userspath")) {
$self->{"error"} = "chdir : $!";
@@ -441,8 +536,11 @@ sub convert_to_pdf {
$ENV{openin_any} = "p";
for (my $run = 1; $run <= 2; $run++) {
- system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
- "> $form->{tmpfile}.err");
+ if (system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
+ "> $form->{tmpfile}.err") == -1) {
+ die "system call to $latex failed: $!";
+ }
+
if ($?) {
$ENV{HOME} = $old_home;
$ENV{openin_any} = $old_openin_any;
@@ -456,6 +554,8 @@ sub convert_to_pdf {
$form->{tmpfile} =~ s/tex$/pdf/;
$self->cleanup();
+
+ return 1;
}
sub _get_latex_path {
@@ -476,4 +576,54 @@ sub uses_temp_file {
return 1;
}
+sub parse_and_create_pdf {
+ my ($class, $template_file_name, %params) = @_;
+
+ my $keep_temp = $::lx_office_conf{debug} && $::lx_office_conf{debug}->{keep_temp_files};
+ my ($tex_fh, $tex_file_name) = File::Temp::tempfile(
+ 'kivitendo-printXXXXXX',
+ SUFFIX => '.tex',
+ DIR => $::lx_office_conf{paths}->{userspath},
+ UNLINK => $keep_temp ? 0 : 1,,
+ );
+
+ my $old_wd = getcwd();
+
+ my $local_form = Form->new('');
+ $local_form->{cwd} = $old_wd;
+ $local_form->{IN} = $template_file_name;
+ $local_form->{tmpdir} = $::lx_office_conf{paths}->{userspath};
+ $local_form->{tmpfile} = $tex_file_name;
+ $local_form->{templates} = SL::DB::Default->get->templates;
+
+ foreach (keys %params) {
+ croak "The parameter '$_' must not be used." if exists $local_form->{$_};
+ $local_form->{$_} = $params{$_};
+ }
+
+ my $error;
+ eval {
+ my $template = SL::Template::LaTeX->new(file_name => $template_file_name, form => $local_form);
+ my $result = $template->parse($tex_fh) && $template->convert_to_pdf;
+
+ die $template->{error} unless $result;
+
+ 1;
+ } or do { $error = $EVAL_ERROR; };
+
+ chdir $old_wd;
+ close $tex_fh;
+
+ if ($keep_temp) {
+ chmod(((stat $tex_file_name)[2] & 07777) | 0660, $tex_file_name);
+ } else {
+ my $tmpfile = $tex_file_name;
+ $tmpfile =~ s/\.\w+$//;
+ unlink(grep { !m/\.pdf$/ } <$tmpfile.*>);
+ }
+
+ return (error => $error) if $error;
+ return (file_name => do { $tex_file_name =~ s/tex$/pdf/; $tex_file_name });
+}
+
1;