#!/usr/bin/perl -w
# Project: File-Utilities
# Descr:   Renaming of files acroding to their modification time
# Author:  Dr. Jürgen Vollmer <juergen@informatik-vollmer.de>
# Id: mv-date,v 1.5 2007/05/21 16:36:55 vollmer Exp $

require 5.006;
=pod

=head1 NAME

mv-date - a script to rename or copy files accroding to their modification time

=head1 SYNOPSIS

perl mv-date [<options>]* file ...

=head1 OPTIONS

  -A      :  use the atime of the files
  -M      :  use the mtime of the files (default)
  -C      :  use the ctime of the files
  -N      :  just renumber the files, ignore the date/time, start with 0
  -N nr   :  just renumber the files, start with nr
  -D nr   :  if -N is given, use nr digit (with leading zeros), default 4

  -c      :  copy the files, atime amd mtime are preserved
  -m      :  move the files (default)
  -n      :  do not perform copy/move, show only the resulting file
             names (note: -suffix is not added, since the new files
             are not created.

  -d dir  :  destination directory, default the directory as given
             by the filename. If the directory does not exists, it is
             created.

  -o      :  overwrite an exisiting file, default: add a suffix

  -p      :  prefix

  -h      :  help
  -v      :  verbose

=head1 DESCRIPTION

Renames (or copies) the files given as arguments. Compute the modification time
(any other time see options) and renames the files as:

    <path>/<prefix->YYYY-MM-DD-HH:MM:SS[-<suffix>].<ext>

where YYYY-MM-DD-HH:MM:SS is the selected time of the file and path may be
specified by the -d option.

If there is already a file with that name append a suffix: 1, 2,...

<ext> is replaced by its lowercase

=head1 EXAMPLE

assume you want to rename the following files with the modification dates
  001.IMG  Mar  4 10:40
  002.IMG  Mar  4 10:41
  003.IMG  Mar  4 10:41

the command
  mv-date -p foo *.IMG

will produce the following files:
  foo-2003-03-04-09:40:00.img
  foo-2003-03-04-09:41:00.img
  foo-2003-03-04-09:41:00-1.img

the command
  mv-date -N 1 -p *.IMG

will produce the following files:
  foo-0001.img
  foo-0002.img
  foo-0003.img

=head1 AUTHOR

Dr. Juergen Vollmer <juergen@informatik-vollmer.de>

If you find this software useful, I would be glad to receive a postcard
from you, showing the place where you're living.

=head1 HOMEPAGE

http://www.informatik-vollmer.de/software/mv-date.html

=head1 COPYRIGHT

Copyright (C) 2003 Dr. Juergen Vollmer, Viktoriastrasse 15,
D-76133 Karlsruhe, Germany.

=head1 LICENSE

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA  02111-1307  USA

=head1 VERSION
1.4 2007/05/21

=cut

use strict;
use English;
use Getopt::Long;
use POSIX "strftime";
use File::stat ":FIELDS";
use File::Basename;
use File::Copy;
use File::Spec::Functions;
use File::Path;

#############################################################################

my $CMD            = basename ($0);
my ($VERSION)	   = 'Revision: 1.5 $' =~ '(\d*\.\d*)';
my ($VERSION_DATE) = 'Date: 2007/05/21 16:36:55 $' =~ '(\d*/\d*/\d*)';

###############################################################################
## check command line options and arguments
###############################################################################

$Getopt::Long::oder          = $Getopt::Long::oder = $REQUIRE_ORDER;
$Getopt::Long::getopt_compat = 0;
$Getopt::Long::ignorecase    = 0;
my ($option_atime,   $option_mtime, $option_ctime,
    $option_copy,    $option_move,  $option_dry_run,
    $option_dir,     $option_overwrite,
    $option_prefix,  $option_renumber, $option_digits,
    $option_verbose, $option_help);

$option_digits = 4;

GetOptions("A"      => \$option_atime,
	   "C"      => \$option_ctime,
	   "M"      => \$option_mtime,
	   "N:i"    => \$option_renumber,
	   "D=i"    => \$option_digits,

	   "c"      => \$option_copy,
	   "m"      => \$option_move,
	   "n"      => \$option_dry_run,

	   "d=s"    => \$option_dir,
	   "o"      => \$option_overwrite,

	   "p=s"    => \$option_prefix,
	   "v"      => \$option_verbose,
	   "h"      => \$option_help,
	   );

sub usage
{
    my $perldoc = dirname ($EXECUTABLE_NAME) . "/perldoc";
    system ("$perldoc $0");
    exit;
}

usage if ($option_help);

my $action      = \&move;
my $action_text = "move";
if ($option_copy) {
    $action      = \&copy;
    $action_text = "copy";
}

if ($option_dir) {
    if (! -d $option_dir) {
	mkpath ($option_dir) ||
	    die "$CMD: can not create directory $option_dir\n";
    }
}

if ($option_prefix) {
    $option_prefix .= "-" if ($option_prefix !~ /.*-$/);
} else {
    $option_prefix = "";
}
#############################################################################

sub time2name ($)
# transforms a UNIX time specification (seconds since 1.1.1970) into
# a YYYY-MM-DD-HH:MM:SS format
# Arguments:   the UNIX time
# Returns:     the time as described above
{
    my $t = shift;
    return strftime ("%Y-%m-%d-%T", gmtime ($t));
}

#############################################################################

sub new_filename ($;$)
# computes a new filename for a given filename
# path/<file.ext> --> path/<prefix->YYYY-MM-DD-HH:MM:SS[-suffix].<ext>
# where YYYY-MM-DD-HH:MM:SS is the mtime of the file
#       if there is already a file with that name append a suffix: 1, 2,...
#       <ext> is replaced by its lowercase
# Argument:  filename
# Returns:   a new filename
{
    my $fn     = shift;
    my $prefix = shift;

    my ($base, $dir, $ext) = fileparse ($fn, qr/\.[^.]*/);

    my $new_base;
    if (defined $option_renumber) {
	$new_base = sprintf ("%s%0*d", $prefix, $option_digits, $option_renumber);
	$option_renumber++;
    } else {
	my $time;
	$time = $st_mtime;
	$time = $st_atime if ($option_atime);
	$time = $st_ctime if ($option_ctime);

	$new_base = $prefix . time2name ($time);
    }
    $dir = $option_dir if ($option_dir);

    my $new_fn = $fn;
    my $suffix = "";
    my $count  = 0;
    while (-f $new_fn) {
	$new_fn = catfile ($dir, $new_base . $suffix . lc ($ext));
	last if ($option_overwrite);
	$count ++;
	$suffix = "-" . $count;
    }
    return $new_fn;
}

#############################################################################
## start processing
#############################################################################

if ($#ARGV < 0) {
    printf STDERR "$CMD: no arguments given, try $CMD -h\n";
    exit;
}
for my $fn (@ARGV) {
    stat($fn) || die "$CMD: can not stat: $fn\n";

    my $new_fn = new_filename ($fn, $option_prefix);
    if ($option_verbose || $option_dry_run) {
	printf "%s %s --> %s\n", $action_text, $fn, $new_fn;
    }
    if (!$option_dry_run) {
	# perform action
	&$action ($fn, $new_fn);

	# preserve mtime and atime
	if ($option_copy) {
	    utime ($st_atime, $st_mtime, $new_fn);
	}
    }
}

#############################################################################
# Log: mv-date,v $
# Revision 1.5  2007/05/21 16:36:55  vollmer
# added optional number argument to -N
# added -D nr command line option
#
# Revision 1.4  2007/05/09 20:41:16  vollmer
# added -N
#
# Revision 1.3  2003/08/28 16:28:26  vollmer
# fixed check for no arguments
#
# Revision 1.1  2003/08/12 09:51:38  vollmer
# Initial revision
#
