]> git.lyx.org Git - lyx.git/blob - development/autotests/useSystemFonts.pl
ctests-costs-benefits: define false positive
[lyx.git] / development / autotests / useSystemFonts.pl
1 #! /usr/bin/env perl
2 # -*- mode: perl; -*-
3 #
4 # file useSystemFonts.pl
5 # 1.) Copies lyx-files to another location
6 # 2.) While copying,
7 #   2a.) searches for relative references to files and
8 #        replaces them with absolute ones
9 #   2b.) Changes default fonts to use non-tex-fonts
10 #
11 # Syntax: perl useSystemFonts.pl sourceFile destFile format
12 # Each param represents a path to a file
13 # sourceFile: full path to a lyx file
14 # destFile: destination path
15 #   Each subdocument will be copied into a subdirectory of dirname(destFile)
16 # format: any string of the form '[a-zA-Z0-9]+', e.g. pdf5
17 #
18 # This file is free software; you can redistribute it and/or
19 # modify it under the terms of the GNU General Public
20 # License as published by the Free Software Foundation; either
21 # version 2 of the License, or (at your option) any later version.
22 #
23 # This software is distributed in the hope that it will be useful,
24 # but WITHOUT ANY WARRANTY; without even the implied warranty of
25 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26 # General Public License for more details.
27 #
28 # You should have received a copy of the GNU General Public
29 # License along with this software; if not, write to the Free Software
30 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31 #
32 # Copyright (c) 2013 Kornel Benko <kornel@lyx.org>
33 #           (c) 2013 Scott Kostyshak <skotysh@lyx.org>
34
35 use strict;
36
37 BEGIN {
38   use File::Spec;
39   my $p = File::Spec->rel2abs( __FILE__ );
40   $p =~ s/[\/\\]?[^\/\\]+$//;
41   unshift(@INC, "$p");
42 }
43 use File::Basename;
44 use File::Path;
45 use File::Copy "cp";
46 use File::Temp qw/ :POSIX /;
47 use lyxStatus;
48
49 # Prototypes
50 sub printCopiedDocuments($);
51 sub interpretedCopy($$$$);
52 sub copyFoundSubdocuments($);
53 sub copyJob($$);
54 sub isrelativeFix($$$);
55 sub isrelative($$$);
56 sub createTemporaryFileName($$$);
57 sub copyJobPending($$);
58 sub addNewJob($$$$$);
59 sub addFileCopyJob($$$$$);
60 sub getNewNameOf($$);
61 sub getlangs($$);
62 sub simplifylangs($);
63 sub getLangEntry();
64
65 # convert lyx file to be compilable with xetex
66
67 my ($source, $dest, $format, $fontT, $encodingT, $languageFile, $rest) = @ARGV;
68 my %encodings = ();      # Encoding with TeX fonts, depending on language tag
69
70 diestack("Too many arguments") if (defined($rest));
71 diestack("Sourcefilename not defined") if (! defined($source));
72 diestack("Destfilename not defined") if (! defined($dest));
73 diestack("Format (e.g. pdf4) not defined") if (! defined($format));
74 diestack("Font type (e.g. texF) not defined") if (! defined($fontT));
75 diestack("Encoding (e.g. ascii) not defined") if (! defined($encodingT));
76
77 $source = File::Spec->rel2abs($source);
78 $dest = File::Spec->rel2abs($dest);
79
80 my %font = ();
81 my $lang = "main";
82 if ($source =~ /\/([a-z][a-z](_[A-Z][A-Z])?)[\/_]/) {
83   $lang = $1;
84 }
85
86 my $inputEncoding = undef;
87 if ($fontT eq "systemF") {
88 }
89 elsif ($encodingT ne "default") {
90   # set input encoding to the requested value
91   $inputEncoding = {
92         "search" => '.*', # this will be substituted from '\inputencoding'-line
93         "out" => $encodingT,
94     };
95 }
96 elsif (0) { # set to '1' to enable setting of inputencoding
97   # use tex font here
98   my %encoding = ();
99   if (defined($languageFile)) {
100     # The 2 lines below does not seem to have any effect
101     #&getlangs($languageFile, \%encoding);
102     #&simplifylangs(\%encoding);
103   }
104   if ($format =~ /^(pdf4)$/) { # xelatex
105     # set input encoding to 'ascii' always
106     $inputEncoding = {
107       "search" => '.*', # this will be substituted from '\inputencoding'-line
108       "out" => "ascii",
109     };
110   }
111   elsif ($format =~ /^(dvi3|pdf5)$/) { # (dvi)?lualatex
112     # when to set input encoding to 'ascii'?
113     if (defined($encoding{$lang})) {
114       $inputEncoding = {
115         "search" => '.*', # this will be substituted from '\inputencoding'-line
116         "out" => $encoding{$lang},
117       };
118     }
119   }
120 }
121
122 my $sourcedir = dirname($source);
123 my $destdir = dirname($dest);
124 if (! -d $destdir) {
125   diestack("could not make dir \"$destdir\"") if (! mkpath $destdir);
126 }
127
128 my $destdirOfSubdocuments;
129 {
130   my ($name, $pat, $suffix) = fileparse($source, qr/\.[^.]*/);
131   my $ext = $format . "-$lang";
132   $name =~ s/[%_]/-/g;
133   $destdirOfSubdocuments = "$destdir/tmp-$ext" . "-$name"; # Global var, something TODO here
134 }
135
136 if(-d $destdirOfSubdocuments) {
137   rmtree($destdirOfSubdocuments);
138 }
139 mkpath($destdirOfSubdocuments); #  for possibly included files
140
141 my %IncludedFiles = ();
142 my %type2hash = (
143   "copy_only" => "copyonly",
144   "interpret" => "interpret");
145
146 addNewJob($source, $dest, "interpret", {}, \%IncludedFiles);
147
148 copyFoundSubdocuments(\%IncludedFiles);
149
150 #printCopiedDocuments(\%IncludedFiles);
151
152 exit(0);
153 ###########################################################
154
155 sub printCopiedDocuments($)
156 {
157   my ($rFiles) = @_;
158   for my $k (keys %{$rFiles}) {
159     my $rJob = $rFiles->{$k};
160     for my $j ( values %type2hash) {
161       if (defined($rJob->{$j})) {
162         print "$j: $k->$rJob->{$j}, " . $rJob->{$j . "copied"} . "\n";
163       }
164     }
165   }
166 }
167
168 sub interpretedCopy($$$$)
169 {
170   my ($source, $dest, $destdirOfSubdocuments, $rFiles) = @_;
171   my $sourcedir = dirname($source);
172   my $res = 0;
173
174   diestack("could not read \"$source\"") if (!open(FI, $source));
175   diestack("could not write \"$dest\"") if (! open(FO, '>', $dest));
176
177   initLyxStack(\%font, $fontT, $inputEncoding);
178
179   my $fi_line_no = 0;
180   my @path_errors = ();
181   while (my $l = <FI>) {
182     $fi_line_no += 1;
183     $l =~ s/[\n\r]+$//;
184     #chomp($l);
185     my $rStatus = checkLyxLine($l, $sourcedir);
186     if ($rStatus->{found}) {
187       my $rF = $rStatus->{result};
188       if ($rStatus->{"filetype"} eq "replace_only") {
189         # e.g. if no files involved (font chage etc)
190         $l = join('', @{$rF});
191       }
192       else {
193         my $filelist = $rStatus->{filelist};
194         my $fidx = $rStatus->{fileidx};
195         my $separator = $rStatus->{"separator"};
196         my $foundrelative = 0;
197         for my $f (@{$filelist}) {
198           my @isrel = isrelative($f,
199                                   $sourcedir,
200                                   $rStatus->{ext});
201           if ($isrel[0]) {
202             $foundrelative = 1;
203             my $ext = $isrel[1];
204             if ($rStatus->{"filetype"} eq "prefix_only") {
205               $f = getNewNameOf("$sourcedir/$f", $rFiles);
206               if ($format eq "docbook5") {
207                 $rF->[1] = join(',', @{$filelist});
208                 $l =  join('', @$rF);
209               }
210             }
211             else {
212               my ($newname, $res1);
213               my @extlist = ();
214               if (ref($rStatus->{ext}) eq "ARRAY") {
215                 my @extlist = @{$rStatus->{ext}};
216                 my $created = 0;
217                 for my $extx (@extlist) {
218                   if (-e "$sourcedir/$f$extx") {
219                     ($newname, $res1) = addFileCopyJob("$sourcedir/$f$extx",
220                                                        "$destdirOfSubdocuments",
221                                                        $rStatus->{"filetype"},
222                                                        $rFiles, $created);
223                     print "Added ($res1) file \"$sourcedir/$f$extx\" to be copied to \"$newname\"\n";
224                     if (!$created && $extx ne "") {
225                       $newname =~ s/$extx$//;
226                     }
227                     $created = 1;
228                   }
229                 }
230                 print "WARNING: No prefixed file.(" . join('|', @extlist) . ") seens to exist, at \"$source:$fi_line_no\"\n" if (!$created);
231               }
232               else {
233               ($newname, $res1) = addFileCopyJob("$sourcedir/$f$ext",
234                                                   "$destdirOfSubdocuments",
235                                                   $rStatus->{"filetype"},
236                                                    $rFiles, 0);
237               print "Added ($res1) file \"$sourcedir/$f$ext\" to be copied to \"$newname\"\n";
238               if ($ext ne "") {
239                 $newname =~ s/$ext$//;
240               }
241               }
242               $f = $newname;
243               $res += $res1;
244             }
245           }
246           else {
247             if (! -e "$f") {
248               # Non relative (e.g. with absolute path) file should exist
249               if ($rStatus->{"filetype"} eq "interpret") {
250                 # filetype::interpret should be interpreted by lyx or latex and therefore emit error
251                 # We prinnt a warning instead
252                 print "WARNING: Interpreted file \"$f\" not found, at \"$source:$fi_line_no\"\n";
253               }
254               elsif ($rStatus->{"filetype"} eq "prefix_only") {
255                 # filetype::prefix_only should be interpreted by latex
256                 print "WARNING: Prefixed file \"$f\" not found, at \"$source:$fi_line_no\"\n";
257               }
258               else {
259                 # Collect the path-error-messages
260                 push(@path_errors, "File \"$f(" . $rStatus->{"filetype"} . ")\" not found, at \"$source:$fi_line_no\"");
261               }
262             }
263           }
264         }
265         if ($foundrelative && $rStatus->{"filetype"} !~ /^(prefix_for_list|prefix_only)$/) {
266           # The result can be relative too
267           # but, since prefix_for_list does no copy, we have to use absolute paths
268           # to address files inside the source dir
269           my @rel_list = ();
270           for my $fr (@{$filelist}) {
271             push(@rel_list, File::Spec->abs2rel($fr, $destdir));
272           }
273           $rF->[$fidx] = join($separator, @rel_list);
274           $l = join('', @{$rF});
275         }
276       }
277     }
278     print FO "$l\n";
279   }
280   close(FI);
281   close(FO);
282   if (@path_errors > 0) {
283     for my $entry (@path_errors) {
284       print "ERROR: $entry\n";
285     }
286     diestack("Aborted because of path errors in \"$source\"");
287   }
288
289   closeLyxStack();
290   return($res);
291 }
292
293 sub copyFoundSubdocuments($)
294 {
295   my ($rFiles) = @_;
296   my $res = 0;
297   do {
298     $res = 0;
299     my %copylist = ();
300
301     for my $filename (keys  %{$rFiles}) {
302       next if (! copyJobPending($filename, $rFiles));
303       $copylist{$filename} = 1;
304     }
305     for my $f (keys %copylist) {
306       # Second loop needed, because here $rFiles may change
307       my ($res1, @destfiles) = copyJob($f, $rFiles);
308       $res += $res1;
309       for my $destfile (@destfiles) {
310         print "res1 = $res1 for \"$f\" to be copied to $destfile\n";
311       }
312     }
313   } while($res > 0);            #  loop, while $rFiles changed
314 }
315
316 sub copyJob($$)
317 {
318   my ($source, $rFiles) = @_;
319   my $sourcedir = dirname($source);
320   my $res = 0;
321   my @dest = ();
322
323   for my $k (values %type2hash) {
324     if ($rFiles->{$source}->{$k}) {
325       if (! $rFiles->{$source}->{$k . "copied"}) {
326         $rFiles->{$source}->{$k . "copied"} = 1;
327         my $dest = $rFiles->{$source}->{$k};
328         push(@dest, $dest);
329         if ($k eq "copyonly") {
330           diestack("Could not copy \"$source\" to \"$dest\"") if (! cp($source, $dest));
331         }
332         else {
333           interpretedCopy($source, $dest, $destdirOfSubdocuments, $rFiles);
334         }
335         $res += 1;
336       }
337     }
338   }
339   return($res, @dest);
340 }
341
342 # Trivial check
343 sub isrelativeFix($$$)
344 {
345   my ($f, $sourcedir, $ext) = @_;
346
347   return(1, $ext) if  (-e "$sourcedir/$f$ext");
348   return(0,0);
349 }
350
351 sub isrelative($$$)
352 {
353   my ($f, $sourcedir, $ext) = @_;
354
355   if (ref($ext) eq "ARRAY") {
356     for my $ext2 (@{$ext}) {
357       my @res = isrelativeFix($f, $sourcedir, $ext2);
358       if ($res[0]) {
359         return(@res);
360       }
361     }
362     return(0,0);
363   }
364   else {
365     return(isrelativeFix($f, $sourcedir, $ext));
366   }
367 }
368
369 my $oldfname = "";
370
371 sub createTemporaryFileName($$$)
372 {
373   my ($source, $destdir, $created) = @_;
374
375   # get the basename to be used for the template
376   my ($name, $path, $suffix) = fileparse($source, qr/\.[^.]*/);
377   #print "source = $source, name = $name, path = $path, suffix = $suffix\n";
378   my $template = "xx-$name" . "-";
379   my $fname;
380   if (! $created) {
381     $fname = File::Temp::tempnam($destdir, $template);
382     $oldfname = $fname;
383   }
384   else {
385     $fname = $oldfname;
386   }
387
388   # Append extension from source
389   if ($suffix ne "") {
390     $fname .= "$suffix";
391   }
392   return($fname);
393 }
394
395 # Check, if file not copied yet
396 sub copyJobPending($$)
397 {
398   my ($f, $rFiles) = @_;
399   for my $t (values %type2hash) {
400     if (defined($rFiles->{$f}->{$t})) {
401       return 1 if (! $rFiles->{$f}->{$t . "copied"});
402     }
403   }
404   return 0;
405 }
406
407 sub addNewJob($$$$$)
408 {
409   my ($source, $newname, $hashname, $rJob, $rFiles) = @_;
410
411   $rJob->{$hashname} = $newname;
412   $rJob->{$hashname . "copied"} = 0;
413   $rFiles->{$source} = $rJob;
414 }
415
416 sub addFileCopyJob($$$$$)
417 {
418   my ($source, $destdirOfSubdocuments, $filetype, $rFiles, $created) = @_;
419   my ($res, $newname) = (0, undef);
420   my $rJob = $rFiles->{$source};
421
422   my $hashname = $type2hash{$filetype};
423   if (! defined($hashname)) {
424     diestack("unknown filetype \"$filetype\"");
425   }
426   if (!defined($rJob->{$hashname})) {
427     addNewJob($source,
428                createTemporaryFileName($source, $destdirOfSubdocuments, $created),
429                "$hashname", $rJob, $rFiles);
430     $res = 1;
431   }
432   $newname = $rJob->{$hashname};
433   return($newname, $res);
434 }
435
436 sub getNewNameOf($$)
437 {
438   my ($f, $rFiles) = @_;
439   my $resultf = $f;
440
441   if (defined($rFiles->{$f})) {
442     for my $t (values %type2hash) {
443       if (defined($rFiles->{$f}->{$t})) {
444         $resultf = $rFiles->{$f}->{$t};
445         last;
446       }
447     }
448   }
449   return($resultf);
450 }
451
452 sub getlangs($$)
453 {
454   my ($languagefile, $rencoding) = @_;
455
456   if (open(FI, $languagefile)) {
457     while (my $l = <FI>) {
458       if ($l =~ /^Language/) {
459         my ($lng, $enc) = &getLangEntry();
460         if (defined($lng)) {
461           $rencoding->{$lng} = $enc;
462         }
463       }
464     }
465     close(FI);
466   }
467 }
468
469 sub simplifylangs($)
470 {
471   my ($rencoding) = @_;
472   my $base = "";
473   my $enc = "";
474   my $differ = 0;
475   my @klist = ();
476   my @klist2 = ();
477   for my $k (reverse sort keys %{$rencoding}) {
478     my @tag = split('_', $k);
479     if ($tag[0] eq $base) {
480       push(@klist, $k);
481       if ($rencoding->{$k} ne $enc) {
482         $differ = 1;
483       }
484     }
485     else {
486       # new base, check that old base was OK
487       if ($base ne "") {
488         if ($differ == 0) {
489           $rencoding->{$base} = $enc;
490           push(@klist2, @klist);
491         }
492       }
493       @klist = ($k);
494       $base = $tag[0];
495       $enc = $rencoding->{$k};
496       $differ = 0;
497     }
498   }
499   if ($base ne "") {
500     # close handling for last entry too
501     if ($differ == 0) {
502       $rencoding->{$base} = $enc;
503       push(@klist2, @klist);
504     }
505   }
506   for my $k (@klist2) {
507     delete($rencoding->{$k});
508   }
509 }
510
511 sub getLangEntry()
512 {
513   my ($lng, $enc) = (undef, undef);
514   while (my $l = <FI>) {
515     chomp($l);
516     if ($l =~ /^\s*Encoding\s+([^ ]+)\s*$/) {
517       $enc = $1;
518     }
519     elsif ($l =~ /^\s*LangCode\s+([^ ]+)\s*$/) {
520       $lng = $1;
521     }
522     elsif ($l =~ /^\s*End\s*$/) {
523       last;
524     }
525   }
526   if (defined($lng) && defined($enc)) {
527     return($lng, $enc);
528   }
529   else {
530     return(undef, undef);
531   }
532 }