#!/usr/bin/perl
#
# zzzrename -- expand URL escapes (e.g., %20) in file names
# Copyright (C) 2004 Fabian "zzznowman" Pietsch
#
# 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
# (at your option) 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.
#
# Version 0.1 (2004-04-05)
#
# Exit codes:
#  0 success, at least one file renamed
#  1 failure, no file found
#  2          syntax error
#  3          unknown error
#
# Verbosity levels:
#  0 errors only
#  1 statistics just before exit
#  2 every rename is shown
#  3 every file checked for URL escapes is output (not recommended)
#
# Default verbosity: 0
#

use strict;
use File::Find;
use vars qw($base);

BEGIN {
	# get basename of what we've been called as
	($base = $0) =~ s#^.*/([^/]+)$#$1#;

	# change warn() and die() to give more convenient results
	$SIG{__WARN__} = sub {
		print(STDERR "$base: warning: @_");
	};
	$SIG{__DIE__} = sub {
		print(STDERR "$base: error: @_");
		print(STDERR "$base: aborting\n");
		exit 3;
	};
}

my ($verbose, $found, $errors, @dirs) = (0) x 3;

# output usage information
sub usage() {
	print(STDERR "zzzrename -- expand URL escapes (e.g., %20) in file names\n",
	             "usage: $0 [-vq] [DIR1 [DIR2 [...]]]\n",
	             "  -v  increase verbosity\n",
	             "  -q  decrease verbosity\n",
	             "\n",
	             "Please look at the source for license information and usage details.\n");
	exit 2;
}

# process command line options
foreach my $arg (@ARGV) {
	if ($arg =~ /^-(.+)$/) {
		foreach my $opt (split(//, $1)) {
			if ($opt eq 'v') {
				$verbose++;
			}
			elsif ($opt eq 'q') {
				$verbose--;
			}
			else {
				usage;
			}
		}
	}
	else {
		push(@dirs, $arg);
	}
}

# use current directory as default
@dirs = ('.') unless (scalar(@dirs));

# traverse filesystem to find files to rename
find(sub {
	# provide debug information if user wishes so
	print("$base: $File::Find::name\n")
	  if ($verbose >= 3);

	# does the file contain URL escapes (like %20)?
	if ((my $name_new = $_) =~ s/%([0-9]{2})/chr(hex($1))/ge) {
		# file contains URL escapes
		print("$base: renaming $File::Find::name to $name_new\n")
		  if ($verbose >= 2);
		$found++;

		# rename the file
		unless (rename $_, $name_new) {
			# couldn't rename it -- inform the user
			warn("can't rename $File::Find::name to $name_new: $!\n");
			$errors++;
		}
	}
}, @dirs);

# output statistics if user requested them
print("$base: found $found files, $errors errors occurred\n")
  if ($verbose >= 1);

# set correct exit code
exit 3 if ($errors);
exit 1 unless ($found);
exit 0;

