Description: |
This subroutine indexes files that contain a date in their name, and displays them as a neat HTML calendar. It uses Time::Local to determine the day of week for the first day of each month, but doesn't know how many days a month has, and will happily index a file whose name indicates it's from the 32nd day of a given month. The number of months is hardwired, but it is flexible about years.
The months are displayed two in a row (easily changeable) and if there are no files for a given month, it's no problem. This calendar will make sure it gives a sane display. If there are no files for only some days in a month, it's not a problem either. If the missing days are between 1 and an existing file, they'll be marked as N/A, otherwise, not at all.
This calendar is designed to only find one file for a particular day.
Call it with the path to the directory to be indexed as a parameter. You might need to tweak the code for some hardwired things, but they're marked.
More information is included in comments in the code, but they're hard to miss.
Update: I changed the HTML in the two lines that start the tables for the years and the months, so it will display correctly in Netscape 4.7x, which it did not before. |
#!/usr/bin/perl -wT
use strict;
# Demonstration code. Please edit the path.
my $self = $ENV{SCRIPT_NAME} || "ENV ERROR"; # Used in link destina
+tion, but you can easily change that.
print "Content-type: text/html\n\n<html><head><title>Old Maps Index</t
+itle></head><body>";
# Edit this path!
&calendar("/path/to/files") or print "Could not read the directory.";
print "</body></html>";
######################################################################
+#######################################
#
# calendar(path)
#
# Runs under strict, taint mode, and generates no warnings.
#
#
#
# Print a really cool calendar of available files with dates in their
+names.
# Suggested usage: index (log)files generated by some program that gen
+erates files.
# See it in action at http://odin.prohosting.com/dakkalot/archive.pl
#
# Recognises files according to two regexps, which you will need to ch
+ange to suit your situation, and provides
# links behind the dates in the calendar, with customizable destinatio
+ns.
# Doesn't require a four-digit year, will ignore months outside of (1.
+.12), but doesn't know how many days each
# month has, so it'll gladly swallow and display the 32nd day of a mon
+th.
# That is no problem, of course, unless your software actually generat
+es files with such dates, then it might
# look odd, but it won't screw up anything. Another effect of not know
+ing how many days each month has, is that
# it won't display much for months that have only the first few files.
+ Again, it won't screw up the calendar.
#
# Requires: Time::Local (standard module) to determine day-of-week of
+the first day of each relevant month.
# Parameter: path to the maze directory.
# Returns: true (and HTML output on STDOUT) on success, false on failu
+re (cannot read directory).
# Example call:
# &calendar("/path/to/files") or print "Could not read directory.";
#
# How to customise:
# I've marked the points you will need to customize with capital lette
+rs in the comments, so they're easy to
# find. Points A and B need similar changes, since the regexps must lo
+ok like eachother.
# Point C isn't that important, but it gets rid of leading zeroes, whi
+ch might be undesirable.
# Point D determines the contents of the links for each day, and point
+ E indicates you're ready to run it.
######################################################################
+#######################################
sub calendar {
require Time::Local; # To determine day-of-week
my $dir = shift; # The path to the directory to be
+indexed
my @months = qw(January February March April May June July August
+September October November December);
my @dow = qw(Sun Mon Tue Wed Thu Fri Sat); # Short names look b
+etter
my $monthsperline = 2; # Number of months to displa
+y on a line
my %CALENDAR;
my ($year, $month, $day);
#####
# A #
#####
# The regexp in the grep block is designed to filter the directory con
+tents to only relevant files.
# This regexp finds files that look like "2001-5-30.mz", but of course
+ you can change it to suit
# Your situation. There is a similar regexp at point B, which captures
+ these numbers.
opendir DIR, $dir or return 0;
my @files = grep { /^\d+-\d\d?-\d\d?\.mz$/ } readdir DIR;
closedir DIR or return 0;
foreach (@files) {
#####
# B #
#####
# This is the second regexp that must look like the first one.
# year - month - day
($year, $month, $day) = $_ =~ /^(\d+)-(\d\d?)-(\d\d?)\.mz$/;
#####
# C #
#####
# Convert to numbers, eliminating leading zeroes. This might b
+e a problem if your files do use them,
# So comment it out if necessary.
$year += 0; $month += 0; $day += 0;
#####
# D #
#####
# What is put in this HoHoA (or something ;-) is what the cale
+ndar cells will link to. Modify at will.
$CALENDAR{$year}->{$month}->[$day] = "$self?map=$year-$month-$
+day";
}
#####
# E #
#####
# After this, there is nothing that you need to adjust for your situat
+ion, but you can do so to change the calendar's appearance.
# If you've successfully changed points A and B, you should be ready t
+o go, but for actual functionality, you'll need to modify
# point D and possibly point C.
# Start the actual calendar
foreach $year (sort keys %CALENDAR) {
my $thisyear = \%{$CALENDAR{$year}};
my $lastmonth = 0;
print "<table border=1 cols=$monthsperline width=100%><tr><th
+colspan=$monthsperline align=center bgcolor=#aaaaaa>$year</th></tr><t
+r>";
foreach $month (1..12) { # foreach $month (sort { $
+a <=> $b } keys %$thisyear) {
if(exists $thisyear->{$month}) {
print "<td>";
print "<table border=1 cols=7 width=100%><tr><th colsp
+an=7 align=center bgcolor=#cccccc>$months[$month-1]</th></tr><tr><th>
+";
print join "</th><th>", @dow;
print "</th></tr><tr>";
my $thismonth = \@{$CALENDAR{$year}->{$month}};
my $thisdow = (localtime Time::Local::timelocal(0,0,0,
+1,$month-1,$year))[6]; # dow for 1st day of month
my $currentdow = 0;
if($currentdow ne $thisdow) { # Don't d
+o this if the month start on a Sunday!
foreach (1..$thisdow) { print "<td></td>"; $curren
+tdow++; }
}
foreach $day (1..$#$thismonth) {
my $contents = $CALENDAR{$year}->{$month}->[$day];
print "<td>";
if($contents) {
print "<a href='$contents'>$day</a>";
} else {
# You can change this if you don't like the gr
+ay "N/A" in cells that exist but have no file
print "<font color=gray>N/A";
}
print "</td>";
$currentdow++;
if($currentdow == 7) {
$currentdow = 0;
print "</tr><tr>";
}
}
print "</tr></table>\n";
print "</td>";
} else {
print "<td></td>";
}
print "</tr><tr>" if $month % $monthsperline == 0;
}
print "</tr></table>\n"
}
return 1;
}
|