Remove tiehandle code.
[p5sagit/p5-mst-13.2.git] / lib / Search / Dict.pm
CommitLineData
a0d0e21e 1package Search::Dict;
2require 5.000;
3require Exporter;
4
b75c8c73 5use strict;
6
37ef5c3b 7our $VERSION = '1.01';
b75c8c73 8our @ISA = qw(Exporter);
9our @EXPORT = qw(look);
a0d0e21e 10
5be1dfc7 11=head1 NAME
a0d0e21e 12
5be1dfc7 13Search::Dict, look - search for key in dictionary file
14
15=head1 SYNOPSIS
16
17 use Search::Dict;
37ef5c3b 18 look *FILEHANDLE, $key, $dict, $fold, $comp;
5be1dfc7 19
20=head1 DESCRIPTION
21
22Sets file position in FILEHANDLE to be first line greater than or equal
23(stringwise) to I<$key>. Returns the new file position, or -1 if an error
24occurs.
25
26The flags specify dictionary order and case folding:
27
28If I<$dict> is true, search by dictionary order (ignore anything but word
37ef5c3b 29characters and whitespace). The default is honour all characters.
5be1dfc7 30
37ef5c3b 31If I<$fold> is true, ignore case. The default is to honour case.
32
33If I<$comp> is defined, use that as a reference to the comparison subroutine,
34which must return less than zero, zero, or greater than zero, if the
35first comparand is less than, equal, or greater than the second comparand.
36
37If there are only three arguments and the third argument is a hash
38reference, the keys of that hash can have values C<dict>, C<fold>, and
39C<comp>, and their correponding values will be used as the parameters.
5be1dfc7 40
41=cut
a0d0e21e 42
43sub look {
37ef5c3b 44 my($fh,$key,$dict,$fold,$comp) = @_;
45 if (@_ == 3 && ref $dict eq 'HASH') {
46 my $opt = $dict;
47 $dict = 0;
48 $dict = $opt->{dict} if exists $opt->{dict};
49 $fold = $opt->{fold} if exists $opt->{fold};
50 $comp = $opt->{comp} if exists $opt->{comp};
51 }
52 $comp = sub { $_[0] cmp $_[1] } unless defined $comp;
5be1dfc7 53 local($_);
b75c8c73 54 my(@stat) = stat($fh)
5be1dfc7 55 or return -1;
56 my($size, $blksize) = @stat[7,11];
57 $blksize ||= 8192;
a0d0e21e 58 $key =~ s/[^\w\s]//g if $dict;
37ef5c3b 59 $key = lc $key if $fold;
60 # find the right block
61 my($min, $max) = (0, int($size / $blksize));
62 my $mid;
a0d0e21e 63 while ($max - $min > 1) {
64 $mid = int(($max + $min) / 2);
b75c8c73 65 seek($fh, $mid * $blksize, 0)
5be1dfc7 66 or return -1;
b75c8c73 67 <$fh> if $mid; # probably a partial line
68 $_ = <$fh>;
37ef5c3b 69 chomp;
a0d0e21e 70 s/[^\w\s]//g if $dict;
37ef5c3b 71 $_ = lc $_ if $fold;
72 if (defined($_) && $comp->($_, $key) < 0) {
a0d0e21e 73 $min = $mid;
74 }
75 else {
76 $max = $mid;
77 }
78 }
37ef5c3b 79 # find the right line
a0d0e21e 80 $min *= $blksize;
b75c8c73 81 seek($fh,$min,0)
5be1dfc7 82 or return -1;
b75c8c73 83 <$fh> if $min;
5be1dfc7 84 for (;;) {
b75c8c73 85 $min = tell($fh);
86 defined($_ = <$fh>)
5be1dfc7 87 or last;
37ef5c3b 88 chomp;
a0d0e21e 89 s/[^\w\s]//g if $dict;
37ef5c3b 90 $_ = lc $_ if $fold;
91 last if $comp->($_, $key) >= 0;
a0d0e21e 92 }
b75c8c73 93 seek($fh,$min,0);
a0d0e21e 94 $min;
95}
96
971;