1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
#
# Suck a self-describing table into memory.
#
# Usage: $table = &suck_table(pathname)
#
# Each table has the following components:
#
# - 'origin' is a hash table with host and time information.
#
# - 'labels' is a hash table that maps data field names to offsets 0..m
#
# - 'data' is an array of (array 0..m with data extracted from file).
#
sub suck_table {
local($path) = @_;
local(%table, @labels, @data, $offset, $n, $line, $ref);
open(TABLE, "<$path") || die "Cannot open $path: $!\n";
#
# The file starts with origin information (host, time, etc.).
#
chop($line = <TABLE>);
(@labels = &tm_split($line))
|| die "$path: No origin dictionary record.\n";
chop($line = <TABLE>);
(@data = &tm_split($line))
|| die "$path: No origin data record.\n";
($#labels == $#data)
|| die "$path: Inconsistent origin field count.\n";
for $offset (0..$#labels) {
$table{'origin'}{@labels[$offset]} = @data[$offset];
}
#
# Read the data dictionary.
#
chop($line = <TABLE>);
(@labels = &tm_split($line))
|| die "$path: No data dictionary record.\n";
for $offset (0..$#labels) {
$table{'labels'}{@labels[$offset]} = $offset;
}
#
# Read the actual data. This is done most often so it needs to be fast.
# Use references to avoid hash table lookups.
#
$ref = \@{$table{'data'}};
for ($n = 0; chop($line = <TABLE>); $n++) {
@{$ref->[$n]} = &tm_split($line);
($#labels > $#{$ref->[$n]})
&& ($#{$ref->[$n]} = $#labels);
($#labels == $#{$ref->[$n]})
|| die "$path: Inconsistent data field count $#labels != $#{$ref->[$n]}: $line\n";
}
#
# Cleanup.
#
close(TABLE);
return %table;
}
if (!$running_under_grave_robber) {
$running_under_grave_robber = 1;
require "tm_misc.pl";
&suck_table($ARGV[0]);
}
1;
|