#! perl.exe use CGI qw/:standard/; use strict; my $columns = param('cols') || 4; my $offset = 0; opendir(DIR, ".") || die "cannot opendir: $!"; foreach (sort readdir(DIR)) { next if /^\.\.?$/ || /~$/; my $d = -d "$_"; splice(@_, $d?$offset++:@_, 0, b($d?"[ ":"",a({-href=>"$_"},$_),$d?" ]":"","\n")); } closedir DIR; print header(-expires=>'now'), start_html('Directory Listing'), h1('Directory Listing'), table({-border=>0,-cellpadding=>5,-cellspacing=>5}, map { Tr($_) } map { td( [ splice(@_,0,$columns) ] ) } 0 .. (@_ / $columns) ), end_html; __END__ # Here's an explanation of how the splice works: # # Tell @_ to pretend to be two arrays, @dirs and @files # and simulate a push command for both arrays. # In the splice documentation # # it shows sample code to simulate push: # # splice(@a,@a,0,$x,$y) # # Since we want to put the @dirs at the front and the # @files at the back, we first tried: # # unshift @_, $dirname # put the dirname first # push @_, $filename; # put the filename last # # that fails because now our directories are in reverse # order. In order to keep the ordering of the dir names, # there has to be a way to push to the middle of the # list. The solution here is to keep an offset into # the middle of the list where the new $dirname should # be inserted and increment the offset every time one # is added. For the case of a filename we revert to # the example above for a simulated push, or make the # offset point to the end of the list. # splice(@_, # this is our list $d?$offset++:@_, # if we have a dir, return # the current offset and # increment, otherwise # return length of list 0, # number of elements to replace # an html-ized version of the dir/file name # putting "[" and "]" around dirnames b($d?"[ ":"",a({-href=>"$_"},$_),$d?" ]":"","\n") );