use strict;
use warnings;

use File::Spec;
use Getopt::Long;

our (%Opts,
     $Dir,
     @Dirs,
     @Files,
);

get_args();
traverse(\@Dirs, \@Files);
output();

sub get_args {  
    $Dir = shift @ARGV;
    
    $Getopt::Long::autoabbrev = 0;
    $Getopt::Long::ignorecase = 0; 
    GetOptions (\%Opts, 'type=s');
    
    $Opts{'type'} ||= '';
    unless (-d $Dir && $Opts{'type'} =~ /^d|f$/) {
        die <<"";
usage: $0 <dir> [-type f|d]

    }
}

sub traverse {
    my ($dirs_ref, $files_ref) = @_;

    my ($count, @dirs, $eval, @eval, @files,
        $limit, @stack);
    $count = 0;

    dir_read($Dir, \@eval);
    @eval =
      map { File::Spec->catfile($Dir, $_) }
      @eval;

    RECURSE:
    while (@eval) {
        if (-d $eval[0]) {
            $eval = shift @eval;
            push @dirs, $eval;
        }
        elsif (-f $eval[0]) {
            my $file = shift @eval;
            push @files, $file;
            next;
        }
        else { die "Traversing failed: unknown type\n" }

        my @items;
        dir_read($eval, \@items);

        foreach (@items) {
            my $item = File::Spec->catfile($eval, $_);
            if (-d $item) { push @stack, $item }
            else { push @files, $item }
        }

        unless (@eval) {
            #if ($limit && ++$count == $limit) { last RECURSE }
            @eval = @stack;
            undef @stack;
        }
    }

    @$dirs_ref  = sort @dirs;
    @$files_ref = sort @files;
}

sub output {
    local $, = "\n";
    
    if ($Opts{'type'} =~ /d/) { print @Dirs }
    if ($Opts{'type'} =~ /f/) { print @Files }
}   

#
# dir_read (\$dir, \@files)
#
# Reads files of a directory.
#

sub dir_read {
    my ($dir, $files_ref) = @_;

    opendir D, $dir
      or die qq~Could not open dir $dir for read-access: $!\n~;
    @$files_ref = readdir D; splice @$files_ref, 0, 2;
    closedir D or die qq~Could not close dir $dir: $!\n~;
}
