The following program gives different results depending on whether
I save the source with Unix or Mac linebreaks.
I could well be the reason is a logic error of mine. I haven't checked
thoroughly.
BTW: I found the program very useful as a replacement for Unix "find".
Axel
---
#!/usr/local/bin/perl -w
### remove if modules are in their own files
{
package WalkTree;
use strict;
my $DIRSEP =
$^O =~ /Mac/ ? ':' :
$^O =~ /Win|OS-2|DOS/ ? '\\' : '/';
my $MACOS = ( $^O =~ /Mac/ ) || 0;
my $WINOS = ( $^O =~ /Win|OS-2|DOS/ ) || 0;
sub walktree {
my ( $dir, $filefunc, $dirfunc, $prune ) = @_;
$MACOS and $dir =~ s/:$//;
if ( -d $dir ) {
if( defined $prune ) { return undef if $dir =~ /$prune/o }
my @values;
local *DH;
opendir DH, $dir or warn "opendir '$dir' failed\n$!";
my $file;
while ( defined( $file = readdir DH )) {
!$MACOS and next if( $file eq '.' or $file eq '..' );
$MACOS and next if( $file eq "Icon\n" );
push @values, walktree( "$dir$DIRSEP$file", $filefunc,
$dirfunc, $prune );
}
closedir DH;
ref $dirfunc ? return $dirfunc->($dir, @values) : return @values;
} else {
ref $filefunc ? return $filefunc->($dir) : return;
}
}
1;
}
### remove if modules are in their own files
### remove if modules are in their own files
{
package File;
use strict;
# encapsulate
{
# value 0 makes an attribute non-writable
my %_attributes = (
name => 1,
);
my $_attributes = sub { keys %_attributes };
my $_cnt;
my $_incr_cnt = sub{ $_cnt++ };
sub get_cnt { $_cnt }
sub new {
my ($caller, %arg) = @_;
my $caller_is_obj = ref( $caller );
my $class = $caller_is_obj || $caller;
my $self = bless {}, $class;
foreach my $member ( $_attributes->() ) {
if( $arg{ $member } ) {
$self->{ $member } = $arg{ $member }
}
}
my @stat = stat( $self->get_name );
# hash slice assignement
@{$self}{
"dev", "inode", "mode", "nlink", "uid", "gid", "rdev",
"size", "atime", "mtime", "ctime", "blksize", "blocks" } =
@stat;
$_incr_cnt->();
return $self;
}
}
sub get_name { return $_[0]->{name} }
sub get_dev { return $_[0]->{dev} }
sub get_inode { return $_[0]->{inode} }
sub get_mode { return $_[0]->{mode} }
sub get_nlink { return $_[0]->{nlink} }
sub get_uid { return $_[0]->{uid} }
sub get_gid { return $_[0]->{gid} }
sub get_rdev { return $_[0]->{rdev} }
sub get_size { return $_[0]->{size} }
sub get_atime { return $_[0]->{atime} }
sub get_mtime { return $_[0]->{mtime} }
sub get_ctime { return $_[0]->{ctime} }
sub get_blksize { return $_[0]->{blksize} }
sub get_blocks { return $_[0]->{blocks} }
1;
}
### remove if modules are in their own files
###
package main;
use strict;
require 5.005;
use Getopt::Std;
### if packages go into external files
### use WalkTree;
### use File;
# search directory start
my $dir;
my $filter;
my $prune;
process_args();
my $filefunc = sub {
if( defined $filter ) { $_[0] =~ /$filter/o and File->new( name => $_[0] ) }
else { File->new( name => $_[0] ) }
};
my @files = grep { ref } WalkTree::walktree( $dir, $filefunc, undef, $prune );
unless( @files ) { exit 1 }
print File->get_cnt(), " files found\n";
print "list of found files with size info:\n", "-" x 40, "\n";
for my $file ( @files ) {
# still possible but we're into OO now
# print $file->{name}, "\n";
print $file->get_size, "\t", $file->get_name, "\n";
}
# just for demonstration (and because I always forget)
my @name_and_mtime = map{ { name => $_->get_name, mtime => $_->get_mtime } } @files;
my @mtime_sorted = sort { $a->{mtime} <=> $b->{mtime} } @name_and_mtime;
print "mtime sorted list of found files:\n", "-" x 40, "\n";
for ( @mtime_sorted ) {
print $_->{mtime}, "\t", $_->{name}, "\n";
}
print "=" x 40, "\n";
print "runtime: ", time - $^T, " seconds.\n";
print "done.\n";
### end of main ###
sub process_args {
my $MACOS = ( $^O =~ /Mac/ ) || 0;
unless( @ARGV ) {
if( $MACOS ) {
@ARGV = split / /, MacPerl::Ask( 'Please enter @ARGV (-h for
help)' );
$dir = ":";
$ARGV[0] and -d $ARGV[0] and $dir = $ARGV[0];
}
!$MACOS and $dir = '.';
}
usage() if ! $ARGV[0] or $ARGV[0] =~ /-h/;
my %opts;
getopts( 'f:p:h', \%opts );
if( $opts{f} ) {
eval { $filter = qr/$opts{f}/ }
or warn "regex '$opts{f}' cannot be compiled, continuing
without filter\n";
}
if( $opts{p} ) {
eval { $prune = qr/$opts{p}/ }
or warn "regex '$opts{p}' cannot be compiled, continuing
without pruning\n";
}
## print "DEBUG: dir = $dir, filter = $filter, prune = ", defined $prune ?
$prune : "undef", "\n";
}
sub usage {
print <<eom;
$0 -f <filter> -p <prune> -h <search directory start>
all arguments are optional
default filter is undef
default prune is undef
defaults search directory search directory is current working directory
eom
exit 1;
}
__END__
=head1 NAME
walktree-finder-oo.pl
=head1 SYNOPSIS
walktree-finder-oo.pl -f <filter> -p <prune> -h <search directory start>
all arguments are optional
default filter is undef
default prune is undef
defaults search directory search directory is current working directory
example:
walktree-finder-oo.pl -f '\.pl$' /usr/local/bin
searches for files ending with .pl in directory /usr/local/bin
for MacOS:
enter command line options in the displayed dialog as
-f \.pl$ 'Macintosh HD:Desktop Folder:myprojects:'
=head1 DESCRIPTION
Demonstration of OO techniques, replacement of File::Find for shortness and
flexibility.
WalkTree was taken from "The Idendity Function" slides provided by Mark-Jason Dominus
at
http://www.plover.com/~mjd/
=head1 BUGS/TODO
=head1 AUTHOR
=head1 VERSION
$Id$
=cut