BEGIN {
use Exporter ();
use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
- $VERSION = 0.03;
+ $VERSION = 0.04;
@ISA = qw (Exporter);
#Give a hoot don't pollute, do not export more than needed by default
@EXPORT = qw ();
=head1 SYNOPSIS
- use IsisDB
+ use IsisDB;
+
my $isis = new IsisDB(
isisdb => './cds/cds',
);
+ for(my $mfn = 1; $mfn <= $isis->{'maxmfn'}; $mfn++) {
+ print $isis->to_ascii($mfn),"\n";
+ }
+
=head1 DESCRIPTION
This module will read CDS/ISIS databases and create hash values out of it.
It can be used as perl-only alternative to OpenIsis module.
+This will module will always be slower that OpenIsis module which use C
+library. However, since it's written in perl, it's platform independent (so
+you don't need C compiler), and can be easily modified.
+
+Unique feature of this module is ability to C<include_deleted> records.
+It will also skip zero sized fields (OpenIsis has a bug in XS bindings, so
+fields which are zero sized will be filled with random junk from memory).
+
=head1 METHODS
=cut
# some binary reads
#
-sub Read32 {
- my $self = shift;
-
- my $f = shift || die "Read32 needs file handle";
- read($$f,$b,4) || die "can't read 4 bytes from $$f from position ".tell($f);
- return unpack("l",$b);
-}
-
=head2 new
Open CDS/ISIS database
my $isis = new IsisDB(
isisdb => './cds/cds',
read_fdt => 1,
- debug => 1,
include_deleted => 1,
+ hash_filter => sub {
+ my $v = shift;
+ $v =~ s#foo#bar#g;
+ },
+ debug => 1,
);
Options are described below:
Boolean flag to specify if field definition table should be read. It's off
by default.
-=item debug
+=item include_deleted
-Dump a C<lot> of debugging output.
+Don't skip logically deleted records in ISIS.
-=item include_deleted
+=item hash_filter
+
+Filter code ref which will be used before data is converted to hash.
+
+=item debug
-Don't skip logically deleted records.
+Dump a B<lot> of debugging output.
=back
croak "new needs database name (isisdb) as argument!" unless ({@_}->{isisdb});
- foreach my $v (qw{isisdb debug include_deleted}) {
+ foreach my $v (qw{isisdb debug include_deleted hash_filter}) {
$self->{$v} = {@_}->{$v};
}
# NXTMFP offset to next available position in last block
# MFTYPE always 0 for user db file (1 for system)
seek(fileMST,4,0);
- $self->{'NXTMFN'}=$self->Read32(\*fileMST) || carp "NXTNFN is zero";
+
+ my $buff;
+
+ read(fileMST, $buff, 4);
+ $self->{'NXTMFN'}=unpack("l",$buff) || carp "NXTNFN is zero";
# save maximum MFN
$self->{'maxmfn'} = $self->{'NXTMFN'} - 1;
}
}
- my $buff;
read(fileCNT, $buff, 26);
$self->unpack_cnt($buff);
my $rec = $isis->fetch(55);
Returns hash with keys which are field names and values are unpacked values
-for that field.
+for that field (like C<^asometing^bsomething else>)
=cut
print "seeking to $mfnpos in file '$self->{isisdb}.XRF'\n" if ($self->{debug});
seek($self->{'fileXRF'},$mfnpos,0);
+ my $buff;
+
# read XRFMFB abd XRFMFP
- my $pointer=$self->Read32(\*{$self->{'fileXRF'}});
+ read($self->{'fileXRF'}, $buff, 4);
+ my $pointer=unpack("l",$buff) || carp "pointer is null";
my $XRFMFB = int($pointer/2048);
my $XRFMFP = $pointer - ($XRFMFB*2048);
seek($self->{'fileMST'},$offset4,0);
- my $value=$self->Read32(\*{$self->{'fileMST'}});
+ read($self->{'fileMST'}, $buff, 4);
+ my $value=unpack("l",$buff);
if ($value!=$mfn) {
print ("Error: The MFN:".$mfn." is not found in MST(".$value.")");
# $NVF=$self->Read16($fileMST);
# $STATUS=$self->Read16($fileMST);
- my $buff;
read($self->{'fileMST'}, $buff, 14);
my ($MFRL,$MFBWB,$MFBWP,$BASE,$NVF,$STATUS) = unpack("slssss", $buff);
read($self->{'fileMST'},$buff,$fld_len);
for (my $i = 0 ; $i < $NVF ; $i++) {
+ # skip zero-sized fields
+ next if ($FieldLEN[$i] == 0);
+
push @{$self->{record}->{$FieldTAG[$i]}}, substr($buff,$FieldPOS[$i],$FieldLEN[$i]);
}
close(fileMST);
return $out;
}
+=head2 to_hash
+
+Read mfn and convert it to hash
+
+ my $hash = $isis->to_hash($mfn);
+
+It has ability to convert characters (using C<hash_filter> from ISIS
+database before creating structures enabling character remapping or quick
+fixup of data.
+
+This function returns hash which is like this:
+
+ $hash = {
+ '210' => [
+ {
+ 'c' => 'New York University press',
+ 'a' => 'New York',
+ 'd' => 'cop. 1988'
+ }
+ ],
+ '990' => [
+ '2140',
+ '88',
+ 'HAY'
+ ],
+ };
+
+You can later use that has to produce any output from ISIS data.
+
+=cut
+
+sub to_hash {
+ my $self = shift;
+
+ my $mfn = shift || confess "need mfn!";
+
+ my $rec;
+ my $row = $self->fetch($mfn);
+
+ foreach my $k (keys %{$row}) {
+ foreach my $l (@{$row->{$k}}) {
+
+ # filter output
+ $l = $self->{'hash_filter'}->($l) if ($self->{'hash_filter'});
+
+ # has subfields?
+ my $val;
+ if ($l =~ m/\^/) {
+ foreach my $t (split(/\^/,$l)) {
+ next if (! $t);
+ $val->{substr($t,0,1)} = substr($t,1);
+ }
+ } else {
+ $val = $l;
+ }
+
+ push @{$rec->{$k}}, $val;
+ }
+ }
+
+ return $rec;
+}
+
#
# XXX porting from php left-over:
#