4 # file useSystemFonts.pl
5 # 1.) Copies lyx-files to another location
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
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
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.
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.
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
32 # Copyright (c) 2013 Kornel Benko <kornel@lyx.org>
33 # (c) 2013 Scott Kostyshak <skotysh@lyx.org>
39 my $p = File::Spec->rel2abs( __FILE__ );
40 $p =~ s/[\/\\]?[^\/\\]+$//;
46 use File::Temp qw/ :POSIX /;
50 sub printCopiedDocuments($);
51 sub interpretedCopy($$$$);
52 sub copyFoundSubdocuments($);
54 sub isrelativeFix($$$);
56 sub createTemporaryFileName($$$);
57 sub copyJobPending($$);
59 sub addFileCopyJob($$$$$);
65 # convert lyx file to be compilable with xetex
67 my ($source, $dest, $format, $fontT, $encodingT, $languageFile, $rest) = @ARGV;
68 my %encodings = (); # Encoding with TeX fonts, depending on language tag
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));
77 $source = File::Spec->rel2abs($source);
78 $dest = File::Spec->rel2abs($dest);
82 if ($source =~ /\/([a-z][a-z](_[A-Z][A-Z])?)[\/_]/) {
86 my $inputEncoding = undef;
87 if ($fontT eq "systemF") {
89 elsif ($encodingT ne "default") {
90 # set input encoding to the requested value
92 "search" => '.*', # this will be substituted from '\inputencoding'-line
96 elsif (0) { # set to '1' to enable setting of inputencoding
99 if (defined($languageFile)) {
100 # The 2 lines below does not seem to have any effect
101 #&getlangs($languageFile, \%encoding);
102 #&simplifylangs(\%encoding);
104 if ($format =~ /^(pdf4)$/) { # xelatex
105 # set input encoding to 'ascii' always
107 "search" => '.*', # this will be substituted from '\inputencoding'-line
111 elsif ($format =~ /^(dvi3|pdf5)$/) { # (dvi)?lualatex
112 # when to set input encoding to 'ascii'?
113 if (defined($encoding{$lang})) {
115 "search" => '.*', # this will be substituted from '\inputencoding'-line
116 "out" => $encoding{$lang},
122 my $sourcedir = dirname($source);
123 my $destdir = dirname($dest);
125 diestack("could not make dir \"$destdir\"") if (! mkpath $destdir);
128 my $destdirOfSubdocuments;
130 my ($name, $pat, $suffix) = fileparse($source, qr/\.[^.]*/);
131 my $ext = $format . "-$lang";
133 $destdirOfSubdocuments = "$destdir/tmp-$ext" . "-$name"; # Global var, something TODO here
136 if(-d $destdirOfSubdocuments) {
137 rmtree($destdirOfSubdocuments);
139 mkpath($destdirOfSubdocuments); # for possibly included files
141 my %IncludedFiles = ();
143 "copy_only" => "copyonly",
144 "interpret" => "interpret");
146 addNewJob($source, $dest, "interpret", {}, \%IncludedFiles);
148 copyFoundSubdocuments(\%IncludedFiles);
150 #printCopiedDocuments(\%IncludedFiles);
153 ###########################################################
155 sub printCopiedDocuments($)
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";
168 sub interpretedCopy($$$$)
170 my ($source, $dest, $destdirOfSubdocuments, $rFiles) = @_;
171 my $sourcedir = dirname($source);
174 diestack("could not read \"$source\"") if (!open(FI, $source));
175 diestack("could not write \"$dest\"") if (! open(FO, '>', $dest));
177 initLyxStack(\%font, $fontT, $inputEncoding);
180 my @path_errors = ();
181 while (my $l = <FI>) {
185 my $rStatus = checkLyxLine($l);
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});
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,
204 if ($rStatus->{"filetype"} eq "prefix_only") {
205 $f = getNewNameOf("$sourcedir/$f", $rFiles);
208 my ($newname, $res1);
210 if (ref($rStatus->{ext}) eq "ARRAY") {
211 my @extlist = @{$rStatus->{ext}};
213 for my $extx (@extlist) {
214 if (-e "$sourcedir/$f$extx") {
215 ($newname, $res1) = addFileCopyJob("$sourcedir/$f$extx",
216 "$destdirOfSubdocuments",
217 $rStatus->{"filetype"},
219 print "Added ($res1) file \"$sourcedir/$f$extx\" to be copied to \"$newname\"\n";
220 if (!$created && $extx ne "") {
221 $newname =~ s/$extx$//;
226 print "WARNING: No prefixed file.(" . join('|', @extlist) . ") seens to exist, at \"$source:$fi_line_no\"\n" if (!$created);
229 ($newname, $res1) = addFileCopyJob("$sourcedir/$f$ext",
230 "$destdirOfSubdocuments",
231 $rStatus->{"filetype"},
233 print "Added ($res1) file \"$sourcedir/$f$ext\" to be copied to \"$newname\"\n";
235 $newname =~ s/$ext$//;
244 # Non relative (e.g. with absolute path) file should exist
245 if ($rStatus->{"filetype"} eq "interpret") {
246 # filetype::interpret should be interpreted by lyx or latex and therefore emit error
247 # We prinnt a warning instead
248 print "WARNING: Interpreted file \"$f\" not found, at \"$source:$fi_line_no\"\n";
250 elsif ($rStatus->{"filetype"} eq "prefix_only") {
251 # filetype::prefix_only should be interpreted by latex
252 print "WARNING: Prefixed file \"$f\" not found, at \"$source:$fi_line_no\"\n";
255 # Collect the path-error-messages
256 push(@path_errors, "File \"$f(" . $rStatus->{"filetype"} . ")\" not found, at \"$source:$fi_line_no\"");
261 if ($foundrelative) {
262 # The result can be relative too
264 for my $fr (@{$filelist}) {
265 push(@rel_list, File::Spec->abs2rel($fr, $destdir));
267 $rF->[$fidx] = join($separator, @rel_list);
268 $l = join('', @{$rF});
276 if (@path_errors > 0) {
277 for my $entry (@path_errors) {
278 print "ERROR: $entry\n";
280 diestack("Aborted because of path errors in \"$source\"");
287 sub copyFoundSubdocuments($)
295 for my $filename (keys %{$rFiles}) {
296 next if (! copyJobPending($filename, $rFiles));
297 $copylist{$filename} = 1;
299 for my $f (keys %copylist) {
300 # Second loop needed, because here $rFiles may change
301 my ($res1, @destfiles) = copyJob($f, $rFiles);
303 for my $destfile (@destfiles) {
304 print "res1 = $res1 for \"$f\" to be copied to $destfile\n";
307 } while($res > 0); # loop, while $rFiles changed
312 my ($source, $rFiles) = @_;
313 my $sourcedir = dirname($source);
317 for my $k (values %type2hash) {
318 if ($rFiles->{$source}->{$k}) {
319 if (! $rFiles->{$source}->{$k . "copied"}) {
320 $rFiles->{$source}->{$k . "copied"} = 1;
321 my $dest = $rFiles->{$source}->{$k};
323 if ($k eq "copyonly") {
324 diestack("Could not copy \"$source\" to \"$dest\"") if (! cp($source, $dest));
327 interpretedCopy($source, $dest, $destdirOfSubdocuments, $rFiles);
337 sub isrelativeFix($$$)
339 my ($f, $sourcedir, $ext) = @_;
341 return(1, $ext) if (-e "$sourcedir/$f$ext");
347 my ($f, $sourcedir, $ext) = @_;
349 if (ref($ext) eq "ARRAY") {
350 for my $ext2 (@{$ext}) {
351 my @res = isrelativeFix($f, $sourcedir, $ext2);
359 return(isrelativeFix($f, $sourcedir, $ext));
365 sub createTemporaryFileName($$$)
367 my ($source, $destdir, $created) = @_;
369 # get the basename to be used for the template
370 my ($name, $path, $suffix) = fileparse($source, qr/\.[^.]*/);
371 #print "source = $source, name = $name, path = $path, suffix = $suffix\n";
372 my $template = "xx-$name" . "-";
375 $fname = File::Temp::tempnam($destdir, $template);
382 # Append extension from source
389 # Check, if file not copied yet
390 sub copyJobPending($$)
392 my ($f, $rFiles) = @_;
393 for my $t (values %type2hash) {
394 if (defined($rFiles->{$f}->{$t})) {
395 return 1 if (! $rFiles->{$f}->{$t . "copied"});
403 my ($source, $newname, $hashname, $rJob, $rFiles) = @_;
405 $rJob->{$hashname} = $newname;
406 $rJob->{$hashname . "copied"} = 0;
407 $rFiles->{$source} = $rJob;
410 sub addFileCopyJob($$$$$)
412 my ($source, $destdirOfSubdocuments, $filetype, $rFiles, $created) = @_;
413 my ($res, $newname) = (0, undef);
414 my $rJob = $rFiles->{$source};
416 my $hashname = $type2hash{$filetype};
417 if (! defined($hashname)) {
418 diestack("unknown filetype \"$filetype\"");
420 if (!defined($rJob->{$hashname})) {
422 createTemporaryFileName($source, $destdirOfSubdocuments, $created),
423 "$hashname", $rJob, $rFiles);
426 $newname = $rJob->{$hashname};
427 return($newname, $res);
432 my ($f, $rFiles) = @_;
435 if (defined($rFiles->{$f})) {
436 for my $t (values %type2hash) {
437 if (defined($rFiles->{$f}->{$t})) {
438 $resultf = $rFiles->{$f}->{$t};
448 my ($languagefile, $rencoding) = @_;
450 if (open(FI, $languagefile)) {
451 while (my $l = <FI>) {
452 if ($l =~ /^Language/) {
453 my ($lng, $enc) = &getLangEntry();
455 $rencoding->{$lng} = $enc;
465 my ($rencoding) = @_;
471 for my $k (reverse sort keys %{$rencoding}) {
472 my @tag = split('_', $k);
473 if ($tag[0] eq $base) {
475 if ($rencoding->{$k} ne $enc) {
480 # new base, check that old base was OK
483 $rencoding->{$base} = $enc;
484 push(@klist2, @klist);
489 $enc = $rencoding->{$k};
494 # close handling for last entry too
496 $rencoding->{$base} = $enc;
497 push(@klist2, @klist);
500 for my $k (@klist2) {
501 delete($rencoding->{$k});
507 my ($lng, $enc) = (undef, undef);
508 while (my $l = <FI>) {
510 if ($l =~ /^\s*Encoding\s+([^ ]+)\s*$/) {
513 elsif ($l =~ /^\s*LangCode\s+([^ ]+)\s*$/) {
516 elsif ($l =~ /^\s*End\s*$/) {
520 if (defined($lng) && defined($enc)) {
524 return(undef, undef);