#!/usr/bin/perl -w

if(($#ARGV < 0) || ($ARGV[0] eq "help")) {
    print STDERR "usage:\n";
    print STDERR "\tcdtool add {FILES|-g GRAFTPOINT}...\n";
    print STDERR "\tcdtool ls\n";
    print STDERR "\tcdtool rm NAME\n";
    print STDERR "\tcdtool szck\n";
    print STDERR "\tcdtool setgp [GRAFTPOINT]\n";
    print STDERR "\tcdtool setimg [IMAGE]\n";
    print STDERR "\tcdtool mkiso\n";
    exit 1;
}

if(-r $ENV{"HOME"} . "/.cdtool") {
    if(open CF, $ENV{"HOME"} . "/.cdtool") {
	while(<CF>) {
	    next if /^\#/;
	    if(/^(\S+)\s+(.*)$/) {
		if($1 eq "gp") {
		    $curgraft = $2;
		} elsif($1 eq "img") {
		    $curimage = $2;
		} else {
		    print STDERR "cdtool: warning: unknown .cdtool directive: $1\n";
		}
	    }
	}
	close CF;
    }
}

sub canonpath {
    my($path) = @_;
    $path = "./" . $path unless $path =~ m,^/,;
    $path =~ s,/$,,;
    $trailer = "";
    while(!-d $path) {
	$path =~ s,/+([^/]*)$,,;
	$trailer .= "/" . $1;
	if($path eq "") {
	    die "weird path given: $_[0]";
	}
    }
    if(!open CHILD, "-|") {
	chdir $path;
	exec "pwd";
	die;
    }
    chomp($cpath = <CHILD>);
    close CHILD;
    return "$cpath$trailer";
}

sub dirname {
    my($path) = @_;
    $path =~ s,/[^/]+/*$,,;
    return $path;
}

sub addfile {
    my($file, $graft) = @_;
    my($dir, $f, $basename);
    $basename = $file;
    $basename =~ s,^.*/,,;
    if(-f $file) {
	print "add $file to $graft\n" if $verbose;
	$img{"$graft$basename"} = $file;
    } elsif(-d $file) {
	$dir = canonpath $file;
	if(opendir DIR, "$dir") {
	    for $f (sort grep !/^\./, readdir DIR) {
		addfile("$dir/$f", "$graft$basename/");
	    }
	    closedir DIR;
	} else {
	    print STDERR "cdtool: could not open $file for listing: $!\n";
	}
    } else {
	print STDERR "cdtool: $file: not a regular file or directory\n";
    }
}

sub readimage {
    my($file, $dieonerr) = @_;
    $dieonerr = 1 unless defined $dieonerr;
    if(!open(IMG, "<", $file)) {
	if($dieonerr) {
	    die "$file: $!";
	} else {
	    return;
	}
    }
    while(<IMG>) {
	if(/^file (.*):::(.*)$/) {
	    $img{$1} = $2;
	} elsif(/^name (.*)$/) {
	    $imgname = $1;
	} elsif(/^rev (\d+)$/) {
	    $rev = $1;
	} elsif(/^justburned/) {
	    $justburned = 1;
	}
    }
    close IMG;
}

sub writeimage {
    my($file) = @_;
    open(IMG, ">", $file) || die "$file: $!";
    print IMG "rev $rev\n";
    print IMG "justburned\n" if $justburned;
    for $f (sort keys %img) {
	print IMG ("file " . $f . ":::" . $img{$f} . "\n");
    }
    close IMG;
}
    
$image = $curimage;
$imgname = $image;
$justburned = 0;
$imgname =~ s,^.*/,,;
$rev = 1;
$verbose = 0;

while(($arg = shift @ARGV) =~ /^-(.+)/) {
    $opts = $1;
    while($opts =~ s/^(.)//) {
	if($1 eq "v") {
	    $verbose = 1;
	}
    }
}

$cmd = $arg;
if($cmd eq "add") {
    if(!defined $image) {
	print STDERR "cdtool: no image defined for adding\n";
	exit 1;
    }
    
    readimage $image, 0;
    $justburned = 0;
    $graft = $curgraft;
    $graft .= "/" unless $graft eq "";
    while(defined($arg = shift @ARGV)) {
	if($arg eq "-g") {
	    $graft = shift @ARGV;
	    $graft =~ s,/+$,,;
	    $graft .= "/" unless $graft eq "";
	} else {
	    if(!defined $graft) {
		print STDERR "cdtool: no graft point defined when adding\n";
		exit 1;
	    }
	    addfile canonpath($arg), $graft
	}
    }
    writeimage $image;
} elsif($cmd eq "ls") {
    readimage $image;
    for $gf (sort keys %img) {
	print "$gf\n";
    }
} elsif($cmd eq "rm") {
    die "no name specified" unless defined($file = shift @ARGV);
    $file = canonpath $file;
    readimage $image;
    $found = 0;
    if(-d $file) {
	$file .= "/";
	for $gname (grep substr($img{$_}, 0, length $file) eq $file, keys %img) {
	    delete $img{$gname};
	    $found = 1;
	}
    } else {
	for $gname (grep $img{$_} eq $file, keys %img) {
	    delete $img{$gname};
	    $found = 1;
	}
    }
    if(!$found) {
	print STDERR "cdtool: $file not found in image\n";
	exit 1;
    }
    $justburned = 0;
    writeimage $image;
} elsif($cmd eq "szck") {
    readimage $image;
    $size = 0;
    for $file (values %img) {
	$size += -s $file;
    }
    $size =~ s/(\d{3})/$1,/g;
    $size =~ s/,$//;
    print "$size\n";
} elsif($cmd eq "setgp") {
    $curgraft = shift @ARGV;
    $curgraft =~ s,/+$,,;
} elsif($cmd eq "setimg") {
    $curimage = shift @ARGV;
} elsif($cmd eq "imgck") {
    readimage $image;
    for $file (values %img) {
	if(! -r $file) {
	    print "$file\n";
	}
    }
} elsif($cmd eq "mkiso") {
    readimage $image;
    open(ISO, "|-", "mkisofs", "-J", "-R", "-V", "$imgname r$rev", "-graft-points", "-path-list", "-") || die "mkisofs: $!";
    for $gf (sort keys %img) {
	print ISO ($gf . "=" . $img{$gf} . "\n");
    }
    close ISO;
    if(!$justburned) {
	$rev++;
	$justburned = 1;
    }
    writeimage $image;
} else {
    print STDERR "cdtool: unknown command: $cmd\n";
    exit 1;
}

die if(!open CF, ">" . $ENV{"HOME"} . "/.cdtool");
if(defined $curgraft) {
    print CF "gp $curgraft\n";
}
if(defined $curimage) {
    print CF "img $curimage\n";
}
close CF;
