Unterstützung für andere Datenbankencodings als Unicode/UTF-8 entfernt
[kivitendo-erp.git] / SL / Template / LaTeX.pm
index 6b18ad0..2f99f7e 100644 (file)
@@ -4,7 +4,15 @@ 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 List::MoreUtils qw(any);
+use Unicode::Normalize qw();
+
+use SL::DB::Default;
 
 sub new {
   my $type = shift;
@@ -16,7 +24,6 @@ sub new {
 
 sub format_string {
   my ($self, $variable) = @_;
-  my $form = $self->{"form"};
 
   $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
 
@@ -62,6 +69,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)
@@ -102,6 +110,7 @@ sub parse_foreach {
       }
       $current_line += $lines;
     }
+  #stop removing code here.
 
     if (   ref $linetotal_array eq 'ARRAY'
         && $i < scalar(@{$linetotal_array})) {
@@ -134,7 +143,7 @@ sub find_end {
 
     my $keyword_pos = $pos - 1 + $tag_start_len;
 
-    if ((substr($text, $keyword_pos, 2) eq 'if') || (substr($text, $keyword_pos, 3) eq 'foreach')) {
+    if ((substr($text, $keyword_pos, 2) eq 'if') || (substr($text, $keyword_pos, 7) eq 'foreach')) {
       $depth++;
 
     } elsif ((substr($text, $keyword_pos, 4) eq 'else') && (1 == $depth)) {
@@ -254,6 +263,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 {
@@ -292,24 +304,28 @@ sub _force_mandatory_packages {
   my $self  = shift;
   my $lines = shift;
 
-  my (%used_packages, $document_start_line);
+  my (%used_packages, $document_start_line, $last_usepackage_line);
 
   foreach my $i (0 .. scalar @{ $lines } - 1) {
     if ($lines->[$i] =~ m/\\usepackage[^\{]*{(.*?)}/) {
       $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;
 
     }
   }
 
-  $document_start_line = scalar @{ $lines } - 1 if (!defined $document_start_line);
+  my $insertion_point = defined($document_start_line)  ? $document_start_line
+                      : defined($last_usepackage_line) ? $last_usepackage_line
+                      :                                  scalar @{ $lines } - 1;
 
-  if (!$used_packages{textcomp}) {
-    splice @{ $lines }, $document_start_line, 0, "\\usepackage{textcomp}\n";
-    $document_start_line++;
+  foreach my $package (qw(textcomp)) {
+    next if $used_packages{$package};
+    splice @{ $lines }, $insertion_point, 0, "\\usepackage{${package}}\n";
+    $insertion_point++;
   }
 }
 
@@ -319,10 +335,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 = <IN>;
   close(IN);
 
@@ -343,14 +359,23 @@ sub parse {
 
   $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->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;
   }
 
-  binmode OUT, ":utf8" if $::locale->is_utf8;
-  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();
@@ -366,6 +391,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 : $!";
@@ -377,15 +403,17 @@ sub convert_to_postscript {
 
   my $latex = $self->_get_latex_path();
   my $old_home = $ENV{HOME};
-  $ENV{HOME}   = $userspath =~ m|^/| ? $userspath : getcwd() . "/" . $userspath;
+  my $old_openin_any = $ENV{openin_any};
+  $ENV{HOME}   = $userspath =~ m|^/| ? $userspath : getcwd();
+  $ENV{openin_any} = "p";
 
   for (my $run = 1; $run <= 2; $run++) {
     system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
            "> $form->{tmpfile}.err");
     if ($?) {
       $ENV{HOME} = $old_home;
-      $self->{"error"} = $form->cleanup();
-      $self->cleanup();
+      $ENV{openin_any} = $old_openin_any;
+      $self->{"error"} = $form->cleanup($latex);
       return 0;
     }
   }
@@ -394,10 +422,11 @@ sub convert_to_postscript {
 
   system("dvips $form->{tmpfile} -o -q > /dev/null");
   $ENV{HOME} = $old_home;
+  $ENV{openin_any} = $old_openin_any;
 
   if ($?) {
     $self->{"error"} = "dvips : $!";
-    $self->cleanup();
+    $self->cleanup('dvips');
     return 0;
   }
   $form->{tmpfile} =~ s/dvi$/ps/;
@@ -412,6 +441,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 : $!";
@@ -423,27 +453,32 @@ sub convert_to_pdf {
 
   my $latex = $self->_get_latex_path();
   my $old_home = $ENV{HOME};
-  $ENV{HOME}   = $userspath =~ m|^/| ? $userspath : getcwd() . "/" . $userspath;
+  my $old_openin_any = $ENV{openin_any};
+  $ENV{HOME}   = $userspath =~ m|^/| ? $userspath : getcwd();
+  $ENV{openin_any} = "p";
 
   for (my $run = 1; $run <= 2; $run++) {
     system("${latex} --interaction=nonstopmode $form->{tmpfile} " .
            "> $form->{tmpfile}.err");
     if ($?) {
-      $ENV{HOME} = $old_home;
-      $self->{"error"} = $form->cleanup();
-      $self->cleanup();
+      $ENV{HOME}     = $old_home;
+      $ENV{openin_any} = $old_openin_any;
+      $self->{error} = $form->cleanup($latex);
       return 0;
     }
   }
 
   $ENV{HOME} = $old_home;
+  $ENV{openin_any} = $old_openin_any;
   $form->{tmpfile} =~ s/tex$/pdf/;
 
   $self->cleanup();
+
+  return 1;
 }
 
 sub _get_latex_path {
-  return $main::latex_bin || 'pdflatex';
+  return $::lx_office_conf{applications}->{latex} || 'pdflatex';
 }
 
 sub get_mime_type() {
@@ -460,4 +495,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($template_file_name, $local_form, \%::myconfig, $::lx_office_conf{paths}->{userspath});
+    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;