autoconf/lib/Autom4te/FileUtils.pm
Paul Eggert 6b1c07685a Use "file name" rather than "filename" or "path",
to be consistent with the terminology of the GNU coding standards.
2004-08-20 19:58:06 +00:00

331 lines
6.5 KiB
Perl

# Copyright (C) 2003 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
package Autom4te::FileUtils;
=head1 NAME
Autom4te::FileUtils - handling files
=head1 SYNOPSIS
use Autom4te::FileUtils
=head1 DESCRIPTION
This perl module provides various general purpose file handling functions.
=cut
use strict;
use Exporter;
use File::stat;
use IO::File;
use Autom4te::Channels;
use Autom4te::ChannelDefs;
use vars qw (@ISA @EXPORT);
@ISA = qw (Exporter);
@EXPORT = qw (&contents
&find_file &mtime
&update_file &up_to_date_p
&xsystem &xqx);
=item C<find_file ($file_name, @include)>
Return the first name for a C<$file_name> in the C<include>s path.
We match exactly the behavior of GNU M4: first look in the current
directory (which includes the case of absolute file names), and, if
the file is not absolute, just fail. Otherwise, look in C<@include>.
If the file is flagged as optional (ends with C<?>), then return undef
if absent, otherwise exit with error.
=cut
# $FILE-NAME
# find_file ($FILE-NAME, @INCLUDE)
# --------------------------------
sub find_file ($@)
{
use File::Spec;
my ($file_name, @include) = @_;
my $optional = 0;
$optional = 1
if $file_name =~ s/\?$//;
return File::Spec->canonpath ($file_name)
if -e $file_name;
if (File::Spec->file_name_is_absolute ($file_name))
{
fatal "$file_name: no such file or directory"
unless $optional;
return undef;
}
foreach my $dir (@include)
{
return File::Spec->canonpath (File::Spec->catfile ($dir, $file_name))
if -e File::Spec->catfile ($dir, $file_name)
}
fatal "$file_name: no such file or directory"
unless $optional;
return undef;
}
=item C<mtime ($file)>
Return the mtime of C<$file>. Missing files, or C<-> standing for
C<STDIN> or C<STDOUT> are ``obsolete'', i.e., as old as possible.
=cut
# $MTIME
# MTIME ($FILE)
# -------------
sub mtime ($)
{
my ($file) = @_;
return 0
if $file eq '-' || ! -f $file;
my $stat = stat ($file)
or fatal "cannot stat $file: $!";
return $stat->mtime;
}
=item C<update_file ($from, $to)>
Rename C<$from> as C<$to>, preserving C<$to> timestamp if it has not
changed. Recognize C<$to> = C<-> standing for C<STDIN>. C<$from> is
always removed/renamed.
=cut
# &update_file ($FROM, $TO)
# -------------------------
sub update_file ($$)
{
my ($from, $to) = @_;
my $SIMPLE_BACKUP_SUFFIX = $ENV{'SIMPLE_BACKUP_SUFFIX'} || '~';
use File::Compare;
use File::Copy;
if ($to eq '-')
{
my $in = new IO::File ("$from");
my $out = new IO::File (">-");
while ($_ = $in->getline)
{
print $out $_;
}
$in->close;
unlink ($from) || fatal "cannot remove $from: $!";
return;
}
if (-f "$to" && compare ("$from", "$to") == 0)
{
# File didn't change, so don't update its mod time.
msg 'note', "`$to' is unchanged";
unlink ($from)
or fatal "cannot remove $from: $!";
return
}
if (-f "$to")
{
# Back up and install the new one.
move ("$to", "$to$SIMPLE_BACKUP_SUFFIX")
or fatal "cannot backup $to: $!";
move ("$from", "$to")
or fatal "cannot rename $from as $to: $!";
msg 'note', "`$to' is updated";
}
else
{
move ("$from", "$to")
or fatal "cannot rename $from as $to: $!";
msg 'note', "`$to' is created";
}
}
=item C<up_to_date_p ($file, @dep)>
Is C<$file> more recent than C<@dep>?
=cut
# $BOOLEAN
# &up_to_date_p ($FILE, @DEP)
# ---------------------------
sub up_to_date_p ($@)
{
my ($file, @dep) = @_;
my $mtime = mtime ($file);
foreach my $dep (@dep)
{
if ($mtime < mtime ($dep))
{
verb "up_to_date ($file): outdated: $dep";
return 0;
}
}
verb "up_to_date ($file): up to date";
return 1;
}
=item C<handle_exec_errors ($command)>
Display an error message for C<$command>, based on the content of
C<$?> and C<$!>.
=cut
# handle_exec_errors ($COMMAND)
# -----------------------------
sub handle_exec_errors ($)
{
my ($command) = @_;
$command = (split (' ', $command))[0];
if ($!)
{
fatal "failed to run $command: $!";
}
else
{
use POSIX qw (WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
if (WIFEXITED ($?))
{
my $status = WEXITSTATUS ($?);
# Propagate exit codes.
fatal ('',
"$command failed with exit status: $status",
exit_code => $status);
}
elsif (WIFSIGNALED ($?))
{
my $signal = WTERMSIG ($?);
fatal "$command terminated by signal: $signal";
}
else
{
fatal "$command exited abnormally";
}
}
}
=item C<xqx ($command)>
Same as C<qx> (but in scalar context), but fails on errors.
=cut
# xqx ($COMMAND)
# --------------
sub xqx ($)
{
my ($command) = @_;
verb "running: $command";
$! = 0;
my $res = `$command`;
handle_exec_errors $command
if $?;
return $res;
}
=item C<xsystem ($command)>
Same as C<system>, but fails on errors, and reports the C<$command>
in verbose mode.
=cut
# xsystem ($COMMAND)
# ------------------
sub xsystem ($)
{
my ($command) = @_;
verb "running: $command";
$! = 0;
handle_exec_errors $command
if system $command;
}
=item C<contents ($file_name)>
Return the contents of c<$file_name>.
=cut
# contents ($FILE-NAME)
# ---------------------
sub contents ($)
{
my ($file) = @_;
verb "reading $file";
local $/; # Turn on slurp-mode.
my $f = new Autom4te::XFile "< $file";
my $contents = $f->getline;
$f->close;
return $contents;
}
1; # for require
### Setup "GNU" style for perl-mode and cperl-mode.
## Local Variables:
## perl-indent-level: 2
## perl-continued-statement-offset: 2
## perl-continued-brace-offset: 0
## perl-brace-offset: 0
## perl-brace-imaginary-offset: 0
## perl-label-offset: -2
## cperl-indent-level: 2
## cperl-brace-offset: 0
## cperl-continued-brace-offset: 0
## cperl-label-offset: -2
## cperl-extra-newline-before-brace: t
## cperl-merge-trailing-else: nil
## cperl-continued-statement-offset: 2
## End: