Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 6744758d

Von Moritz Bunkus vor fast 18 Jahren hinzugefügt

  • ID 6744758dc61f5005930b1034c7406641d953f2d4
  • Vorgänger 7f820f8f
  • Nachfolger e5abe3ef
  • OpenDocument-Vorlagen: Konvertierung nach PDF: Der Xvfb wird nun nicht mehr nach jeder Konvertierung beendet sondern einmalig gestartet. Weitere Konvertierungen nutzen einen bereits laufenden Xvfb, was die Zeit zum Umwandeln um ca. 4s reduziert.
  • OpenDocument-Vorlagen: Spezialvariablen first, last, odd und counter hinzugefuegt.
  • OpenDocument-Vorlagen: "<%else%>" in "<%if%>" implementiert.
  • foreach-Zeilenvariablen nach der Schleife wieder aus $form entfernen.
  • HTML-Vorlagen: Unterstuetzung zur Konvertierung nach Postscript und PDF implementiert.
  • OpenDocument-zu-PDF-Konvertierung: Funktionen eingebaut, um OpenOffice als Daemon zu starten, auf den ueber UNO zugegriffen wird. Dadurch verringern sich die Zeiten fuer die Konvertierung drastisch (sieben bis acht Sekunden, wenn OO fuer jedes zu konvertierende Dokument gestartet wird, und zwei bis drei Sekunden, wenn OO ueber UNO angesprochen wird). Erfordert allerdings ein installiertes Python.
  • OpenOffice: Portnummer des OO-Daemons konfigurierbar gemacht.
  • HTML- und LaTeX-Vorlagen: Bloecke verschachtelbar gemacht (analog zu den Parseraenderungen, die fuer OpenDocument vorgenommen wurden). Dabei Unterstuetzung fuer die <%include...%>-Anweisung entfernt.
  • LaTeX/HTML-Vorlagen: Variablen koennen auch un-escaped ausgegeben werden, indem die Form <%variable NOESCAPE%> benutzt wird.
  • OpenDocument-Vorlagen: Die styles.xml ebenfalls parsen, in ihr stehen die Kopf- und Fusszeilen.
  • Backslashes in Variablen bei LaTeX-Vorlagen anstaendig escapen.
  • Falsche Ersetzung von '&' in OpenDocument-XML-Dateien.
  • Markup fuer Hoch- und Tiefstellen mit <sup>...</sup> und <sub>...</sub> bei HTML- und OpenDocument-Vorlagen.
  • Markup-Tags bei Umwandlung in OpenDocument sowohl klein als auch gross geschrieben akzeptieren.
  • In Vorlagen neben "<%ifnot...%>" auch "<%if not...%>" zulassen.

Unterschiede anzeigen:

SL/Template.pm
87 87
  my $form = $self->{"form"};
88 88

  
89 89
  my %replace =
