|
|
#!/usr/bin/env perl
|
|
|
#
|
|
|
# Copyright 2015 Norbert Preining
|
|
|
#
|
|
|
# This file is licensed under the GNU General Public License version 2
|
|
|
# or any later version.
|
|
|
#
|
|
|
# History:
|
|
|
# Original shell script (C) 1994 Thomas Esser (as texhash), Public domain.
|
|
|
#
|
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
C<mktexlsr> and C<TeX::LSR> - handle TeX's Kpathsea file name database C<ls-R>
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
mktexlsr [I<option>]... [I<dir>]...
|
|
|
|
|
|
texhash [I<option>]... [I<dir>]...
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
B<mktexlsr> rebuilds the C<ls-R> filename databases used by TeX.
|
|
|
If one or more arguments I<dir> are given, these are used as the
|
|
|
directories in which to build C<ls-R>. Else all directories in the
|
|
|
search path for C<ls-R> files (i.e., \$TEXMFDBS) are used.
|
|
|
|
|
|
B<texhash> is a synonym for B<mktexlsr>; there are no differences in
|
|
|
behavior based on the name.
|
|
|
|
|
|
=head1 OPTIONS
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
=item B<--dry-run>, B<-n>
|
|
|
|
|
|
do not actually update anything
|
|
|
|
|
|
=item B<--help>, B<-h>
|
|
|
|
|
|
display this help and exit
|
|
|
|
|
|
=item B<--nofollow>
|
|
|
|
|
|
do not follow symlinks (default to follow)
|
|
|
|
|
|
=item B<--output[=]>I<NAME>, B<-o> I<NAME>
|
|
|
|
|
|
if (and only if) exactly one I<dir> is given, output C<ls-R> file to I<NAME>
|
|
|
|
|
|
=item B<--quiet>, B<-q>, B<--silent>
|
|
|
|
|
|
cancel --verbose
|
|
|
|
|
|
=item B<--verbose>
|
|
|
|
|
|
explain what is being done, defaults to on when output is connected
|
|
|
to a terminal.
|
|
|
|
|
|
=item B<--version>, B<-v>
|
|
|
|
|
|
output version information and exit
|
|
|
|
|
|
=back
|
|
|
|
|
|
=cut
|
|
|
|
|
|
use strict;
|
|
|
$^W = 1;
|
|
|
|
|
|
|
|
|
package mktexlsr;
|
|
|
|
|
|
my $ismain;
|
|
|
|
|
|
BEGIN {
|
|
|
$^W = 1;
|
|
|
$ismain = (__FILE__ eq $0);
|
|
|
}
|
|
|
|
|
|
# for future inclusion in TeX Live svn:
|
|
|
my $svnid = '$Id: mktexlsr.pl 38001 2015-07-30 01:25:25Z preining $';
|
|
|
my $lastchdate = '$Date: 2015-07-30 03:25:25 +0200 (Thu, 30 Jul 2015) $';
|
|
|
$lastchdate =~ s/^\$Date:\s*//;
|
|
|
$lastchdate =~ s/ \(.*$//;
|
|
|
my $svnrev = '$Revision: 38001 $';
|
|
|
$svnrev =~ s/^\$Revision:\s*//;
|
|
|
$svnrev =~ s/\s*\$$//;
|
|
|
my $version = "revision $svnrev ($lastchdate)";
|
|
|
|
|
|
use Getopt::Long;
|
|
|
use File::Basename;
|
|
|
use Pod::Usage;
|
|
|
|
|
|
my $opt_dryrun = 0;
|
|
|
my $opt_help = 0;
|
|
|
my $opt_verbose = (-t STDIN); # test whether connected to a terminal
|
|
|
my $opt_version = 0;
|
|
|
my $opt_output;
|
|
|
my $opt_sort = 0; # for debugging sort output
|
|
|
my $opt_follow = 1; # follow links - check whether they are dirs or not
|
|
|
|
|
|
(my $prg = basename($0)) =~ s/\.pl$//;
|
|
|
|
|
|
my $lsrmagic =
|
|
|
'% ls-R -- filename database for kpathsea; do not change this line.';
|
|
|
my $oldlsrmagic =
|
|
|
'% ls-R -- maintained by MakeTeXls-R; do not change this line.';
|
|
|
|
|
|
|
|
|
&main() if $ismain;
|
|
|
|
|
|
|
|
|
|
|
|
#################################################################
|
|
|
#
|
|
|
# usage as module
|
|
|
#
|
|
|
|
|
|
package TeX::LSR;
|
|
|
|
|
|
use Cwd;
|
|
|
use File::Spec::Functions;
|
|
|
use File::Find;
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=head1 Perl Module Usage
|
|
|
|
|
|
This file also provides a module C<TeX::LSR> that can be used
|
|
|
as programmatic interface to the C<ls-R> files. Available
|
|
|
methods are:
|
|
|
|
|
|
$lsr = new TeX::LSR( root => $texmftree );
|
|
|
$lsr->loadtree();
|
|
|
$lsr->loadfile();
|
|
|
$lsr->write( [filename => $fn, sort => $do_sort ] );
|
|
|
$lsr->addfiles ( @files );
|
|
|
|
|
|
=head1 Methods
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
=item C<< TeX::LSR->new( [root => "$path"] ) >>
|
|
|
|
|
|
create a new C<LSR> object related to the tree in C<$path>,
|
|
|
without loading any further information. Returns 1 on success
|
|
|
and 0 on failure.
|
|
|
|
|
|
The tree is represented as hash, where each file and directory
|
|
|
acts as key, with files having 1 as value, and directories
|
|
|
their recursive representation hash as value.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub new {
|
|
|
my $class = shift;
|
|
|
my %params = @_;
|
|
|
my $self = {
|
|
|
root => $params{'root'},
|
|
|
filename => '', # to accomodated both ls-r and ls-R
|
|
|
is_loaded => 0,
|
|
|
tree => { }
|
|
|
};
|
|
|
bless $self, $class;
|
|
|
return $self;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $lsr->loadtree() >>
|
|
|
|
|
|
Loads the file information from the actual tree by traversing the
|
|
|
whole directory recursively.
|
|
|
|
|
|
Common VCS files and directories are ignored (C<.git>, C<.svn>, C<.hg>,
|
|
|
C<.bzr>, C<CVS>). See above for the representation.
|
|
|
|
|
|
Returns 1 on success, 0 on failure.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
# returns 1 on success, 0 on failure
|
|
|
sub loadtree {
|
|
|
my $self = shift;
|
|
|
return 0 if (!defined($self->{'root'}));
|
|
|
return 0 if (! -d $self->{'root'});
|
|
|
|
|
|
my $tree;
|
|
|
build_tree($tree, $self->{'root'});
|
|
|
$self->{'tree'} = $tree->{$self->{'root'}};
|
|
|
$self->{'is_loaded'} = 1;
|
|
|
return 1;
|
|
|
|
|
|
# code adapted from
|
|
|
# http://www.perlmonks.org/?node=How%20to%20map%20a%20directory%20tree%20to%20a%20perl%20hash%20tree
|
|
|
sub build_tree {
|
|
|
my $node = $_[0] = {};
|
|
|
my @s;
|
|
|
# go through all dirs recursively (File::Find::find),
|
|
|
# links are dereferenced according to $opt_follow
|
|
|
# add an entry of 1 if it is not a directory, otherwise
|
|
|
# create an empty hash as argument
|
|
|
File::Find::find( { follow_skip => 2, follow_fast => $opt_follow, wanted => sub {
|
|
|
$node = (pop @s)->[1] while (@s && $File::Find::dir ne $s[-1][0]);
|
|
|
# ignore VCS
|
|
|
return if ($_ eq ".git");
|
|
|
return if ($_ eq ".svn");
|
|
|
return if ($_ eq ".hg");
|
|
|
return if ($_ eq ".bzr");
|
|
|
return if ($_ eq "CVS");
|
|
|
return $node->{$_} = 1 if (! -d);
|
|
|
push (@s, [ $File::Find::name, $node ]);
|
|
|
$node = $node->{$_} = {};
|
|
|
}}, $_[1]);
|
|
|
$_[0]{$_[1]} = delete $_[0]{'.'};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
# set the `filename' member; check ls-R first, then ls-r.
|
|
|
|
|
|
=pod C<< $lsr->setup_filename() >>
|
|
|
|
|
|
We support file names C<ls-R> and C<ls-r>, but create as C<ls-R>.
|
|
|
Internal function, should not be used outside.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub setup_filename {
|
|
|
my $self = shift;
|
|
|
if (!$self->{'filename'}) {
|
|
|
if (-r $self->{'root'} . "/ls-R") {
|
|
|
$self->{'filename'} = 'ls-R';
|
|
|
} elsif (-r $self->{'root'} . "/ls-r") {
|
|
|
$self->{'filename'} = 'ls-r';
|
|
|
} else {
|
|
|
$self->{'filename'} = 'ls-R';
|
|
|
}
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $lsr->load() >>
|
|
|
|
|
|
Loads the file information either from the C<lsr-R> file, if
|
|
|
present, otherwise from the actual tree.
|
|
|
|
|
|
Returns 1 on success, 0 on failure.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub load {
|
|
|
my $self = shift;
|
|
|
return 0 if (!defined($self->{'root'}));
|
|
|
return 0 if (! -d $self->{'root'});
|
|
|
$self->setup_filename();
|
|
|
if (-r $self->{'filename'}) {
|
|
|
return $self->loadfile();
|
|
|
} else {
|
|
|
return $self->loadtree();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $lsr->loadfile() >>
|
|
|
|
|
|
Loads the file information from the C<ls-R> file. Checks for the
|
|
|
presence of the magic header as first line.
|
|
|
|
|
|
Returns 1 on success, 0 on failure.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
# read given file; return 0 if failure, 1 if ok.
|
|
|
sub loadfile {
|
|
|
my $self = shift;
|
|
|
return 0 if (!defined($self->{'root'}));
|
|
|
return 0 if (! -d $self->{'root'});
|
|
|
|
|
|
$self->setup_filename();
|
|
|
my $lsrfile = catfile($self->{'root'}, $self->{'filename'});
|
|
|
return 0 if (! -r $lsrfile);
|
|
|
|
|
|
open (LSR, "<", $lsrfile)
|
|
|
|| die "$prg: readable but not openable $lsrfile??: $!";
|
|
|
|
|
|
# check first line for the magic header
|
|
|
chomp (my $fl = <LSR>);
|
|
|
if (($fl eq $lsrmagic) || ($fl eq $oldlsrmagic)) {
|
|
|
my %tree;
|
|
|
my $t;
|
|
|
for my $l (<LSR>) {
|
|
|
chomp($l);
|
|
|
next if ($l =~ m!^\s*$!);
|
|
|
next if ($l =~ m!^\./:!);
|
|
|
if ($l =~ m!^(.*):!) {
|
|
|
$t = \%tree;
|
|
|
my @a = split(/\//, $1);
|
|
|
for (@a) {
|
|
|
$t->{$_} = {} if (!defined($t->{$_}) || ($t->{$_} == 1));
|
|
|
$t = $t->{$_};
|
|
|
}
|
|
|
} else {
|
|
|
$t->{$l} = 1;
|
|
|
}
|
|
|
}
|
|
|
$self->{'tree'} = $tree{'.'};
|
|
|
}
|
|
|
close(LSR);
|
|
|
$self->{'is_loaded'} = 1;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
#
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $lsr->write( [ filename => "$fn", sort => $val) >>
|
|
|
|
|
|
Writes out the C<ls-R> file, either to the default file name, or
|
|
|
to C<$fn> if given. Entries within a directory are not sorted
|
|
|
(not necessary), but sorting can be enforced by passing a true
|
|
|
value to C<sort>.
|
|
|
|
|
|
Returns 1 on success, 0 on failure (and give warning).
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub write {
|
|
|
my $self = shift;
|
|
|
my %params = @_;
|
|
|
my $fn;
|
|
|
my $dosort = 0;
|
|
|
$fn = $params{'filename'} if $params{'filename'};
|
|
|
$dosort = $params{'sort'};
|
|
|
if (!defined($self->{'root'})) {
|
|
|
warn "TeX::LSR: root undefined, cannot write.\n";
|
|
|
return 0;
|
|
|
}
|
|
|
if ($self->{'is_loaded'} == 0) {
|
|
|
warn "TeX::LSR: tree not loaded, cannot write: $self->{root}\n";
|
|
|
return 0;
|
|
|
}
|
|
|
if (!defined($fn)) {
|
|
|
$self->setup_filename();
|
|
|
$fn = catfile($self->{'root'}, $self->{'filename'});
|
|
|
}
|
|
|
if (-e $fn && ! -w $fn) {
|
|
|
warn "TeX::LSR: ls-R file not writable, skipping: $fn\n";
|
|
|
return 0;
|
|
|
}
|
|
|
open (LSR, ">$fn") || die "TeX::LSR writable but cannot open??; $!";
|
|
|
print LSR "$lsrmagic\n\n";
|
|
|
print LSR "./:\n"; # hardwired ./ for top-level files
|
|
|
do_entry($self->{'tree'}, ".", $dosort);
|
|
|
close LSR;
|
|
|
return 1;
|
|
|
|
|
|
sub do_entry {
|
|
|
my ($t, $n, $sortit) = @_;
|
|
|
print LSR "$n:\n";
|
|
|
my @sd;
|
|
|
for my $st ($sortit ? sort(keys %$t) : keys %$t) {
|
|
|
push (@sd, $st) if (ref($t->{$st}) eq 'HASH');
|
|
|
print LSR "$st\n";
|
|
|
}
|
|
|
print LSR "\n";
|
|
|
for my $st ($sortit ? sort @sd : @sd) {
|
|
|
do_entry($t->{$st}, "$n/$st", $sortit);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $lsr->addfiles( @files ) >>
|
|
|
|
|
|
Adds the files from C<@files> to the C<ls-R> tree. If a file
|
|
|
is relative, it is added relative the the root of the tree. If
|
|
|
it is absolute and the root agrees with a prefix of the file name,
|
|
|
add the remaining part. If they disagree, throw an error.
|
|
|
|
|
|
Returns 1 on success, 0 on failure (and give warning).
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub addfiles {
|
|
|
my ($self, @files) = @_;
|
|
|
if ($self->{'is_loaded'} == 0) {
|
|
|
warn "TeX::LSR: tree not loaded, cannot add files: $self->{root}\n";
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
# if we are passed an absolute file name, check whether the prefix
|
|
|
# coincides with the root of the texmf tree, and add the relative
|
|
|
# file name, otherwise bail out
|
|
|
for my $f (@files) {
|
|
|
if (file_name_is_absolute($f)) {
|
|
|
my $cf = canonpath($f);
|
|
|
my $cr = canonpath($self->root);
|
|
|
if ($cf =~ m/^$cr([\\\/])?(.*)$/) {
|
|
|
$f = $2;
|
|
|
} else {
|
|
|
warn("File $f does not reside in $self->root.");
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
my $t = $self->{'tree'};
|
|
|
my @a = split(/[\\\/]/, $f);
|
|
|
my $fn = pop @a;
|
|
|
for (@a) {
|
|
|
$t->{$_} = {} if (!defined($t->{$_}) || ($t->{$_} == 1));
|
|
|
$t = $t->{$_};
|
|
|
}
|
|
|
$t->{$fn} = 1;
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=back
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
##########################################################
|
|
|
#
|
|
|
# package TeX::Update
|
|
|
#
|
|
|
# based on the mktexupd function in TLUtils
|
|
|
|
|
|
package TeX::Update;
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=head1 TeX ls-R Update module
|
|
|
|
|
|
This file also provides a module C<TeX::Update> that can be used
|
|
|
to add files to their respective trees.
|
|
|
Available methods are:
|
|
|
|
|
|
$upd = new TeX::Update();
|
|
|
$upd->mustexist(1);
|
|
|
$upd->add(file1, [file2]);
|
|
|
$upd->add(file3);
|
|
|
$upd->exec();
|
|
|
$upd->reset();
|
|
|
|
|
|
=head1 Methods
|
|
|
|
|
|
=over 4
|
|
|
|
|
|
=item C<< TeX::Update->new() >>
|
|
|
|
|
|
Create a new TeX::Update object.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub new {
|
|
|
my $class = shift;
|
|
|
my $self = {
|
|
|
files => {},
|
|
|
mustexist => 0,
|
|
|
};
|
|
|
bless $self, $class;
|
|
|
return $self;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $upd->add( @files ) >>
|
|
|
|
|
|
Adds a list of files without any checks done.
|
|
|
Returns 1.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub add {
|
|
|
my $self = shift;
|
|
|
foreach my $file (@_) {
|
|
|
$file =~ s|\\|/|g;
|
|
|
$self->{'files'}{$file} = 1;
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $upd->reset( ) >>
|
|
|
|
|
|
Removes all references to added files. Returns 1.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub reset {
|
|
|
my $self = shift;
|
|
|
$self->{'files'} = {};
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $upd->mustexist( [ $newvalue ] ) >>
|
|
|
|
|
|
Wit C<$newvalue> given, sets the mustexist propery. In both
|
|
|
cases returns the current value afterwards.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub mustexist {
|
|
|
my $self = shift;
|
|
|
if (@_) { $self->{'mustexist'} = shift }
|
|
|
return $self->{'mustexist'};
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=item C<< $upd->exec( ) >>
|
|
|
|
|
|
Goes through all added files, determines whether the files is contained
|
|
|
in a tree that contains a ls-R files. If yes, adds the files there.
|
|
|
If the mustexist property is set, bails out in case a file does not
|
|
|
exists.
|
|
|
|
|
|
Returns 1 on success, 0 on failure (and give warning).
|
|
|
|
|
|
=cut
|
|
|
|
|
|
sub exec {
|
|
|
my $self = shift;
|
|
|
# first check whether all files exist
|
|
|
if ($self->{'mustexist'}) {
|
|
|
for my $f (keys %{$self->{'files'}}) {
|
|
|
die "File \'$f\' doesn't exist.\n" if (! -f $f);
|
|
|
}
|
|
|
}
|
|
|
my @texmfdbs = mktexlsr::find_default_lsr_trees();
|
|
|
# filter files into the respective trees
|
|
|
my %dbs;
|
|
|
for my $p (keys %{$self->{'files'}}) {
|
|
|
for my $db (@texmfdbs) {
|
|
|
# remove terminal / if present
|
|
|
$db =~ s|/$||;
|
|
|
# lowercase for Windows
|
|
|
$db = lc($db) if mktexlsr::win32();
|
|
|
# search path
|
|
|
my $used_path = mktexlsr::win32() ? lc($p) : $p;
|
|
|
# check whether $p/$used_path is a file in $db
|
|
|
# we append a / to make sure that subdirs do not overlap (texmf/-dist)
|
|
|
if ( substr($used_path, 0, length("$db/")) eq "$db/" ) {
|
|
|
# fie $p/$used_path resides in the current $db
|
|
|
# strip initial $db/
|
|
|
my $filepart = substr($used_path, length("$db/"));
|
|
|
$dbs{$db}{$filepart} = 1;
|
|
|
last; # of the db loops!
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
#
|
|
|
# now do the actual work
|
|
|
for my $db (keys %dbs) {
|
|
|
if (! -d $db) {
|
|
|
if (! mktexlsr::mkdirhier($db) ) {
|
|
|
die "Cannot create directory $db: $!";
|
|
|
}
|
|
|
}
|
|
|
my $lsr = new TeX::LSR(root => $db);
|
|
|
# load either from ls-R or tree
|
|
|
$lsr->load() || die "Cannot load ls-R in $db.";
|
|
|
$lsr->addfiles(keys %{$dbs{$db}}) || die "Cannot add some file to $db.";
|
|
|
$lsr->write() || die "Cannot write ls-R in $db.";
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=back
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
|
|
|
#############################################################
|
|
|
#
|
|
|
# back to main mktexlsr package/program.
|
|
|
|
|
|
package mktexlsr;
|
|
|
|
|
|
sub main {
|
|
|
GetOptions("dry-run|n" => \$opt_dryrun,
|
|
|
"help|h" => \$opt_help,
|
|
|
"verbose!" => \$opt_verbose,
|
|
|
"quiet|q|silent" => sub { $opt_verbose = 0 },
|
|
|
"sort" => \$opt_sort,
|
|
|
"output|o=s" => \$opt_output,
|
|
|
"follow!" => \$opt_follow,
|
|
|
"version|v" => \$opt_version)
|
|
|
|| pod2usage(2);
|
|
|
|
|
|
pod2usage(-verbose => 2, -exitval => 0) if $opt_help;
|
|
|
|
|
|
if ($opt_version) {
|
|
|
print version();
|
|
|
exit (0);
|
|
|
}
|
|
|
|
|
|
if ($opt_output && $#ARGV != 0) {
|
|
|
# we only support --output with only one tree as argument
|
|
|
die "$prg: with --output, exactly one tree must be given: @ARGV\n";
|
|
|
}
|
|
|
|
|
|
for my $t (find_lsr_trees()) {
|
|
|
my $lsr = new TeX::LSR(root => $t);
|
|
|
print "$prg: Updating $t...\n" if $opt_verbose;
|
|
|
if ($lsr->loadtree()) {
|
|
|
if ($opt_dryrun) {
|
|
|
print "$prg: Dry run, not writing files.\n" if $opt_dryrun;
|
|
|
} elsif ($opt_output) {
|
|
|
#warn "writing to $opt_output\n";
|
|
|
$lsr->write(filename => $opt_output, sort => $opt_sort);
|
|
|
} else {
|
|
|
#warn "writing with sort=$opt_sort\n";
|
|
|
$lsr->write(sort => $opt_sort);
|
|
|
}
|
|
|
} else {
|
|
|
warn "$prg: cannot read files, skipping: $t\n";
|
|
|
}
|
|
|
}
|
|
|
print "$prg: Done.\n" if $opt_verbose;
|
|
|
}
|
|
|
|
|
|
sub find_default_lsr_trees {
|
|
|
# the shellfile used kpsewhich --show-path=ls-R | tr : '\n'
|
|
|
# seems to be simpler than using -var-value TEXMFDBS and
|
|
|
# fixing the return value
|
|
|
my $delim = win32() ? ';' : ':';
|
|
|
chomp( my $t = `kpsewhich -show-path=ls-R` );
|
|
|
my @texmfdbs = split($delim, $t);
|
|
|
return @texmfdbs;
|
|
|
}
|
|
|
|
|
|
sub find_lsr_trees {
|
|
|
my %lsrs;
|
|
|
my @candidates = @ARGV;
|
|
|
if (!@candidates) {
|
|
|
@candidates = find_default_lsr_trees();
|
|
|
}
|
|
|
for my $t (@candidates) {
|
|
|
my $ret;
|
|
|
eval {$ret = Cwd::abs_path($t);}; # eval needed for w32
|
|
|
if ($ret) {
|
|
|
$lsrs{$ret} = 1;
|
|
|
} else {
|
|
|
# ignored, we simply skip directories that don't exist
|
|
|
}
|
|
|
}
|
|
|
return sort(keys %lsrs);
|
|
|
}
|
|
|
|
|
|
sub version {
|
|
|
my $ret = sprintf "%s version %s\n", $prg, $version;
|
|
|
return $ret;
|
|
|
}
|
|
|
|
|
|
|
|
|
sub win32 {
|
|
|
return ( ($^O =~ /^MSWin/i) ? 1 : 0 );
|
|
|
}
|
|
|
|
|
|
# copied from TLUtils.pm
|
|
|
sub mkdirhier {
|
|
|
my ($tree,$mode) = @_;
|
|
|
|
|
|
return if (-d "$tree");
|
|
|
my $subdir = "";
|
|
|
# win32 is special as usual: we need to separate //servername/ part
|
|
|
# from the UNC path, since (! -d //servername/) tests true
|
|
|
$subdir = $& if ( win32() && ($tree =~ s!^//[^/]+/!!) );
|
|
|
|
|
|
my @dirs = split (/\//, $tree);
|
|
|
for my $dir (@dirs) {
|
|
|
$subdir .= "$dir/";
|
|
|
if (! -d $subdir) {
|
|
|
if (defined $mode) {
|
|
|
mkdir ($subdir, $mode)
|
|
|
|| die "$0: mkdir($subdir,$mode) failed, goodbye: $!\n";
|
|
|
} else {
|
|
|
mkdir ($subdir) || die "$0: mkdir($subdir) failed, goodbye: $!\n";
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
# for module loading!
|
|
|
1;
|
|
|
|
|
|
=pod
|
|
|
|
|
|
=head1 FURTHER INFORMATION AND BUG REPORTING
|
|
|
|
|
|
For more information, see the `Filename database' section of
|
|
|
Kpathsea manual available at http://tug.org/kpathsea.
|
|
|
|
|
|
Report bugs to: tex-k@tug.org
|
|
|
|
|
|
=head1 AUTHORS AND COPYRIGHT
|
|
|
|
|
|
This script and its documentation were written for the TeX Live
|
|
|
distribution (L<http://tug.org/texlive>) and both are licensed under the
|
|
|
GNU General Public License Version 2 or later.
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
### Local Variables:
|
|
|
### perl-indent-level: 2
|
|
|
### tab-width: 2
|
|
|
### indent-tabs-mode: nil
|
|
|
### End:
|
|
|
# vim:set tabstop=2 expandtab: #
|
|
|
|