#!/usr/local/bin/perl
#
# $Id: pmvmac,v 0.50 2002/01/18 18:30:51 dankogai Exp $
#

use strict;
use Getopt::Std;
use File::stat;
use File::Basename;

my %Opt;
getopts("fivD", \%Opt);
$Opt{i} and delete $Opt{f}; # for safety

my $IAM = basename($0); 
my %Hardlink; # key = inode, val = name of first file copied

my $Dst = pop @ARGV; @ARGV or help();
my $Dstst = stat($Dst); # not lstat; symlink to directory allowed
unless (-d _){
    @ARGV == 1 or help();
    do_move($ARGV[0], $Dst);
}else{
    $Dst =~ s,/+$,,o; 
    for my $src (@ARGV){
	$src =~ s,/+$,,o; 
	do_move($src, $Dst . '/' . basename($src));
    }
}
exit;

use MacOSX::File::Copy;
use MacOSX::File::Catalog;
use File::Path;

sub do_move{
    my ($src, $dst) = @_;
    
    $Opt{v} and print STDERR "$src\n";

    # clean up destination

    if (my $dstst = lstat($dst)){
	$Opt{i} and prompt($dst) or return;
	rmtree([ $dst ]) or "warn; can't rmtree $dst" and return;
    }

    if ( lstat($src)->dev == $Dstst->dev ){
	$Opt{D} and warn "intra-device move";
	return move($src, $dst);
    }else{
	$Opt{D} and warn "cross-device move";
	my @cmd = $Opt{D} ? qw(perl -Mblib bin/pcpmac) : 'pcpmac';
	my $err = system(@cmd, '-pr', $src, $dst);
	$err == 0 and rmtree([ $src ]);
	$! and warn $!;
    }
}

sub prompt{
    my $path = shift;
    $| = 1;
    print "Overwrite $path? [y/N]:";
    my $answer = <STDIN>; chomp $answer;
    return lc($answer) eq 'y';
}

sub help{
    warn caller;
    print STDERR <<"EOT";
usage: $IAM [-f|-i] src target
       $IAM [-f|-i] src1 ... srcN directory
EOT
exit;
}
1;

__END__
=head1 NAME

pmvmac -- MvMac(1), or mv(1),  implemented as perl script

=head1 SYNOPSIS

 pmvmac [-f|-i]  source_file target_file
 pmvmac [-f|-i]  source_file ... target_directory

=head1 DESCRIPTION

pmvmac, as its name implies, moves files with finder info and
resource fork.  

In the first synopsis form, pmvmac renames the source_file to the
target_file.  In the second synopsis form, each named source_file is
moved to the destination target_directory.  The names of the files
themselves are not changed.  If mv detects an attempt to move a file
to itself, the copy will fail.

The following options are available:

=item -f

Foreach existing destination pathname, attempt to overwrite it. If
permissions do not allow move to succeed, remove it without prompting
for confirmation.

=item -i

Causes pmvmac to write a prompt to the standard error output before
copying a file that would overwrite an existing file.  If the response 
from the standard input begins with the character "y" or "Y", the
file move is attempted.

For safety, this option cancels -f option.  This is the opposite of
BSD mv implementation.

=item -v

Verbose mode.  Prints each items copied to standard output.

=head2 Cross-volume move

When mvmac tries to move items accross volumes, pmvmac uses pcpmac and
File::Path::rmtree() to accomplish the move.  The effect is equivalent
to:

  rm -f destination_path && $BB%(B
  pcpmac -r source_file destination && $BB%(B
  rm -rf source_file

=head1 AUTHOR

Dan Kogai <dankogai@dan.co.jp>

=head1 SEE ALSO

L<mv(1)>
L</Developer/Tools/MvMac>

=head1 COPYRIGHT

Copyright 2002 Dan Kogai <dankogai@dan.co.jp>

    This library is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.
