summaryrefslogtreecommitdiff
path: root/lib/Tie/File.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Tie/File.pm')
-rw-r--r--lib/Tie/File.pm105
1 files changed, 80 insertions, 25 deletions
diff --git a/lib/Tie/File.pm b/lib/Tie/File.pm
index 8ae70a67b7..b22f3e1b28 100644
--- a/lib/Tie/File.pm
+++ b/lib/Tie/File.pm
@@ -5,7 +5,7 @@ use POSIX 'SEEK_SET';
use Fcntl 'O_CREAT', 'O_RDWR', 'LOCK_EX';
require 5.005;
-$VERSION = "0.15";
+$VERSION = "0.16";
# Idea: The object will always contain an array of byte offsets
# this will be filled in as is necessary and convenient.
@@ -52,10 +52,20 @@ sub TIEARRAY {
}
my $mode = defined($opts{mode}) ? $opts{mode} : O_CREAT|O_RDWR;
+ my $fh;
- my $fh = \do { local *FH }; # only works in 5.005 and later
- sysopen $fh, $file, $mode, 0666 or return;
- binmode $fh;
+ if (UNIVERSAL::isa($file, 'GLOB')) {
+ unless (seek $file, 0, SEEK_SET) {
+ croak "$pack: your filehandle does not appear to be seekable";
+ }
+ $fh = $file;
+ } elsif (ref $file) {
+ croak "usage: tie \@array, $pack, filename, [option => value]...";
+ } else {
+ $fh = \do { local *FH }; # only works in 5.005 and later
+ sysopen $fh, $file, $mode, 0666 or return;
+ binmode $fh;
+ }
{ my $ofh = select $fh; $| = 1; select $ofh } # autoflush on write
$opts{fh} = $fh;
@@ -98,7 +108,10 @@ sub STORE {
my $oldrec = $self->FETCH($n);
# _check_cache promotes record $n to MRU. Is this correct behavior?
- $self->{cache}{$n} = $rec if $self->_check_cache($n);
+ if (my $cached = $self->_check_cache($n)) {
+ $self->{cache}{$n} = $rec;
+ $self->{cached} += length($rec) - length($cached);
+ }
if (not defined $oldrec) {
# We're storing a record beyond the end of the file
@@ -194,6 +207,9 @@ sub DELETE {
if ($n == $lastrec) {
$self->_seek($n);
$self->_chop_file;
+ $#{$self->{offsets}}--;
+ delete $self->{cached}{$n};
+ @{$self->{lru}} = grep $_ != $n, @{$self->{lru}};
# perhaps in this case I should also remove trailing null records?
} else {
$self->STORE($n, "");
@@ -493,8 +509,7 @@ sub _extend_file_to {
# Todo : just use $self->{recsep} x $extras here?
while ($extras-- > 0) {
$self->_write_record($self->{recsep});
- $pos += $self->{recseplen};
- push @{$self->{offsets}}, $pos;
+ push @{$self->{offsets}}, tell $self->{fh};
}
}
@@ -533,15 +548,17 @@ sub flock {
sub _check_integrity {
my ($self, $file, $warn) = @_;
my $good = 1;
- local *F = $self->{fh};
- seek F, 0, SEEK_SET;
-# open F, $file or die "Couldn't open file $file: $!";
-# binmode F;
- local $/ = $self->{recsep};
+
unless ($self->{offsets}[0] == 0) {
$warn && print STDERR "# rec 0: offset <$self->{offsets}[0]> s/b 0!\n";
$good = 0;
}
+
+ local *F = $self->{fh};
+ seek F, 0, SEEK_SET;
+ local $/ = $self->{recsep};
+ $. = 0;
+
while (<F>) {
my $n = $. - 1;
my $cached = $self->{cache}{$n};
@@ -549,6 +566,7 @@ sub _check_integrity {
my $ao = tell F;
if (defined $offset && $offset != $ao) {
$warn && print STDERR "# rec $n: offset <$offset> actual <$ao>\n";
+ $good = 0;
}
if (defined $cached && $_ ne $cached) {
$good = 0;
@@ -595,13 +613,15 @@ sub _check_integrity {
$good;
}
+"Cogito, ergo sum."; # don't forget to return a true value from the file
+
=head1 NAME
Tie::File - Access the lines of a disk file via a Perl array
=head1 SYNOPSIS
- # This file documents Tie::File version 0.15
+ # This file documents Tie::File version 0.16
tie @array, 'Tie::File', filename or die ...;
@@ -746,7 +766,7 @@ argument to the Perl built-in C<flock> function; for example
C<LOCK_SH> or C<LOCK_EX | LOCK_NB>. (These constants are provided by
the C<use Fcntl ':flock'> declaration.)
-C<MODE> is optional; C<< $o->flock >> simply locks the file with
+C<MODE> is optional; C<$o-E<gt>flock> simply locks the file with
C<LOCK_EX>.
The best way to unlock a file is to discard the object and untie the
@@ -765,6 +785,24 @@ have a green light, that does not prevent the idiot coming the other
way from plowing into you sideways; it merely guarantees to you that
the idiot does not also have a green light at the same time.
+=head2 Tying to an already-opened filehandle
+
+If C<$fh> is a filehandle, such as is returned by C<IO::File> or one
+of the other C<IO> modules, you may use:
+
+ tie @array, 'Tie::File', $fh, ...;
+
+Similarly if you opened that handle C<FH> with regular C<open> or
+C<sysopen>, you may use:
+
+ tie @array, 'Tie::File', \*FH, ...;
+
+Handles that were opened write-only won't work. Handles that were
+opened read-only will work as long as you don't try to write to them.
+Handles must be attached to seekable sources of data---that means no
+pipes or sockets. If you try to supply a non-seekable handle, the
+C<tie> call will abort your program.
+
=head1 CAVEATS
(That's Latin for 'warnings'.)
@@ -773,7 +811,7 @@ the idiot does not also have a green light at the same time.
Every effort was made to make this module efficient. Nevertheless,
changing the size of a record in the middle of a large file will
-always be slow, because everything after the new record must be move.
+always be slow, because everything after the new record must be moved.
In particular, note that:
@@ -805,7 +843,7 @@ The author has supposed that since this module is concerned with file
I/O, almost all normal use of it will be heavily I/O bound, and that
the time to maintain complicated data structures inside the module
will be dominated by the time to actually perform the I/O. This
-suggests, for example, that and LRU read-cache is a good tradeoff,
+suggests, for example, that an LRU read-cache is a good tradeoff,
even if it requires substantial adjustment following a C<splice>
operation.
@@ -838,7 +876,7 @@ C<mjd-perl-tiefile-subscribe@plover.com>.
=head1 LICENSE
-C<Tie::File> version 0.15 is copyright (C) 2002 Mark Jason Dominus.
+C<Tie::File> version 0.16 is copyright (C) 2002 Mark Jason Dominus.
This library is free software; you may redistribute it and/or modify
it under the same terms as Perl itself.
@@ -866,19 +904,34 @@ For licensing inquiries, contact the author at:
=head1 WARRANTY
-C<Tie::File> version 0.15 comes with ABSOLUTELY NO WARRANTY.
+C<Tie::File> version 0.16 comes with ABSOLUTELY NO WARRANTY.
For details, see the license.
-=head1 TODO
+=head1 THANKS
+
+Gigantic thanks to Jarkko Hietaniemi, for agreeing to put this in the
+core when I hadn't written it yet, and for generally being helpful,
+supportive, and competent. (Usually the rule is "choose any one.")
+Also big thanks to Abhijit Menon-Sen for all of the same things.
+
+Special thanks to Craig Berry (for VMS portability help), Randy Kobes
+(for Win32 portability help), the rest of the CPAN testers (for
+testing).
-Allow tie to seekable filehandle rather than named file.
+More thanks to:
+Gerrit Haase /
+Tassilo von Parseval /
+H. Dieter Pearcey /
+Peter Somu /
+Tels
-Tests for default arguments to SPLICE. Tests for CLEAR/EXTEND.
-Tests for DELETE/EXISTS.
+=head1 TODO
+
+Test DELETE machinery more carefully.
-More tests. (Configuration options, cache flushery, locking. _twrite
-should be tested separately, because there are a lot of weird special
-cases lurking in there.)
+More tests. (Configuration options, cache flushery. _twrite should
+be tested separately, because there are a lot of weird special cases
+lurking in there.)
More tests. (Stuff I didn't think of yet.)
@@ -890,5 +943,7 @@ More tests.
Fixed-length mode.
+Maybe an autolocking mode?
+
=cut