]> git.lyx.org Git - features.git/blob - development/autotests/useSystemFonts.pl
eec406e2d56637e43c42485d6531aa1061a272f3
[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.) In order to be able to compile with luatex or xetex
10 #        changes default fonts to use non-tex-fonts instead
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 =~ /^(ru|uk|sk|el)$/) {
90     $font{roman} = "DejaVu Serif";
91     $font{sans} = "DejaVu Sans";
92     $font{typewriter} = "DejaVu Sans Mono";
93   }
94   elsif ($lang =~ /^(he)$/) {
95     $font{roman} = "FreeSans";
96     $font{sans} = "FreeSans";
97     $font{typewriter} = "FreeSans";
98   }
99   elsif ($lang eq "fa") {
100     $font{roman} = "FreeFarsi";
101     $font{sans} = "FreeFarsi";
102     $font{typewriter} = "FreeFarsi Monospace";
103   }
104   elsif ($lang eq "zh_CN") {
105     $font{roman} = "WenQuanYi Micro Hei";
106     $font{sans} = "WenQuanYi Micro Hei";
107     $font{typewriter} = "WenQuanYi Micro Hei";
108   }
109   elsif ($lang eq "ko" ) {
110     $font{roman} = "NanumGothic"; # NanumMyeongjo, NanumGothic Eco, NanumGothicCoding
111     $font{sans} = "NanumGothic";
112     $font{typewriter} = "NanumGothic";
113   }
114   elsif ($lang eq "ar" ) {
115     # available in 'fonts-sil-scheherazade' package
116     $font{roman} = "Scheherazade";
117     $font{sans} = "Scheherazade";
118     $font{typewriter} = "Scheherazade";
119   }
120   else {
121     # default system fonts
122     $font{roman} = "FreeSerif";
123     $font{sans} = "FreeSans";
124     $font{typewriter} = "FreeMono";
125   }
126 }
127 elsif ($encodingT ne "default") {
128   # set input encoding to the requested value
129   $inputEncoding = {
130         "search" => '.*', # this will be substituted from '\inputencoding'-line
131         "out" => $encodingT,
132     };
133 }
134 elsif (0) { # set to '1' to enable setting of inputencoding
135   # use tex font here
136   my %encoding = ();
137   if (defined($languageFile)) {
138     # The 2 lines below does not seem to have any effect
139     #&getlangs($languageFile, \%encoding);
140     #&simplifylangs(\%encoding);
141   }
142   if ($format =~ /^(pdf4)$/) { # xelatex
143     # set input encoding to 'ascii' always
144     $inputEncoding = {
145       "search" => '.*', # this will be substituted from '\inputencoding'-line
146       "out" => "ascii",
147     };
148   }
149   elsif ($format =~ /^(dvi3|pdf5)$/) { # (dvi)?lualatex
150     # when to set input encoding to 'ascii'?
151     if (defined($encoding{$lang})) {
152       $inputEncoding = {
153         "search" => '.*', # this will be substituted from '\inputencoding'-line
154         "out" => $encoding{$lang},
155       };
156     }
157   }
158 }
159
160 my $sourcedir = dirname($source);
161 my $destdir = dirname($dest);
162 if (! -d $destdir) {
163   diestack("could not make dir \"$destdir\"") if (! mkpath $destdir);
164 }
165
166 my $destdirOfSubdocuments;
167 {
168   my ($name, $pat, $suffix) = fileparse($source, qr/\.[^.]*/);
169   my $ext = $format . "_$lang";
170   $destdirOfSubdocuments = "$destdir/tmp_$ext" . "_$name"; # Global var, something TODO here
171 }
172
173 if(-d $destdirOfSubdocuments) {
174   rmtree($destdirOfSubdocuments);
175 }
176 mkpath($destdirOfSubdocuments); #  for possibly included files
177
178 my %IncludedFiles = ();
179 my %type2hash = (
180   "copy_only" => "copyonly",
181   "interpret" => "interpret");
182
183 addNewJob($source, $dest, "interpret", {}, \%IncludedFiles);
184
185 copyFoundSubdocuments(\%IncludedFiles);
186
187 #printCopiedDocuments(\%IncludedFiles);
188
189 exit(0);
190 ###########################################################
191
192 sub printCopiedDocuments($)
193 {
194   my ($rFiles) = @_;
195   for my $k (keys %{$rFiles}) {
196     my $rJob = $rFiles->{$k};
197     for my $j ( values %type2hash) {
198       if (defined($rJob->{$j})) {
199         print "$j: $k->$rJob->{$j}, " . $rJob->{$j . "copied"} . "\n";
200       }
201     }
202   }
203 }
204
205 sub interpretedCopy($$$$)
206 {
207   my ($source, $dest, $destdirOfSubdocuments, $rFiles) = @_;
208   my $sourcedir = dirname($source);
209   my $res = 0;
210
211   diestack("could not read \"$source\"") if (!open(FI, $source));
212   diestack("could not write \"$dest\"") if (! open(FO, '>', $dest));
213
214   initLyxStack(\%font, $fontT, $inputEncoding);
215
216   while (my $l = <FI>) {
217     $l =~ s/[\n\r]+$//;
218     #chomp($l);
219     my $rStatus = checkLyxLine($l);
220     if ($rStatus->{found}) {
221       my $rF = $rStatus->{result};
222       if ($rStatus->{"filetype"} eq "replace_only") {
223         # e.g. if no files involved (font chage etc)
224         $l = join('', @{$rF});
225       }
226       else {
227         my $filelist = $rStatus->{filelist};
228         my $fidx = $rStatus->{fileidx};
229         my $separator = $rStatus->{"separator"};
230         my $foundrelative = 0;
231         for my $f (@{$filelist}) {
232           my @isrel = isrelative($f,
233                                   $sourcedir,
234                                   $rStatus->{ext});
235           if ($isrel[0]) {
236             $foundrelative = 1;
237             my $ext = $isrel[1];
238             if ($rStatus->{"filetype"} eq "prefix_only") {
239               $f = getNewNameOf("$sourcedir/$f", $rFiles);
240             }
241             else {
242               my ($newname, $res1);
243               ($newname, $res1) = addFileCopyJob("$sourcedir/$f$ext",
244                                                   "$destdirOfSubdocuments",
245                                                   $rStatus->{"filetype"},
246                                                   $rFiles);
247               print "Added ($res1) file \"$sourcedir/$f$ext\" to be copied to \"$newname\"\n";
248               if ($ext ne "") {
249                 $newname =~ s/$ext$//;
250               }
251               $f = $newname;
252               $res += $res1;
253             }
254           }
255           else {
256             if (! -e "$f") {
257               # Non relative (e.g. with absolute path) file should exist
258               diestack("File \"$f\" not found, while parsing \"$source\"");
259             }
260           }
261         }
262         if ($foundrelative) {
263           $rF->[$fidx] = join($separator, @{$filelist});
264           $l = join('', @{$rF});
265         }
266       }
267     }
268     print FO "$l\n";
269   }
270   close(FI);
271   close(FO);
272
273   closeLyxStack();
274   return($res);
275 }
276
277 sub copyFoundSubdocuments($)
278 {
279   my ($rFiles) = @_;
280   my $res = 0;
281   do {
282     $res = 0;
283     my %copylist = ();
284
285     for my $filename (keys  %{$rFiles}) {
286       next if (! copyJobPending($filename, $rFiles));
287       $copylist{$filename} = 1;
288     }
289     for my $f (keys %copylist) {
290       # Second loop needed, because here $rFiles may change
291       my ($res1, @destfiles) = copyJob($f, $rFiles);
292       $res += $res1;
293       for my $destfile (@destfiles) {
294         print "res1 = $res1 for \"$f\" to be copied to $destfile\n";
295       }
296     }
297   } while($res > 0);            #  loop, while $rFiles changed
298 }
299
300 sub copyJob($$)
301 {
302   my ($source, $rFiles) = @_;
303   my $sourcedir = dirname($source);
304   my $res = 0;
305   my @dest = ();
306
307   for my $k (values %type2hash) {
308     if ($rFiles->{$source}->{$k}) {
309       if (! $rFiles->{$source}->{$k . "copied"}) {
310         $rFiles->{$source}->{$k . "copied"} = 1;
311         my $dest = $rFiles->{$source}->{$k};
312         push(@dest, $dest);
313         if ($k eq "copyonly") {
314           diestack("Could not copy \"$source\" to \"$dest\"") if (! cp($source, $dest));
315         }
316         else {
317           interpretedCopy($source, $dest, $destdirOfSubdocuments, $rFiles);
318         }
319         $res += 1;
320       }
321     }
322   }
323   return($res, @dest);
324 }
325
326 # Trivial check
327 sub isrelativeFix($$$)
328 {
329   my ($f, $sourcedir, $ext) = @_;
330
331   return(1, $ext) if  (-e "$sourcedir/$f$ext");
332   return(0,0);
333 }
334
335 sub isrelative($$$)
336 {
337   my ($f, $sourcedir, $ext) = @_;
338
339   if (ref($ext) eq "ARRAY") {
340     for my $ext2 (@{$ext}) {
341       my @res = isrelativeFix($f, $sourcedir, $ext2);
342       if ($res[0]) {
343         return(@res);
344       }
345     }
346     return(0,0);
347   }
348   else {
349     return(isrelativeFix($f, $sourcedir, $ext));
350   }
351 }
352
353 sub createTemporaryFileName($$)
354 {
355   my ($source, $destdir) = @_;
356
357   # get the basename to be used for the template
358   my ($name, $path, $suffix) = fileparse($source, qr/\.[^.]*/);
359   #print "source = $source, name = $name, path = $path, suffix = $suffix\n";
360   my $template = "xx_$name" . "_";
361   my $fname = File::Temp::tempnam($destdir, $template);
362
363   # Append extension from source
364   if ($suffix ne "") {
365     $fname .= "$suffix";
366   }
367   return($fname);
368 }
369
370 # Check, if file not copied yet
371 sub copyJobPending($$)
372 {
373   my ($f, $rFiles) = @_;
374   for my $t (values %type2hash) {
375     if (defined($rFiles->{$f}->{$t})) {
376       return 1 if (! $rFiles->{$f}->{$t . "copied"});
377     }
378   }
379   return 0;
380 }
381
382 sub addNewJob($$$$$)
383 {
384   my ($source, $newname, $hashname, $rJob, $rFiles) = @_;
385
386   $rJob->{$hashname} = $newname;
387   $rJob->{$hashname . "copied"} = 0;
388   $rFiles->{$source} = $rJob;
389 }
390
391 sub addFileCopyJob($$$$)
392 {
393   my ($source, $destdirOfSubdocuments, $filetype, $rFiles) = @_;
394   my ($res, $newname) = (0, undef);
395   my $rJob = $rFiles->{$source};
396
397   my $hashname = $type2hash{$filetype};
398   if (! defined($hashname)) {
399     diestack("unknown filetype \"$filetype\"");
400   }
401   if (!defined($rJob->{$hashname})) {
402     addNewJob($source,
403                createTemporaryFileName($source, $destdirOfSubdocuments),
404                "$hashname", $rJob, $rFiles);
405     $res = 1;
406   }
407   $newname = $rJob->{$hashname};
408   return($newname, $res);
409 }
410
411 sub getNewNameOf($$)
412 {
413   my ($f, $rFiles) = @_;
414   my $resultf = $f;
415
416   if (defined($rFiles->{$f})) {
417     for my $t (values %type2hash) {
418       if (defined($rFiles->{$f}->{$t})) {
419         $resultf = $rFiles->{$f}->{$t};
420         last;
421       }
422     }
423   }
424   return($resultf);
425 }
426
427 sub getlangs($$)
428 {
429   my ($languagefile, $rencoding) = @_;
430
431   if (open(FI, $languagefile)) {
432     while (my $l = <FI>) {
433       if ($l =~ /^Language/) {
434         my ($lng, $enc) = &getLangEntry();
435         if (defined($lng)) {
436           $rencoding->{$lng} = $enc;
437         }
438       }
439     }
440     close(FI);
441   }
442 }
443
444 sub simplifylangs($)
445 {
446   my ($rencoding) = @_;
447   my $base = "";
448   my $enc = "";
449   my $differ = 0;
450   my @klist = ();
451   my @klist2 = ();
452   for my $k (reverse sort keys %{$rencoding}) {
453     my @tag = split('_', $k);
454     if ($tag[0] eq $base) {
455       push(@klist, $k);
456       if ($rencoding->{$k} ne $enc) {
457         $differ = 1;
458       }
459     }
460     else {
461       # new base, check that old base was OK
462       if ($base ne "") {
463         if ($differ == 0) {
464           $rencoding->{$base} = $enc;
465           push(@klist2, @klist);
466         }
467       }
468       @klist = ($k);
469       $base = $tag[0];
470       $enc = $rencoding->{$k};
471       $differ = 0;
472     }
473   }
474   if ($base ne "") {
475     # close handling for last entry too
476     if ($differ == 0) {
477       $rencoding->{$base} = $enc;
478       push(@klist2, @klist);
479     }
480   }
481   for my $k (@klist2) {
482     delete($rencoding->{$k});
483   }
484 }
485
486 sub getLangEntry()
487 {
488   my ($lng, $enc) = (undef, undef);
489   while (my $l = <FI>) {
490     chomp($l);
491     if ($l =~ /^\s*Encoding\s+([^ ]+)\s*$/) {
492       $enc = $1;
493     }
494     elsif ($l =~ /^\s*LangCode\s+([^ ]+)\s*$/) {
495       $lng = $1;
496     }
497     elsif ($l =~ /^\s*End\s*$/) {
498       last;
499     }
500   }
501   if (defined($lng) && defined($enc)) {
502     return($lng, $enc);
503   }
504   else {
505     return(undef, undef);
506   }
507 }