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