X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;ds=sidebyside;f=SL%2FTemplate%2FLaTeX.pm;h=6a5d8e4a9be7ab1a63f03ba6005ebc7dd7db7eaf;hb=606510ade9fe97cb9ca64878f1ed19326e65c50c;hp=291eb9f0ff9b484100f7dbc2ba73cfeafd811571;hpb=a23454bb1b039a31b7f77710ff663fa9152d530c;p=kivitendo-erp.git
diff --git a/SL/Template/LaTeX.pm b/SL/Template/LaTeX.pm
index 291eb9f0f..6a5d8e4a9 100644
--- a/SL/Template/LaTeX.pm
+++ b/SL/Template/LaTeX.pm
@@ -9,9 +9,106 @@ 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 _lb_to_space {
+ my ($to_replace) = @_;
+
+ my $vspace = '\vspace*{0.5cm}';
+ return $vspace x (length($to_replace) / length($html_replace{'
'}));
+}
+
+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; # remove line breaks at the end of the text
+ $content =~ s{ ^ \s+ }{}gx; # remove white space at the start of the text
+ $content =~ s{ ^ ( \\newline \ )+ }{ _lb_to_space($1) }gxe; # convert line breaks at the start of the text to vertical space
+ $content =~ s{ ( \n\n+ ) ( \\newline \ )+ }{ $1 . _lb_to_space($2) }gxe; # convert line breaks at the start of a paragraph to vertical space
+ $content =~ s{ ( \\end\{ [^\}]+ \} \h* ) ( \\newline \ )+ }{ $1 . _lb_to_space($2) }gxe; # convert line breaks after LaTeX environments like lists to vertical space
+ $content =~ s{ ^ \h+ \\newline }{\\newline}gmx;
+ $content =~ s{ \n\n \h* \\newline \h* }{\n\n}gmx;
+
+ return $content;
+}
+
+my %formatters = (
+ html => \&_format_html,
+ text => \&_format_text,
+);
+
sub new {
my $type = shift;
@@ -21,24 +118,17 @@ sub new {
}
sub format_string {
- my ($self, $variable) = @_;
+ my ($self, $content, $variable) = @_;
- $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
+ my $formatter =
+ $formatters{ $self->{variable_content_types}->{$variable} }
+ // $formatters{ $self->{default_content_type} }
+ // $formatters{ text };
- # 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');
+ $content =~ s{[^\p{Print}\n]|\p{Cf}}{}g;
+ $variable =~ s{[^\p{Print}\n]|\p{Cf}}{}g;
- foreach my $key (keys(%markup_replace)) {
- my $new = $markup_replace{$key};
- $variable =~ s/\$\<\$${key}\$\>\$(.*?)\$<\$\/${key}\$>\$/\\${new}\{$1\}/gi;
- }
-
- $variable =~ s/[\x00-\x1f]//g;
-
- return $variable;
+ return $formatter->($self, $content, variable => $variable);
}
sub parse_foreach {
@@ -195,15 +285,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);
@@ -320,7 +410,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++;
@@ -336,7 +426,7 @@ sub parse {
$self->{"error"} = "$form->{templates}/$form->{IN}: $!";
return 0;
}
- binmode IN, ":utf8" if $::locale->is_utf8;
+ binmode IN, ":utf8";
my @lines = ;
close(IN);
@@ -346,13 +436,13 @@ 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"} = [];
@@ -363,7 +453,9 @@ sub parse {
$contents = "[% TAGS $self->{tag_start} $self->{tag_end} %]\n" . $contents;
}
- $::form->init_template->process(\$contents, $form, \$new_contents) || die $::form->template->error;
+ my $globals = global_vars();
+
+ $::form->template->process(\$contents, { %$form, %$globals }, \$new_contents) || die $::form->template->error;
} else {
$new_contents = $self->parse_block($contents);
}
@@ -372,13 +464,8 @@ sub parse {
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();
@@ -408,11 +495,13 @@ sub convert_to_postscript {
my $old_home = $ENV{HOME};
my $old_openin_any = $ENV{openin_any};
$ENV{HOME} = $userspath =~ m|^/| ? $userspath : getcwd();
- $ENV{openin_any} = "p";
+ $ENV{openin_any} = "r";
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;
@@ -423,12 +512,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;
}
@@ -458,11 +549,14 @@ sub convert_to_pdf {
my $old_home = $ENV{HOME};
my $old_openin_any = $ENV{openin_any};
$ENV{HOME} = $userspath =~ m|^/| ? $userspath : getcwd();
- $ENV{openin_any} = "p";
+ $ENV{openin_any} = "r";
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;
@@ -516,7 +610,7 @@ sub parse_and_create_pdf {
$local_form->{IN} = $template_file_name;
$local_form->{tmpdir} = $::lx_office_conf{paths}->{userspath};
$local_form->{tmpfile} = $tex_file_name;
- $local_form->{templates} = $::myconfig{templates};
+ $local_form->{templates} = SL::DB::Default->get->templates;
foreach (keys %params) {
croak "The parameter '$_' must not be used." if exists $local_form->{$_};
@@ -525,7 +619,7 @@ sub parse_and_create_pdf {
my $error;
eval {
- my $template = SL::Template::LaTeX->new($template_file_name, $local_form, \%::myconfig, $::lx_office_conf{paths}->{userspath});
+ 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;
@@ -548,4 +642,15 @@ sub parse_and_create_pdf {
return (file_name => do { $tex_file_name =~ s/tex$/pdf/; $tex_file_name });
}
+sub global_vars {
+ {
+ AUTH => $::auth,
+ INSTANCE_CONF => $::instance_conf,
+ LOCALE => $::locale,
+ LXCONFIG => $::lx_office_conf,
+ LXDEBUG => $::lxdebug,
+ MYCONFIG => \%::myconfig,
+ };
+}
+
1;