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

Reply via email to