Once again syncing after too long an absence
[p5sagit/p5-mst-13.2.git] / lib / Search / Dict.pm
CommitLineData
a0d0e21e 1package Search::Dict;
2require 5.000;
3require Exporter;
4
0e06870b 5use strict;
6
7our $VERSION = '1.00';
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;
18 look *FILEHANDLE, $key, $dict, $fold;
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
29characters and whitespace).
30
31If I<$fold> is true, ignore case.
32
33=cut
a0d0e21e 34
35sub look {
0e06870b 36 my($fh,$key,$dict,$fold) = @_;
5be1dfc7 37 local($_);
0e06870b 38 my(@stat) = stat($fh)
5be1dfc7 39 or return -1;
40 my($size, $blksize) = @stat[7,11];
41 $blksize ||= 8192;
a0d0e21e 42 $key =~ s/[^\w\s]//g if $dict;
df76f08a 43 $key = lc $key if $fold;
5be1dfc7 44 my($min, $max, $mid) = (0, int($size / $blksize));
a0d0e21e 45 while ($max - $min > 1) {
46 $mid = int(($max + $min) / 2);
0e06870b 47 seek($fh, $mid * $blksize, 0)
5be1dfc7 48 or return -1;
0e06870b 49 <$fh> if $mid; # probably a partial line
50 $_ = <$fh>;
a0d0e21e 51 chop;
52 s/[^\w\s]//g if $dict;
df76f08a 53 $_ = lc $_ if $fold;
5be1dfc7 54 if (defined($_) && $_ lt $key) {
a0d0e21e 55 $min = $mid;
56 }
57 else {
58 $max = $mid;
59 }
60 }
61 $min *= $blksize;
0e06870b 62 seek($fh,$min,0)
5be1dfc7 63 or return -1;
0e06870b 64 <$fh> if $min;
5be1dfc7 65 for (;;) {
0e06870b 66 $min = tell($fh);
67 defined($_ = <$fh>)
5be1dfc7 68 or last;
a0d0e21e 69 chop;
70 s/[^\w\s]//g if $dict;
df76f08a 71 $_ = lc $_ if $fold;
a0d0e21e 72 last if $_ ge $key;
a0d0e21e 73 }
0e06870b 74 seek($fh,$min,0);
a0d0e21e 75 $min;
76}
77
781;