]> git.lyx.org Git - lyx.git/blob - development/autotests/useSystemFonts.pl
ctests: useSystemFonts.pl -- revert changes in 1879fbedfb67cc6.
[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 #   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 =~ /^(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 "ko" ) {
105     # $font{roman} = "NanumGothic"; # NanumMyeongjo, NanumGothic Eco, NanumGothicCoding
106     # $font{sans} = "NanumGothic";
107     # $font{typewriter} = "NanumGothic";
108   }
109   elsif ($lang eq "ar" ) {
110     # available in 'fonts-sil-scheherazade' package
111     $font{roman} = "Scheherazade";
112     $font{sans} = "Scheherazade";
113     $font{typewriter} = "Scheherazade";
114   }
115   else {
116     # default system fonts
117     $font{roman} = "FreeSerif";
118     $font{sans} = "FreeSans";
119     $font{typewriter} = "FreeMono";
120   }
121 }
122 elsif ($encodingT ne "default") {
123   # set input encoding to the requested value
124   $inputEncoding = {
125         "search" => '.*', # this will be substituted from '\inputencoding'-line
126         "out" => $encodingT,
127     };
128 }
129 elsif (0) { # set to '1' to enable setting of inputencoding
130   # use tex font here
131   my %encoding = ();
132   if (defined($languageFile)) {
133     # The 2 lines below does not seem to have any effect
134     #&getlangs($languageFile, \%encoding);
135     #&simplifylangs(\%encoding);
136   }
137   if ($format =~ /^(pdf4)$/) { # xelatex
138     # set input encoding to 'ascii' always
139     $inputEncoding = {
140       "search" => '.*', # this will be substituted from '\inputencoding'-line
141       "out" => "ascii",
142     };
143   }
144   elsif ($format =~ /^(dvi3|pdf5)$/) { # (dvi)?lualatex
145     # when to set input encoding to 'ascii'?
146     if (defined($encoding{$lang})) {
147       $inputEncoding = {
148         "search" => '.*', # this will be substituted from '\inputencoding'-line
149         "out" => $encoding{$lang},
150       };
151     }
152   }
153 }
154
155 my $sourcedir = dirname($source);
156 my $destdir = dirname($dest);
157 if (! -d $destdir) {
158   diestack("could not make dir \"$destdir\"") if (! mkpath $destdir);
159 }
160
161 my $destdirOfSubdocuments;
162 {
163   my ($name, $pat, $suffix) = fileparse($source, qr/\.[^.]*/);
164   my $ext = $format . "_$lang";
165   $destdirOfSubdocuments = "$destdir/tmp_$ext" . "_$name"; # Global var, something TODO here
166 }
167
168 if(-d $destdirOfSubdocuments) {
169   rmtree($destdirOfSubdocuments);
170 }
171 mkpath($destdirOfSubdocuments); #  for possibly included files
172
173 my %IncludedFiles = ();
174 my %type2hash = (
175   "copy_only" => "copyonly",
176   "interpret" => "interpret");
177
178 addNewJob($source, $dest, "interpret", {}, \%IncludedFiles);
179
180 copyFoundSubdocuments(\%IncludedFiles);
181
182 #printCopiedDocuments(\%IncludedFiles);
183
184 exit(0);
185 ###########################################################
186
187 sub printCopiedDocuments($)
188 {
189   my ($rFiles) = @_;
190   for my $k (keys %{$rFiles}) {
191     my $rJob = $rFiles->{$k};
192     for my $j ( values %type2hash) {
193       if (defined($rJob->{$j})) {
194         print "$j: $k->$rJob->{$j}, " . $rJob->{$j . "copied"} . "\n";
195       }
196     }
197   }
198 }
199
200 sub interpretedCopy($$$$)
201 {
202   my ($source, $dest, $destdirOfSubdocuments, $rFiles) = @_;
203   my $sourcedir = dirname($source);
204   my $res = 0;
205
206   diestack("could not read \"$source\"") if (!open(FI, $source));
207   diestack("could not write \"$dest\"") if (! open(FO, '>', $dest));
208
209   initLyxStack(\%font, $fontT, $inputEncoding);
210
211   my $fi_line_no = 0;
212   my @path_errors = ();
213   while (my $l = <FI>) {
214     $fi_line_no += 1;
215     $l =~ s/[\n\r]+$//;
216     #chomp($l);
217     my $rStatus = checkLyxLine($l);
218     if ($rStatus->{found}) {
219       my $rF = $rStatus->{result};
220       if ($rStatus->{"filetype"} eq "replace_only") {
221         # e.g. if no files involved (font chage etc)
222         $l = join('', @{$rF});
223       }
224       else {
225         my $filelist = $rStatus->{filelist};
226         my $fidx = $rStatus->{fileidx};
227         my $separator = $rStatus->{"separator"};
228         my $foundrelative = 0;
229         for my $f (@{$filelist}) {
230           my @isrel = isrelative($f,
231                                   $sourcedir,
232                                   $rStatus->{ext});
233           if ($isrel[0]) {
234             $foundrelative = 1;
235             my $ext = $isrel[1];
236             if ($rStatus->{"filetype"} eq "prefix_only") {
237               $f = getNewNameOf("$sourcedir/$f", $rFiles);
238             }
239             else {
240               my ($newname, $res1);
241               ($newname, $res1) = addFileCopyJob("$sourcedir/$f$ext",
242                                                   "$destdirOfSubdocuments",
243                                                   $rStatus->{"filetype"},
244                                                   $rFiles);
245               print "Added ($res1) file \"$sourcedir/$f$ext\" to be copied to \"$newname\"\n";
246               if ($ext ne "") {
247                 $newname =~ s/$ext$//;
248               }
249               $f = $newname;
250               $res += $res1;
251             }
252           }
253           else {
254             if (! -e "$f") {
255               # Non relative (e.g. with absolute path) file should exist
256               if ($rStatus->{"filetype"} eq "interpret") {
257                 # filetype::interpret should be interpreted by lyx or latex and therefore emit error
258                 # We prinnt a warning instead
259                 print "WARNING: Interpreted file \"$f\" not found, at \"$source:$fi_line_no\"\n";
260               }
261               elsif ($rStatus->{"filetype"} eq "prefix_only") {
262                 # filetype::prefix_only should be interpreted by latex
263                 print "WARNING: Prefixed file \"$f\" not found, at \"$source:$fi_line_no\"\n";
264               }
265               else {
266                 # Collect the path-error-messages
267                 push(@path_errors, "File \"$f(" . $rStatus->{"filetype"} . ")\" not found, at \"$source:$fi_line_no\"");
268               }
269             }
270           }
271         }
272         if ($foundrelative) {
273           $rF->[$fidx] = join($separator, @{$filelist});
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 sub createTemporaryFileName($$)
370 {
371   my ($source, $destdir) = @_;
372
373   # get the basename to be used for the template
374   my ($name, $path, $suffix) = fileparse($source, qr/\.[^.]*/);
375   #print "source = $source, name = $name, path = $path, suffix = $suffix\n";
376   my $template = "xx_$name" . "_";
377   my $fname = File::Temp::tempnam($destdir, $template);
378
379   # Append extension from source
380   if ($suffix ne "") {
381     $fname .= "$suffix";
382   }
383   return($fname);
384 }
385
386 # Check, if file not copied yet
387 sub copyJobPending($$)
388 {
389   my ($f, $rFiles) = @_;
390   for my $t (values %type2hash) {
391     if (defined($rFiles->{$f}->{$t})) {
392       return 1 if (! $rFiles->{$f}->{$t . "copied"});
393     }
394   }
395   return 0;
396 }
397
398 sub addNewJob($$$$$)
399 {
400   my ($source, $newname, $hashname, $rJob, $rFiles) = @_;
401
402   $rJob->{$hashname} = $newname;
403   $rJob->{$hashname . "copied"} = 0;
404   $rFiles->{$source} = $rJob;
405 }
406
407 sub addFileCopyJob($$$$)
408 {
409   my ($source, $destdirOfSubdocuments, $filetype, $rFiles) = @_;
410   my ($res, $newname) = (0, undef);
411   my $rJob = $rFiles->{$source};
412
413   my $hashname = $type2hash{$filetype};
414   if (! defined($hashname)) {
415     diestack("unknown filetype \"$filetype\"");
416   }
417   if (!defined($rJob->{$hashname})) {
418     addNewJob($source,
419                createTemporaryFileName($source, $destdirOfSubdocuments),
420                "$hashname", $rJob, $rFiles);
421     $res = 1;
422   }
423   $newname = $rJob->{$hashname};
424   return($newname, $res);
425 }
426
427 sub getNewNameOf($$)
428 {
429   my ($f, $rFiles) = @_;
430   my $resultf = $f;
431
432   if (defined($rFiles->{$f})) {
433     for my $t (values %type2hash) {
434       if (defined($rFiles->{$f}->{$t})) {
435         $resultf = $rFiles->{$f}->{$t};
436         last;
437       }
438     }
439   }
440   return($resultf);
441 }
442
443 sub getlangs($$)
444 {
445   my ($languagefile, $rencoding) = @_;
446
447   if (open(FI, $languagefile)) {
448     while (my $l = <FI>) {
449       if ($l =~ /^Language/) {
450         my ($lng, $enc) = &getLangEntry();
451         if (defined($lng)) {
452           $rencoding->{$lng} = $enc;
453         }
454       }
455     }
456     close(FI);
457   }
458 }
459
460 sub simplifylangs($)
461 {
462   my ($rencoding) = @_;
463   my $base = "";
464   my $enc = "";
465   my $differ = 0;
466   my @klist = ();
467   my @klist2 = ();
468   for my $k (reverse sort keys %{$rencoding}) {
469     my @tag = split('_', $k);
470     if ($tag[0] eq $base) {
471       push(@klist, $k);
472       if ($rencoding->{$k} ne $enc) {
473         $differ = 1;
474       }
475     }
476     else {
477       # new base, check that old base was OK
478       if ($base ne "") {
479         if ($differ == 0) {
480           $rencoding->{$base} = $enc;
481           push(@klist2, @klist);
482         }
483       }
484       @klist = ($k);
485       $base = $tag[0];
486       $enc = $rencoding->{$k};
487       $differ = 0;
488     }
489   }
490   if ($base ne "") {
491     # close handling for last entry too
492     if ($differ == 0) {
493       $rencoding->{$base} = $enc;
494       push(@klist2, @klist);
495     }
496   }
497   for my $k (@klist2) {
498     delete($rencoding->{$k});
499   }
500 }
501
502 sub getLangEntry()
503 {
504   my ($lng, $enc) = (undef, undef);
505   while (my $l = <FI>) {
506     chomp($l);
507     if ($l =~ /^\s*Encoding\s+([^ ]+)\s*$/) {
508       $enc = $1;
509     }
510     elsif ($l =~ /^\s*LangCode\s+([^ ]+)\s*$/) {
511       $lng = $1;
512     }
513     elsif ($l =~ /^\s*End\s*$/) {
514       last;
515     }
516   }
517   if (defined($lng) && defined($enc)) {
518     return($lng, $enc);
519   }
520   else {
521     return(undef, undef);
522   }
523 }