90
    ('order' => [
90
    ('order' => [quotemeta("\\"),
91
                 '<pagebreak>',
91 92
                 '&', quotemeta("\n"),
92 93
                 '"', '\$', '%', '_', '#', quotemeta('^'),
93 94
                 '{', '}',  '<', '>', '?', "\r"
94 95
                 ],
96
     quotemeta("\\") => '\\textbackslash ',
97
     '<pagebreak>'   => '',
95 98
     '"'             => "''",
96 99
     '&'             => '\&',
97 100
     '\$'            => '\$',
......
124 127
  return $variable;
125 128
}
126 129

  
127
sub parse {
128
  my $self = $_[0];
129
  local *OUT = $_[1];
130
  my ($form, $myconfig) = ($self->{"form"}, $self->{"myconfig"});
130
sub substitute_vars {
131
  my ($self, $text, @indices) = @_;
131 132

  
132
  # Some variables used for page breaks
133
  my ($chars_per_line, $lines_on_first_page, $lines_on_second_page) =
134
    (0, 0, 0);
135
  my ($current_page, $current_line, $current_row) = (1, 1, 0);
136
  my ($pagebreak, $sum, $two_passes, $nodiscount_sum) = ("", 0, 0, 0);
137
  my ($par, $var);
133
  my $form = $self->{"form"};
138 134

  
139
  # Do we have to run LaTeX two times? This is needed if
140
  # the template contains page references.
141
  $two_passes = 0;
135
  while ($text =~ /<\%(.*?)\%>/) {
136
    my ($var, @options) = split(/\s+/, $1);
137
    my $value = $form->{$var};
142 138

  
143
  if (!open(IN, "$form->{templates}/$form->{IN}")) {
144
    $self->{"error"} = "$!";
145
    return 0;
139
    for (my $i = 0; $i < scalar(@indices); $i++) {
140
      last unless (ref($value) eq "ARRAY");
141
      $value = $value->[$indices[$i]];
142
    }
143
    $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
144
    substr($text, $-[0], $+[0] - $-[0]) = $value;
146 145
  }
147
  @_ = <IN>;
148
  close(IN);
149 146

  
150
  # first we generate a tmpfile
151
  # read file and replace <%variable%>
152
  while ($_ = shift) {
153
    $par = "";
154
    $var = $_;
147
  return $text;
148
}
155 149

  
156
    $two_passes = 1 if (/\\pageref/);
150
sub parse_foreach {
151
  my ($self, $var, $text, $start_tag, $end_tag, @indices) = @_;
157 152

  
158
    # detect pagebreak block and its parameters
159
    if (/\s*<%pagebreak ([0-9]+) ([0-9]+) ([0-9]+)%>/) {
160
      $chars_per_line       = $1;
161
      $lines_on_first_page  = $2;
162
      $lines_on_second_page = $3;
153
  my ($form, $new_contents) = ($self->{"form"}, "");
163 154

  
164
      while ($_ = shift) {
165
        last if (/\s*<%end pagebreak%>/);
166
        $pagebreak .= $_;
167
      }
168
    }
155
  my $ary = $form->{$var};
156
  for (my $i = 0; $i < scalar(@indices); $i++) {
157
    last unless (ref($ary) eq "ARRAY");
158
    $ary = $ary->[$indices[$i]];
159
  }
169 160

  
170
    if (/\s*<%foreach /) {
161
  my $sum = 0;
162
  my $current_page = 1;
163
  my ($current_line, $corrent_row) = (0, 1);
171 164

  
172
      # this one we need for the count
173
      chomp $var;
174
      $var =~ s/\s*<%foreach (.+?)%>/$1/;
175
      while ($_ = shift) {
176
        last if (/\s*<%end /);
165
  for (my $i = 0; $i < scalar(@{$ary}); $i++) {
166
    $form->{"__first__"} = $i == 0;
167
    $form->{"__last__"} = ($i + 1) == scalar(@{$ary});
168
    $form->{"__odd__"} = (($i + 1) % 2) == 1;
169
    $form->{"__counter__"} = $i + 1;
170

  
171
    if ((scalar(@{$form->{"description"}}) == scalar(@{$ary})) &&
172
        $self->{"chars_per_line"}) {
173
      my $lines =
174
        int(length($form->{"description"}->[$i]) / $self->{"chars_per_line"});
175
      my $lpp;
176

  
177
      $form->{"description"}->[$i] =~ s/(\\newline\s?)*$//;
178
      my $_description = $form->{"description"}->[$i];
179
      while ($_description =~ /\\newline/) {
180
        $lines++;
181
        $_description =~ s/\\newline//;
182
      }
183
      $lines++;
177 184

  
178
        # store line in $par
179
        $par .= $_;
185
      if ($current_page == 1) {
186
        $lpp = $self->{"lines_on_first_page"};
187
      } else {
188
        $lpp = $self->{"lines_on_second_page"};
180 189
      }
181 190

  
182
      # Count the number of "lines" for our variable. Also find the forced pagebreak entries.
183
      my $num_entries = scalar(@{$form->{$var}});
184
      my @forced_pagebreaks = ();
185
      for (my $i = 0; $i < scalar(@{$form->{$var}}); $i++) {
186
        if ($form->{$var}->[$i] =~ /<pagebreak>/) {
187
          push(@forced_pagebreaks, $i);
188
        }
191
      # Yes we need a manual page break -- or the user has forced one
192
      if ((($current_line + $lines) > $lpp) ||
193
          ($form->{"description"}->[$i] =~ /<pagebreak>/)) {
194
        my $pb = $self->{"pagebreak_block"};
195

  
196
        # replace the special variables <%sumcarriedforward%>
197
        # and <%lastpage%>
198

  
199
        my $psum = $form->format_amount($myconfig, $sum, 2);
200
        $pb =~ s/<%sumcarriedforward%>/$psum/g;
201
        $pb =~ s/<%lastpage%>/$current_page/g;
202

  
203
        my $new_text = $self->parse_block($pb, (@indices, $i));
204
        return undef unless (defined($new_text));
205
        $new_contents .= $new_text;
206

  
207
        $current_page++;
208
        $current_line = 0;
189 209
      }
210
      $current_line += $lines;
211
    }
212
    if ($i < scalar(@{$form->{"linetotal"}})) {
213
      $sum += $form->parse_amount($myconfig, $form->{"linetotal"}->[$i]);
214
    }
190 215

  
191
      $current_line = 1;
192
      # display contents of $form->{number}[] array
193
      for ($i = 0; $i < $num_entries; $i++) {
194
        # Try to detect whether a manual page break is necessary
195
        # but only if there was a <%pagebreak ...%> block before
196

  
197
        if ($chars_per_line) {
198
          my $lines =
199
            int(length($form->{"description"}->[$i]) / $chars_per_line + 0.95);
200
          my $lpp;
201

  
202
          $form->{"description"}->[$i] =~ s/(\\newline\s?)*$//;
203
          my $_description = $form->{"description"}->[$i];
204
          while ($_description =~ /\\newline/) {
205
            $lines++;
206
            $_description =~ s/\\newline//;
207
          }
208
          $lines++;
216
    my $new_text = $self->parse_block($text, (@indices, $i));
217
    return undef unless (defined($new_text));
218
    $new_contents .= $start_tag . $new_text . $end_tag;
219
  }
220
  map({ delete($form->{"__${_}__"}); } qw(first last odd counter));
209 221

  
210
          if ($current_page == 1) {
211
            $lpp = $lines_on_first_page;
212
          } else {
213
            $lpp = $lines_on_second_page;
214
          }
222
  return $new_contents;
223
}
215 224

  
216
          # Yes we need a manual page break -- or the user has forced one
217
          if ((($current_line + $lines) > $lpp) ||
218
              grep(/^${current_row}$/, @forced_pagebreaks)) {
219
            my $pb = $pagebreak;
225
sub find_end {
226
  my ($self, $text, $pos, $var, $not) = @_;
220 227

  
221
            # replace the special variables <%sumcarriedforward%>
222
            # and <%lastpage%>
228
  my $depth = 1;
229
  $pos = 0 unless ($pos);
223 230

  
224
            my $psum = $form->format_amount($myconfig, $sum, 2);
225
            my $nodiscount_psum = $form->format_amount($myconfig, $nodiscount_sum, 2);
226
            $pb =~ s/<%nodiscount_sumcarriedforward%>/$nodiscount_psum/g;
227
            $pb =~ s/<%sumcarriedforward%>/$psum/g;
228
            $pb =~ s/<%lastpage%>/$current_page/g;
231
  while ($pos < length($text)) {
232
    $pos++;
229 233

  
230
            # only "normal" variables are supported here
231
            # (no <%if, no <%foreach, no <%include)
234
    next if (substr($text, $pos - 1, 2) ne '<%');
232 235

  
233
            while ($pb =~ /<%(.*?)%>/) {
234
              substr($pb, $-[0], $+[0] - $-[0]) =
235
                $self->format_string($form->{"$1"}->[$i]);
236
            }
236
    if ((substr($text, $pos + 1, 2) eq 'if') || (substr($text, $pos + 1, 3) eq 'for')) {
237
      $depth++;
237 238

  
238
            # page break block is ready to rock
239
            print(OUT $pb);
240
            $current_page++;
241
            $current_line = 1;
242
          }
243
          $current_line += $lines;
244
          $current_row++;
245
        }
246
        $sum += $form->parse_amount($myconfig, $form->{"linetotal"}->[$i]);
247
        $nodiscount_sum += $form->parse_amount($myconfig, $form->{"nodiscount_linetotal"}->[$i]);
248

  
249
        # don't parse par, we need it for each line
250
        $_ = $par;
251
        while (/<%(.*?)%>/) {
252
          substr($_, $-[0], $+[0] - $-[0]) =
253
            $self->format_string($form->{"$1"}->[$i]);
254
        }
255
        print OUT;
239
    } elsif ((substr($text, $pos + 1, 4) eq 'else') && (1 == $depth)) {
240
      if (!$var) {
241
        $self->{"error"} = '<%else%> outside of <%if%> / <%ifnot%>.';
242
        return undef;
243
      }
244

  
245
      my $block = substr($text, 0, $pos - 1);
246
      substr($text, 0, $pos - 1) = "";
247
      $text =~ s!^<\%[^\%]+\%>!!;
248
      $text = '<%if' . ($not ?  " " : "not ") . $var . '%>' . $text;
249

  
250
      return ($block, $text);
251

  
252
    } elsif (substr($text, $pos + 1, 3) eq 'end') {
253
      $depth--;
254
      if ($depth == 0) {
255
        my $block = substr($text, 0, $pos - 1);
256
        substr($text, 0, $pos - 1) = "";
257
        $text =~ s!^<\%[^\%]+\%>!!;
258

  
259
        return ($block, $text);
256 260
      }
257
      next;
258 261
    }
262
  }
259 263

  
260
    # if not comes before if!
261
    if (/\s*<%if not /) {
264
  return undef;
265
}
262 266

  
263
      # check if it is not set and display
264
      chop;
265
      s/\s*<%if not (.+?)%>/$1/;
267
sub parse_block {
268
  $main::lxdebug->enter_sub();
266 269

  
267
      unless ($form->{$_}) {
268
        while ($_ = shift) {
269
          last if (/\s*<%end /);
270
  my ($self, $contents, @indices) = @_;
270 271

  
271
          # store line in $par
272
          $par .= $_;
273
        }
272
  my $new_contents = "";
274 273

  
275
        $_ = $par;
274
  while ($contents ne "") {
275
    my $pos_if = index($contents, '<%if');
276
    my $pos_foreach = index($contents, '<%foreach');
276 277

  
277
      } else {
278
        while ($_ = shift) {
279
          last if (/\s*<%end /);
280
        }
281
        next;
282
      }
278
    if ((-1 == $pos_if) && (-1 == $pos_foreach)) {
279
      $new_contents .= $self->substitute_vars($contents, @indices);
280
      last;
283 281
    }
284 282

  
285
    if (/\s*<%if /) {
283
    if ((-1 == $pos_if) || ((-1 != $pos_foreach) && ($pos_if > $pos_foreach))) {
284
      $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_foreach), @indices);
285
      substr($contents, 0, $pos_foreach) = "";
286 286

  
287
      # check if it is set and display
288
      chop;
289
      s/\s*<%if (.+?)%>/$1/;
287
      if ($contents !~ m|^<\%foreach (.*?)\%>|) {
288
        $self->{"error"} = "Malformed <\%foreach\%>.";
289
        $main::lxdebug->leave_sub();
290
        return undef;
291
      }
290 292

  
291
      if ($form->{$_}) {
292
        while ($_ = shift) {
293
          last if (/\s*<%end /);
293
      my $var = $1;
294 294

  
295
          # store line in $par
296
          $par .= $_;
297
        }
295
      substr($contents, 0, length($&)) = "";
298 296

  
299
        $_ = $par;
297
      my $block;
298
      ($block, $contents) = $self->find_end($contents);
299
      if (!$block) {
300
        $self->{"error"} = "Unclosed <\%foreach\%>." unless ($self->{"error"});
301
        $main::lxdebug->leave_sub();
302
        return undef;
303
      }
300 304

  
301
      } else {
302
        while ($_ = shift) {
303
          last if (/\s*<%end /);
305
      my $new_text = $self->parse_foreach($var, $block, "", "", @indices);
306
      if (!defined($new_text)) {
307
        $main::lxdebug->leave_sub();
308
        return undef;
309
      }
310
      $new_contents .= $new_text;
311

  
312
    } else {
313
      $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
314
      substr($contents, 0, $pos_if) = "";
315

  
316
      if ($contents !~ m|^<\%if\s*(not)?\s+(.*?)\%>|) {
317
        $self->{"error"} = "Malformed <\%if\%>.";
318
        $main::lxdebug->leave_sub();
319
        return undef;
320
      }
321

  
322
      my ($not, $var) = ($1, $2);
323

  
324
      substr($contents, 0, length($&)) = "";
325

  
326
      ($block, $contents) = $self->find_end($contents, 0, $var, $not);
327
      if (!$block) {
328
        $self->{"error"} = "Unclosed <\%if${not}\%>." unless ($self->{"error"});
329
        $main::lxdebug->leave_sub();
330
        return undef;
331
      }
332

  
333
      my $value = $self->{"form"}->{$var};
334
      for (my $i = 0; $i < scalar(@indices); $i++) {
335
        last unless (ref($value) eq "ARRAY");
336
        $value = $value->[$indices[$i]];
337
      }
338

  
339
      if (($not && !$value) || (!$not && $value)) {
340
        my $new_text = $self->parse_block($block, @indices);
341
        if (!defined($new_text)) {
342
          $main::lxdebug->leave_sub();
343
          return undef;
304 344
        }
305
        next;
345
        $new_contents .= $new_text;
306 346
      }
307 347
    }
348
  }
308 349

  
309
    # check for <%include filename%>
310
    if (/\s*<%include /) {
350
  $main::lxdebug->leave_sub();
311 351

  
312
      # get the filename
313
      chomp $var;
314
      $var =~ s/\s*<%include (.+?)%>/$1/;
352
  return $new_contents;
353
}
315 354

  
316
      # mangle filename
317
      $var =~ s/(\/|\.\.)//g;
355
sub parse {
356
  my $self = $_[0];
357
  local *OUT = $_[1];
358
  my $form = $self->{"form"};
318 359

  
319
      # prevent the infinite loop!
320
      next if ($form->{"$var"});
360
  # Do we have to run LaTeX two times? This is needed if
361
  # the template contains page references.
362
  my $two_passes = 0;
321 363

  
322
      open(INC, $form->{templates} . "/$var")
323
        or $form->error($self->cleanup . $form->{templates} . "/$var : $!");
324
      unshift(@_, <INC>);
325
      close(INC);
364
  if (!open(IN, "$form->{templates}/$form->{IN}")) {
365
    $self->{"error"} = "$!";
366
    return 0;
367
  }
368
  @_ = <IN>;
369
  close(IN);
326 370

  
327
      $form->{"$var"} = 1;
371
  my $contents = join("", @_);
372
  $two_passes = 1 if ($contents =~ /\\pageref/s);
328 373

  
329
      next;
330
    }
374
  # detect pagebreak block and its parameters
375
  if ($contents =~ /<%pagebreak\s+(\d+)\s+(\d+)\s+(\d+)\s*%>(.*?)<%end(\s*pagebreak)?%>/s) {
376
    $self->{"chars_per_line"} = $1;
377
    $self->{"lines_on_first_page"} = $2;
378
    $self->{"lines_on_second_page"} = $3;
379
    $self->{"pagebreak_block"} = $4;
331 380

  
332
    while (/<%(.*?)%>/) {
333
      substr($_, $-[0], $+[0] - $-[0]) = $self->format_string($form->{$1});
334
    }
335
    print OUT;
381
    substr($contents, length($`), length($&)) = "";
336 382
  }
337 383

  
384
  $self->{"forced_pagebreaks"} = [];
385

  
386
  my $new_contents = $self->parse_block($contents);
387
  if (!defined($new_contents)) {
388
    $main::lxdebug->leave_sub();
389
    return 0;
390
  }
391

  
392
  print(OUT $new_contents);
393

  
338 394
  if ($form->{"format"} =~ /postscript/i) {
339 395
    return $self->convert_to_postscript($two_passes);
340 396
  } elsif ($form->{"format"} =~ /pdf/i) {
......
473 529

  
474 530
  # Allow some HTML markup to be converted into the output format's
475 531
  # corresponding markup code, e.g. bold or italic.
476
  my @markup_replace = ('b', 'i', 's', 'u');
532
  my @markup_replace = ('b', 'i', 's', 'u', 'sub', 'sup');
477 533

  
478 534
  foreach my $key (@markup_replace) {
479 535
    $variable =~ s/\&lt;(\/?)${key}\&gt;/<$1${key}>/g;
......
483 539
}
484 540

  
485 541
sub get_mime_type() {
486
  return "text/html";
542
  my ($self) = @_;
543

  
544
  if ($self->{"form"}->{"format"} =~ /postscript/i) {
545
    return "application/postscript";
546
  } elsif ($self->{"form"}->{"format"} =~ /pdf/i) {
547
    return "application/pdf";
548
  } else {
549
    return "text/html";
550
  }
487 551
}
488 552

  
489 553
sub uses_temp_file {
490
  return 0;
554
  my ($self) = @_;
555

  
556
  if ($self->{"form"}->{"format"} =~ /postscript/i) {
557
    return 1;
558
  } elsif ($self->{"form"}->{"format"} =~ /pdf/i) {
559
    return 1;
560
  } else {
561
    return 0;
562
  }
563
}
564

  
565
sub convert_to_postscript {
566
  my ($self) = @_;
567
  my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
568

  
569
  # Convert the HTML file to postscript
570

  
571
  if (!chdir("$userspath")) {
572
    $self->{"error"} = "chdir : $!";
573
    $self->cleanup();
574
    return 0;
575
  }
576

  
577
  $form->{"tmpfile"} =~ s/$userspath\///g;
578
  my $psfile = $form->{"tmpfile"};
579
  $psfile =~ s/.html/.ps/;
580
  if ($psfile eq $form->{"tmpfile"}) {
581
    $psfile .= ".ps";
582
  }
583

  
584
  system("html2ps -f html2ps-config < $form->{tmpfile} > $psfile");
585
  if ($?) {
586
    $self->{"error"} = $form->cleanup();
587
    $self->cleanup();
588
    return 0;
589
  }
590

  
591
  $form->{"tmpfile"} = $psfile;
592

  
593
  $self->cleanup();
594

  
595
  return 1;
491 596
}
492 597

  
598
sub convert_to_pdf {
599
  my ($self) = @_;
600
  my ($form, $userspath) = ($self->{"form"}, $self->{"userspath"});
601

  
602
  # Convert the HTML file to PDF
603

  
604
  if (!chdir("$userspath")) {
605
    $self->{"error"} = "chdir : $!";
606
    $self->cleanup();
607
    return 0;
608
  }
609

  
610
  $form->{"tmpfile"} =~ s/$userspath\///g;
611
  my $pdffile = $form->{"tmpfile"};
612
  $pdffile =~ s/.html/.pdf/;
613
  if ($pdffile eq $form->{"tmpfile"}) {
614
    $pdffile .= ".pdf";
615
  }
616

  
617
  system("html2ps -f html2ps-config < $form->{tmpfile} | ps2pdf - $pdffile");
618
  if ($?) {
619
    $self->{"error"} = $form->cleanup();
620
    $self->cleanup();
621
    return 0;
622
  }
623

  
624
  $form->{"tmpfile"} = $pdffile;
625

  
626
  $self->cleanup();
627

  
628
  return 1;
629
}
493 630

  
494 631

  
495 632
####
......
498 635

  
499 636
package OpenDocumentTemplate;
500 637

  
638
use POSIX 'setsid';
501 639
use vars qw(@ISA);
502 640

  
503 641
use Cwd;
......
560 698
  }
561 699

  
562 700
  for (my $i = 0; $i < scalar(@{$ary}); $i++) {
701
    $form->{"__first__"} = $i == 0;
702
    $form->{"__last__"} = ($i + 1) == scalar(@{$ary});
703
    $form->{"__odd__"} = (($i + 1) % 2) == 1;
704
    $form->{"__counter__"} = $i + 1;
563 705
    my $new_text = $self->parse_block($text, (@indices, $i));
564 706
    return undef unless (defined($new_text));
565 707
    $new_contents .= $start_tag . $new_text . $end_tag;
566 708
  }
709
  map({ delete($form->{"__${_}__"}); } qw(first last odd counter));
567 710

  
568 711
  return $new_contents;
569 712
}
570 713

  
714
sub find_end {
715
  my ($self, $text, $pos, $var, $not) = @_;
716

  
717
  my $depth = 1;
718
  $pos = 0 unless ($pos);
719

  
720
  while ($pos < length($text)) {
721
    $pos++;
722

  
723
    next if (substr($text, $pos - 1, 5) ne '&lt;%');
724

  
725
    if ((substr($text, $pos + 4, 2) eq 'if') || (substr($text, $pos + 4, 3) eq 'for')) {
726
      $depth++;
727

  
728
    } elsif ((substr($text, $pos + 4, 4) eq 'else') && (1 == $depth)) {
729
      if (!$var) {
730
        $self->{"error"} = '<%else%> outside of <%if%> / <%ifnot%>.';
731
        return undef;
732
      }
733

  
734
      my $block = substr($text, 0, $pos - 1);
735
      substr($text, 0, $pos - 1) = "";
736
      $text =~ s!^\&lt;\%[^\%]+\%\&gt;!!;
737
      $text = '&lt;%if' . ($not ?  " " : "not ") . $var . '%&gt;' . $text;
738

  
739
      return ($block, $text);
740

  
741
    } elsif (substr($text, $pos + 4, 3) eq 'end') {
742
      $depth--;
743
      if ($depth == 0) {
744
        my $block = substr($text, 0, $pos - 1);
745
        substr($text, 0, $pos - 1) = "";
746
        $text =~ s!^\&lt;\%[^\%]+\%\&gt;!!;
747

  
748
        return ($block, $text);
749
      }
750
    }
751
  }
752

  
753
  return undef;
754
}
755

  
571 756
sub parse_block {
572 757
  $main::lxdebug->enter_sub();
573 758

  
......
590 775
        if ($table_row =~ m|\&lt;\%foreachrow\s+(.*?)\%\&gt;|) {
591 776
          my $var = $1;
592 777

  
593
          $table_row =~ s|\&lt;\%foreachrow .*?\%\&gt;||g;
594
          $table_row =~ s!\&lt;\%end(for|foreach)?row\s+${var}\%\&gt;!!g;
778
          substr($table_row, length($`), length($&)) = "";
779

  
780
          my ($t1, $t2) = $self->find_end($table_row, length($`));
781
          if (!$t1) {
782
            $self->{"error"} = "Unclosed <\%foreachrow\%>." unless ($self->{"error"});
783
            $main::lxdebug->leave_sub();
784
            return undef;
785
          }
595 786

  
596
          my $new_text = $self->parse_foreach($var, $table_row, $tag, $end_tag, @indices);
597
          return undef unless (defined($new_text));
787
          my $new_text = $self->parse_foreach($var, $t1 . $t2, $tag, $end_tag, @indices);
788
          if (!defined($new_text)) {
789
            $main::lxdebug->leave_sub();
790
            return undef;
791
          }
598 792
          $new_contents .= $new_text;
599 793

  
600 794
        } else {
601 795
          my $new_text = $self->parse_block($table_row, @indices);
602
          return undef unless (defined($new_text));
796
          if (!defined($new_text)) {
797
            $main::lxdebug->leave_sub();
798
            return undef;
799
          }
603 800
          $new_contents .= $tag . $new_text . $end_tag;
604 801
        }
605 802

  
......
634 831

  
635 832
        substr($contents, 0, length($&)) = "";
636 833

  
637
        if ($contents !~ m!\&lt;\%end\s*?(for)?\s+${var}\%\&gt;!) {
638
          $self->{"error"} = "Unclosed <\%foreach\%>.";
834
        my $block;
835
        ($block, $contents) = $self->find_end($contents);
836
        if (!$block) {
837
          $self->{"error"} = "Unclosed <\%foreach\%>." unless ($self->{"error"});
639 838
          $main::lxdebug->leave_sub();
640 839
          return undef;
641 840
        }
642 841

  
643
        substr($contents, 0, length($`) + length($&)) = "";
644
        my $new_text = $self->parse_foreach($var, $`, "", "", @indices);
645
        return undef unless (defined($new_text));
842
        my $new_text = $self->parse_foreach($var, $block, "", "", @indices);
843
        if (!defined($new_text)) {
844
          $main::lxdebug->leave_sub();
845
          return undef;
846
        }
646 847
        $new_contents .= $new_text;
647 848

  
648 849
      } else {
649 850
        $new_contents .= $self->substitute_vars(substr($contents, 0, $pos_if), @indices);
650 851
        substr($contents, 0, $pos_if) = "";
651 852

  
652
        if ($contents !~ m|^\&lt;\%if(not)?\s+(.*?)\%\&gt;|) {
853
        if ($contents !~ m|^\&lt;\%if\s*(not)?\s+(.*?)\%\&gt;|) {
653 854
          $self->{"error"} = "Malformed <\%if\%>.";
654 855
          $main::lxdebug->leave_sub();
655 856
          return undef;
......
659 860

  
660 861
        substr($contents, 0, length($&)) = "";
661 862

  
662
        if ($contents !~ m!\&lt;\%endif${not}\s+${var}\%\&gt;!) {
663
          $self->{"error"} = "Unclosed <\%if${not}\%>.";
863
        ($block, $contents) = $self->find_end($contents, 0, $var, $not);
864
        if (!$block) {
865
          $self->{"error"} = "Unclosed <\%if${not}\%>." unless ($self->{"error"});
664 866
          $main::lxdebug->leave_sub();
665 867
          return undef;
666 868
        }
667 869

  
668
        substr($contents, 0, length($`) + length($&)) = "";
669

  
670 870
        my $value = $self->{"form"}->{$var};
671 871
        for (my $i = 0; $i < scalar(@indices); $i++) {
672 872
          last unless (ref($value) eq "ARRAY");
......
674 874
        }
675 875

  
676 876
        if (($not && !$value) || (!$not && $value)) {
677
          my $new_text = $self->parse_block($`, @indices);
678
          return undef unless (defined($new_text));
877
          my $new_text = $self->parse_block($block, @indices);
878
          if (!defined($new_text)) {
879
            $main::lxdebug->leave_sub();
880
            return undef;
881
          }
679 882
          $new_contents .= $new_text;
680 883
        }
681 884
      }
682 885
    }
683 886
  }
684 887

  
888
  $main::lxdebug->leave_sub();
889

  
685 890
  return $new_contents;
686 891
}
687 892

  
......
694 899

  
695 900
  close(OUT);
696 901

  
902
  my $file_name;
903
  if ($form->{"IN"} =~ m|^/|) {
904
    $file_name = $form->{"IN"};
905
  } else {
906
    $file_name = $form->{"templates"} . "/" . $form->{"IN"};
907
  }
908

  
697 909
  my $zip = Archive::Zip->new();
698
  if (Archive::Zip::AZ_OK != $zip->read("$form->{templates}/$form->{IN}")) {
910
  if (Archive::Zip::AZ_OK != $zip->read($file_name)) {
699 911
    $self->{"error"} = "File not found/is not a OpenDocument file.";
700 912
    $main::lxdebug->leave_sub();
701 913
    return 0;
......
720 932
</style:style>
721 933
<style:style style:name="TLXO${rnd}STRIKETHROUGH" style:family="text">
722 934
<style:text-properties style:text-line-through-style="solid"/>
723
</style:style>|;
935
</style:style>
936
<style:style style:name="TLXO${rnd}SUPER" style:family="text">
937
<style:text-properties style:text-position="super 58%"/>
938
</style:style>
939
<style:style style:name="TLXO${rnd}SUB" style:family="text">
940
<style:text-properties style:text-position="sub 58%"/>
941
</style:style>
942
|;
724 943

  
725 944
  $contents =~ s|</office:automatic-styles>|${new_styles}</office:automatic-styles>|;
726 945
  $contents =~ s|[\n\r]||gm;
727 946

  
728 947
  my $new_contents = $self->parse_block($contents);
729
  return 0 unless (defined($new_contents));
948
  if (!defined($new_contents)) {
949
    $main::lxdebug->leave_sub();
950
    return 0;
951
  }
730 952

  
731 953
#   $new_contents =~ s|>|>\n|g;
732 954

  
733 955
  $zip->contents("content.xml", $new_contents);
956

  
957
  my $styles = $zip->contents("styles.xml");
958
  if ($contents) {
959
    my $new_styles = $self->parse_block($styles);
960
    if (!defined($new_contents)) {
961
      $main::lxdebug->leave_sub();
962
      return 0;
963
    }
964
    $zip->contents("styles.xml", $new_styles);
965
  }
966

  
734 967
  $zip->writeToFileNamed($form->{"tmpfile"}, 1);
735 968

  
736 969
  my $res = 1;
......
742 975
  return $res;
743 976
}
744 977

  
978
sub is_xvfb_running {
979
  $main::lxdebug->enter_sub();
980

  
981
  my ($self) = @_;
982

  
983
  local *IN;
984
  my $dfname = $self->{"userspath"} . "/xvfb_display";
985
  my $display;
986

  
987
  $main::lxdebug->message(LXDebug::DEBUG2, "    Looking for $dfname\n");
988
  if ((-f $dfname) && open(IN, $dfname)) {
989
    my $pid = <IN>;
990
    chomp($pid);
991
    $display = <IN>;
992
    chomp($display);
993
    my $xauthority = <IN>;
994
    chomp($xauthority);
995
    close(IN);
996

  
997
    $main::lxdebug->message(LXDebug::DEBUG2, "      found with $pid and $display\n");
998

  
999
    if ((! -d "/proc/$pid") || !open(IN, "/proc/$pid/cmdline")) {
1000
      $main::lxdebug->message(LXDebug::DEBUG2, "  no/wrong process #1\n");
1001
      unlink($dfname, $xauthority);
1002
      $main::lxdebug->leave_sub();
1003
      return undef;
1004
    }
1005
    my $line = <IN>;
1006
    close(IN);
1007
    if ($line !~ /xvfb/i) {
1008
      $main::lxdebug->message(LXDebug::DEBUG2, "      no/wrong process #2\n");
1009
      unlink($dfname, $xauthority);
1010
      $main::lxdebug->leave_sub();
1011
      return undef;
1012
    }
1013

  
1014
    $ENV{"XAUTHORITY"} = $xauthority;
1015
    $ENV{"DISPLAY"} = $display;
1016
  } else {
1017
    $main::lxdebug->message(LXDebug::DEBUG2, "      not found\n");
1018
  }
1019

  
1020
  $main::lxdebug->leave_sub();
1021

  
1022
  return $display;
1023
}
1024

  
1025
sub spawn_xvfb {
1026
  $main::lxdebug->enter_sub();
1027

  
1028
  my ($self) = @_;
1029

  
1030
  $main::lxdebug->message(LXDebug::DEBUG2, "spawn_xvfb()\n");
1031

  
1032
  my $display = $self->is_xvfb_running();
1033

  
1034
  if ($display) {
1035
    $main::lxdebug->leave_sub();
1036
    return $display;
1037
  }
1038

  
1039
  $display = 99;
1040
  while ( -f "/tmp/.X${display}-lock") {
1041
    $display++;
1042
  }
1043
  $display = ":${display}";
1044
  $main::lxdebug->message(LXDebug::DEBUG2, "  display $display\n");
1045

  
1046
  my $mcookie = `mcookie`;
1047
  die("Installation error: mcookie not found.") if ($? != 0);
1048
  chomp($mcookie);
1049

  
1050
  $main::lxdebug->message(LXDebug::DEBUG2, "  mcookie $mcookie\n");
1051

  
1052
  my $xauthority = "/tmp/.Xauthority-" . $$ . "-" . time() . "-" . int(rand(9999999));
1053
  $ENV{"XAUTHORITY"} = $xauthority;
1054

  
1055
  $main::lxdebug->message(LXDebug::DEBUG2, "  xauthority $xauthority\n");
1056

  
1057
  system("xauth add \"${display}\" . \"${mcookie}\"");
1058
  if ($? != 0) {
1059
    $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started (xauth: $!)";
1060
    $main::lxdebug->leave_sub();
1061
    return undef;
1062
  }
1063

  
1064
  $main::lxdebug->message(LXDebug::DEBUG2, "  about to fork()\n");
1065

  
1066
  my $pid = fork();
1067
  if (0 == $pid) {
1068
    $main::lxdebug->message(LXDebug::DEBUG2, "  Child execing\n");
1069
    exec($main::xvfb_bin, $display, "-screen", "0", "640x480x8", "-nolisten", "tcp");
1070
  }
1071
  sleep(3);
1072
  $main::lxdebug->message(LXDebug::DEBUG2, "  parent dont sleeping\n");
1073

  
1074
  local *OUT;
1075
  my $dfname = $self->{"userspath"} . "/xvfb_display";
1076
  if (!open(OUT, ">$dfname")) {
1077
    $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started ($dfname: $!)";
1078
    unlink($xauthority);
1079
    kill($pid);
1080
    $main::lxdebug->leave_sub();
1081
    return undef;
1082
  }
1083
  print(OUT "$pid\n$display\n$xauthority\n");
1084
  close(OUT);
1085

  
1086
  $main::lxdebug->message(LXDebug::DEBUG2, "  parent re-testing\n");
1087

  
1088
  if (!$self->is_xvfb_running()) {
1089
    $self->{"error"} = "Conversion to PDF failed because OpenOffice could not be started.";
1090
    unlink($xauthority, $dfname);
1091
    kill($pid);
1092
    $main::lxdebug->leave_sub();
1093
    return undef;
1094
  }
1095

  
1096
  $main::lxdebug->message(LXDebug::DEBUG2, "  spawn OK\n");
1097

  
1098
  $main::lxdebug->leave_sub();
1099

  
1100
  return $display;
1101
}
1102

  
1103
sub is_openoffice_running {
1104
  $main::lxdebug->enter_sub();
1105

  
1106
  system("./scripts/oo-uno-test-conn.py $main::openofficeorg_daemon_port " .
1107
         "> /dev/null 2> /dev/null");
1108
  my $res = $? == 0;
1109
  $main::lxdebug->message(LXDebug::DEBUG2, "  is_openoffice_running(): $?\n");
1110

  
1111
  $main::lxdebug->leave_sub();
1112

  
1113
  return $res;
1114
}
1115

  
1116
sub spawn_openoffice {
1117
  $main::lxdebug->enter_sub();
1118

  
1119
  my ($self) = @_;
1120

  
1121
  $main::lxdebug->message(LXDebug::DEBUG2, "spawn_openoffice()\n");
1122

  
1123
  my ($try, $spawned_oo, $res);
1124

  
1125
  $res = 0;
1126
  for ($try = 0; $try < 15; $try++) {
1127
    if ($self->is_openoffice_running()) {
1128
      $res = 1;
1129
      last;
1130
    }
1131

  
1132
    if (!$spawned_oo) {
1133
      my $pid = fork();
1134
      if (0 == $pid) {
1135
        $main::lxdebug->message(LXDebug::DEBUG2, "  Child daemonizing\n");
1136
        chdir('/');
1137
        open(STDIN, '/dev/null');
1138
        open(STDOUT, '>/dev/null');
1139
        my $new_pid = fork();
1140
        exit if ($new_pid);
1141
        my $ssres = setsid();
1142
        $main::lxdebug->message(LXDebug::DEBUG2, "  Child execing\n");
1143
        my @cmdline = ($main::openofficeorg_writer_bin,
1144
                       "-minimized", "-norestore", "-nologo", "-nolockcheck",
1145
                       "-headless",
1146
                       "-accept=socket,host=localhost,port=" .
1147
                       $main::openofficeorg_daemon_port . ";urp;");
1148
        exec(@cmdline);
1149
      }
1150

  
1151
      $main::lxdebug->message(LXDebug::DEBUG2, "  Parent after fork\n");
1152
      $spawned_oo = 1;
1153
      sleep(3);
1154
    }
1155

  
1156
    sleep($try >= 5 ? 2 : 1);
1157
  }
1158

  
1159
  if (!$res) {
1160
    $self->{"error"} = "Conversion from OpenDocument to PDF failed because " .
1161
      "OpenOffice could not be started.";
1162
  }
1163

  
1164
  $main::lxdebug->leave_sub();
1165

  
1166
  return $res;
1167
}
1168

  
745 1169
sub convert_to_pdf {
1170
  $main::lxdebug->enter_sub();
1171

  
746 1172
  my ($self) = @_;
747 1173

  
748 1174
  my $form = $self->{"form"};
......
759 1185
    $ENV{'HOME'} = getcwd() . "/" . $self->{"userspath"};
760 1186
  }
761 1187

  
762
  my @cmdline = ($main::xvfb_run_bin, $main::openofficeorg_writer_bin,
763
                 "-minimized", "-norestore", "-nologo", "-nolockcheck",
764
                 "-headless",
765
                 "file:${filename}.odt",
766
                 "macro://" . (split('/', $filename))[-1] .
767
                 "/Standard.Conversion.ConvertSelfToPDF()");
1188
  if (!$self->spawn_xvfb()) {
1189
    $main::lxdebug->leave_sub();
1190
    return 0;
1191
  }
1192

  
1193
  my @cmdline;
1194
  if (!$main::openofficeorg_daemon) {
1195
    @cmdline = ($main::openofficeorg_writer_bin,
1196
                "-minimized", "-norestore", "-nologo", "-nolockcheck",
1197
                "-headless",
1198
                "file:${filename}.odt",
1199
                "macro://" . (split('/', $filename))[-1] .
1200
                "/Standard.Conversion.ConvertSelfToPDF()");
1201
  } else {
1202
    if (!$self->spawn_openoffice()) {
1203
      $main::lxdebug->leave_sub();
1204
      return 0;
1205
    }
1206

  
1207
    @cmdline = ("./scripts/oo-uno-convert-pdf.py",
1208
                $main::openofficeorg_daemon_port,
1209
                "${filename}.odt");
1210
  }
768 1211

  
769 1212
  system(@cmdline);
770 1213

  
......
793 1236
  my $iconv = $self->{"iconv"};
794 1237

  
795 1238
  my %replace =
796
    ('order' => ['<', '>', '"', "'",
1239
    ('order' => ['&', '<', '>', '"', "'",
797 1240
                 '\x80',        # Euro
798
                 quotemeta("\n"), quotemeta("\r"), '&'],
1241
                 quotemeta("\n"), quotemeta("\r")],
799 1242
     '<'             => '&lt;',
800 1243
     '>'             => '&gt;',
801 1244
     '"'             => '&quot;',
802 1245
     "'"             => '&apos;',
803
     '&'             => '&quot;',
1246
     '&'             => '&amp;',
804 1247
     '\x80'          => chr(0xa4), # Euro
805 1248
     quotemeta("\n") => '<text:line-break/>',
806 1249
     quotemeta("\r") => '',
......
812 1255
  # corresponding markup code, e.g. bold or italic.
813 1256
  my $rnd = $self->{"rnd"};
814 1257
  my %markup_replace = ("b" => "BOLD", "i" => "ITALIC", "s" => "STRIKETHROUGH",
815
                        "u" => "UNDERLINE");
1258
                        "u" => "UNDERLINE", "sup" => "SUPER", "sub" => "SUB");
816 1259

  
817 1260
  foreach my $key (keys(%markup_replace)) {
818 1261
    my $value = $markup_replace{$key};
819
    $variable =~ s|\&lt;${key}\&gt;|<text:span text:style-name=\"TLXO${rnd}${value}\">|g;
820
    $variable =~ s|\&lt;/${key}\&gt;|</text:span>|g;
1262
    $variable =~ s|\&lt;${key}\&gt;|<text:span text:style-name=\"TLXO${rnd}${value}\">|gi;
1263
    $variable =~ s|\&lt;/${key}\&gt;|</text:span>|gi;
821 1264
  }
822 1265

  
823 1266
  return $iconv->convert($variable);
users/html2ps-config
1
@html2ps {
2
  option {
3
    titlepage: 0
4
    hyphenate: 0
5
    colour: 1
6
  }
7
  break-table: 1
8
}
9

  
10
@page {
11
  margin-top: 1.5cm
12
  margin-left: 1.5cm
13
  margin-bottom: 1.5cm
14
  margin-right: 1.5cm
15
}
16

  
17
BODY {
18
  font-family: Helvetica
19
  font-size: 8pt
20
}
21

  
22
H1 { font-size: 10pt }
23
H2 { font-size: 10pt }
24
H3 { font-size: 10pt }
25
H4 { font-size: 10pt }
26
H5 { font-size: 10pt }
27
H6 { font-size: 10pt }

Auch abrufbar als: Unified diff