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
10 # 2c.) Changes the non-tex fonts setting if it is "default".
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
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.
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.
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
33 # Copyright (c) 2013 Kornel Benko <kornel@lyx.org>
34 # (c) 2013 Scott Kostyshak <skotysh@lyx.org>
40 my $p = File::Spec->rel2abs( __FILE__ );
41 $p =~ s/[\/\\]?[^\/\\]+$//;
47 use File::Temp qw/ :POSIX /;
51 sub printCopiedDocuments($);
52 sub interpretedCopy($$$$);
53 sub copyFoundSubdocuments($);
55 sub isrelativeFix($$$);
57 sub createTemporaryFileName($$);
58 sub copyJobPending($$);
60 sub addFileCopyJob($$$$);
66 # convert lyx file to be compilable with xetex
68 my ($source, $dest, $format, $fontT, $encodingT, $languageFile, $rest) = @ARGV;
69 my %encodings = (); # Encoding with TeX fonts, depending on language tag
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));
78 $source = File::Spec->rel2abs($source);
79 $dest = File::Spec->rel2abs($dest);
83 if ($source =~ /\/([a-z][a-z](_[A-Z][A-Z])?)[\/_]/) {
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)$/) {
92 # default system fonts
93 $font{roman} = "FreeSerif";
94 $font{sans} = "FreeSans";
95 $font{typewriter} = "FreeMono";
98 elsif ($encodingT ne "default") {
99 # set input encoding to the requested value
101 "search" => '.*', # this will be substituted from '\inputencoding'-line
105 elsif (0) { # set to '1' to enable setting of inputencoding
108 if (defined($languageFile)) {
109 # The 2 lines below does not seem to have any effect
110 #&getlangs($languageFile, \%encoding);
111 #&simplifylangs(\%encoding);
113 if ($format =~ /^(pdf4)$/) { # xelatex
114 # set input encoding to 'ascii' always
116 "search" => '.*', # this will be substituted from '\inputencoding'-line
120 elsif ($format =~ /^(dvi3|pdf5)$/) { # (dvi)?lualatex
121 # when to set input encoding to 'ascii'?
122 if (defined($encoding{$lang})) {
124 "search" => '.*', # this will be substituted from '\inputencoding'-line
125 "out" => $encoding{$lang},
131 my $sourcedir = dirname($source);
132 my $destdir = dirname($dest);
134 diestack("could not make dir \"$destdir\"") if (! mkpath $destdir);
137 my $destdirOfSubdocuments;
139 my ($name, $pat, $suffix) = fileparse($source, qr/\.[^.]*/);
140 my $ext = $format . "_$lang";
141 $destdirOfSubdocuments = "$destdir/tmp_$ext" . "_$name"; # Global var, something TODO here
144 if(-d $destdirOfSubdocuments) {
145 rmtree($destdirOfSubdocuments);
147 mkpath($destdirOfSubdocuments); # for possibly included files
149 my %IncludedFiles = ();
151 "copy_only" => "copyonly",
152 "interpret" => "interpret");
154 addNewJob($source, $dest, "interpret", {}, \%IncludedFiles);
156 copyFoundSubdocuments(\%IncludedFiles);
158 #printCopiedDocuments(\%IncludedFiles);
161 ###########################################################
163 sub printCopiedDocuments($)
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";
176 sub interpretedCopy($$$$)
178 my ($source, $dest, $destdirOfSubdocuments, $rFiles) = @_;
179 my $sourcedir = dirname($source);
182 diestack("could not read \"$source\"") if (!open(FI, $source));
183 diestack("could not write \"$dest\"") if (! open(FO, '>', $dest));
185 initLyxStack(\%font, $fontT, $inputEncoding);
188 my @path_errors = ();
189 while (my $l = <FI>) {
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});
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,
212 if ($rStatus->{"filetype"} eq "prefix_only") {
213 $f = getNewNameOf("$sourcedir/$f", $rFiles);
216 my ($newname, $res1);
217 ($newname, $res1) = addFileCopyJob("$sourcedir/$f$ext",
218 "$destdirOfSubdocuments",
219 $rStatus->{"filetype"},
221 print "Added ($res1) file \"$sourcedir/$f$ext\" to be copied to \"$newname\"\n";
223 $newname =~ s/$ext$//;
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";
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";
242 # Collect the path-error-messages
243 push(@path_errors, "File \"$f(" . $rStatus->{"filetype"} . ")\" not found, at \"$source:$fi_line_no\"");
248 if ($foundrelative) {
249 $rF->[$fidx] = join($separator, @{$filelist});
250 $l = join('', @{$rF});
258 if (@path_errors > 0) {
259 for my $entry (@path_errors) {
260 print "ERROR: $entry\n";
262 diestack("Aborted because of path errors in \"$source\"");
269 sub copyFoundSubdocuments($)
277 for my $filename (keys %{$rFiles}) {
278 next if (! copyJobPending($filename, $rFiles));
279 $copylist{$filename} = 1;
281 for my $f (keys %copylist) {
282 # Second loop needed, because here $rFiles may change
283 my ($res1, @destfiles) = copyJob($f, $rFiles);
285 for my $destfile (@destfiles) {
286 print "res1 = $res1 for \"$f\" to be copied to $destfile\n";
289 } while($res > 0); # loop, while $rFiles changed
294 my ($source, $rFiles) = @_;
295 my $sourcedir = dirname($source);
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};
305 if ($k eq "copyonly") {
306 diestack("Could not copy \"$source\" to \"$dest\"") if (! cp($source, $dest));
309 interpretedCopy($source, $dest, $destdirOfSubdocuments, $rFiles);
319 sub isrelativeFix($$$)
321 my ($f, $sourcedir, $ext) = @_;
323 return(1, $ext) if (-e "$sourcedir/$f$ext");
329 my ($f, $sourcedir, $ext) = @_;
331 if (ref($ext) eq "ARRAY") {
332 for my $ext2 (@{$ext}) {
333 my @res = isrelativeFix($f, $sourcedir, $ext2);
341 return(isrelativeFix($f, $sourcedir, $ext));
345 sub createTemporaryFileName($$)
347 my ($source, $destdir) = @_;
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);
355 # Append extension from source
362 # Check, if file not copied yet
363 sub copyJobPending($$)
365 my ($f, $rFiles) = @_;
366 for my $t (values %type2hash) {
367 if (defined($rFiles->{$f}->{$t})) {
368 return 1 if (! $rFiles->{$f}->{$t . "copied"});
376 my ($source, $newname, $hashname, $rJob, $rFiles) = @_;
378 $rJob->{$hashname} = $newname;
379 $rJob->{$hashname . "copied"} = 0;
380 $rFiles->{$source} = $rJob;
383 sub addFileCopyJob($$$$)
385 my ($source, $destdirOfSubdocuments, $filetype, $rFiles) = @_;
386 my ($res, $newname) = (0, undef);
387 my $rJob = $rFiles->{$source};
389 my $hashname = $type2hash{$filetype};
390 if (! defined($hashname)) {
391 diestack("unknown filetype \"$filetype\"");
393 if (!defined($rJob->{$hashname})) {
395 createTemporaryFileName($source, $destdirOfSubdocuments),
396 "$hashname", $rJob, $rFiles);
399 $newname = $rJob->{$hashname};
400 return($newname, $res);
405 my ($f, $rFiles) = @_;
408 if (defined($rFiles->{$f})) {
409 for my $t (values %type2hash) {
410 if (defined($rFiles->{$f}->{$t})) {
411 $resultf = $rFiles->{$f}->{$t};
421 my ($languagefile, $rencoding) = @_;
423 if (open(FI, $languagefile)) {
424 while (my $l = <FI>) {
425 if ($l =~ /^Language/) {
426 my ($lng, $enc) = &getLangEntry();
428 $rencoding->{$lng} = $enc;
438 my ($rencoding) = @_;
444 for my $k (reverse sort keys %{$rencoding}) {
445 my @tag = split('_', $k);
446 if ($tag[0] eq $base) {
448 if ($rencoding->{$k} ne $enc) {
453 # new base, check that old base was OK
456 $rencoding->{$base} = $enc;
457 push(@klist2, @klist);
462 $enc = $rencoding->{$k};
467 # close handling for last entry too
469 $rencoding->{$base} = $enc;
470 push(@klist2, @klist);
473 for my $k (@klist2) {
474 delete($rencoding->{$k});
480 my ($lng, $enc) = (undef, undef);
481 while (my $l = <FI>) {
483 if ($l =~ /^\s*Encoding\s+([^ ]+)\s*$/) {
486 elsif ($l =~ /^\s*LangCode\s+([^ ]+)\s*$/) {
489 elsif ($l =~ /^\s*End\s*$/) {
493 if (defined($lng) && defined($enc)) {
497 return(undef, undef);