#!/usr/bin/perl -w

use IO::File;
use strict;

my $fields_in = ($ARGV[0]||'') eq "F"
	and shift;

@ARGV == 2
	or die "usage $0 [F] field_types table.dat < table\n";

my ($field_types, $msql_dat) = @ARGV;

# load_field_types
# ------------------------------------------------------------
my @fields;
{
	my $file = IO::File->new($field_types);
	my $line;
	while (defined ($line = <$file>)) {
		chomp $line;
		my ($field, $type, $size) = split /\t/, $line, -1;
		push @fields, [$field, $type, $size];
	}
}

# build packer
# ------------------------------------------------------------
my $packer = "";
my $record_len = 0;
{
	for my $fieldref (@fields) {
		my ($field, $type, $size) = @$fieldref;

		$packer .= "c1"; # for `null' byte
		$record_len ++;

		if ($type eq "char") {
			$packer .= "a$size";
			$record_len += $size;
		} elsif ($type eq "int") {
			$packer .= "i";
			$record_len += 4;
		} elsif ($type eq "real") {
			$packer .= "dc"; # XXX this is certainly wrong!
			$record_len += 8;
		} else {
			die "unknown field type `$type'\n";
		}
	}
}

# strip fields if wanted
# ------------------------------------------------------------
if ($fields_in) {
	my $guff = <STDIN>;
}

# convert the data
# ------------------------------------------------------------
my $record_block = (8 + $record_len + 8) & ~7;
$packer = "ii${packer}a*"; # for zeros on end

my $out = IO::File->new($msql_dat, "w")
	or die "cannot create `$msql_dat'\n";

my $buf;

my $sig = 20;
my $null = "\0" x 8;

# write the table header, we will fill it in later
$buf = pack "iiiia8", ($sig, -1, 0, 0, $null);
print $out $buf;

my $count_active_rows = 0;

my $time = time;
my $in_use = 1;

my $line;
my @row;
while (defined ($line = <STDIN>)) {
	chomp $line;
	@row = split /\t/, $line, -1;
	for (@row) {
		if ($_ eq "\0") {
			undef $_;
		} else {
			s/([^\\]|^)((?:\\\\)*)\\0/$1$2\0/g;
			s/([^\\]|^)((?:\\\\)*)\\n/$1$2\n/g;
			s/([^\\]|^)((?:\\\\)*)\\t/$1$2\t/g;
			s/\\\\/\\/g;
		}
	}

	@row == @fields
		or warn "wrong number of fields unpacked from row!!";

	$count_active_rows ++;
		
	my @data = ($in_use, $time);

	for (@row) {
		if (defined $_) {
			push @data, 1, $_;
		} else {
			push @data, 0, '';
		}
	}

	$buf = pack $packer, @data;
	my $zeros = $record_block - length $buf;
	warn "row too long!" if $zeros < 0;
	$buf .= "\0" x $zeros;
	
	print $out $buf;
}

$out->seek(0, SEEK_SET);

# write the table header, properly this time!
$buf = pack "iiiia8", ($sig, -1, $count_active_rows, $count_active_rows, $null);
print $out $buf;

close $out;
