#!/usr/bin/perl -w
# mkcalendar - $Id$
# Copyright 2008 Perette Barella
# All Rights Reserved.
######################################################################
use Time::Local;
use Getopt::Std;
sub time_to_minute {
my ($time) = @_;
my ($hour, $minute) = split /:/, $time;
return ($hour * 60) + $minute;
}
sub minute_to_time {
my ($minute) = @_;
my $hour = $minute / 60;
$minute %= 60;
if ($ampm_time) {
my $printhour = $hour % 12;
if ($printhour == 0) {
$printhour = 12;
}
return sprintf ("%d:%02d %sM", $printhour, $minute,
$hour >= 12 ? "P" : "A");
}
return sprintf ("%02d:%02d", $hour, $minute);
}
sub get_real_dayname {
my ($day) = @_;
$day = "${day}day";
($day eq "Tueday") && ($day="Tuesday");
($day eq "Wedday") && ($day="Wednesday");
($day eq "Thuday") && ($day="Thursday");
($day eq "Satday") && ($day="Saturday");
return $day;
}
sub generate_format_timelist {
for $day (split /,/, $weekdays) {
print STDOUT "
", get_real_dayname ($day), "\n\t";
my $dayevents = $dailyevents {$day};
if ($verbose) {
print STDERR $day, " keys: ", join (",", keys %$dayevents), "\n";
}
for $time (sort { $a <=> $b } keys %$dayevents) {
$event = $dayevents->{$time};
print STDOUT "\t",
minute_to_time ($event->{starttime}),
"-",
minute_to_time ($event->{endtime}),
": ",
$event->{description},
"\n";
}
print STDOUT "\t \n";
}
}
sub generate_format_eventlist {
my @activities = split /,/, $event_order;
my $multiple = ($#{activities} gt 0);
for $activity (split /,/, $event_order) {
if ($multiple) {
print STDOUT " $activity\n\t";
}
for $day (split /,/, $weekdays) {
my $dayevents = $dailyevents {$day};
if ($verbose) {
print STDERR $day, " keys: ", join (",", keys %$dayevents), "\n";
}
for $time (sort { $a <=> $b } keys %$dayevents) {
$event = $dayevents->{$time};
if (index ($event->{description}, $activity) >= 0) {
print STDOUT "\t",
get_real_dayname ($day),
" ",
minute_to_time ($event->{starttime}),
"-",
minute_to_time ($event->{endtime}),
" ",
$event->{description},
"\n";
}
}
}
if ($multiple) {
print STDOUT "\t \n";
}
}
}
sub generate_table_format {
$startminute = time_to_minute ($start);
$endminute = time_to_minute ($end);
# Add in "Empty" events representing when nothing is happening.
for $day (split /,/, $weekdays) {
# Make up a bogus "back" event to start with
$lasttime = $startminute;
$lastend = $startminute;
$lastevent = { };
$dailyevents {$day}{$endminute} = {
description => "End calendar - to cause a last loop iteration"
};
my $dayevents = $dailyevents {$day};
if ($verbose) {
print STDERR $day, " keys: ", join (",", keys %$dayevents), "\n";
}
for $time (sort { $a <=> $b } keys %$dayevents) {
if ($debug) {
print STDERR "Time=$time, lasttime=$lasttime, lastend=$lastend\n";
}
$event = $dayevents->{$time};
# The last event in display gets the shorter
# of its assigned time, or when this event starts.
if ($lastend >= $time) {
# Tell the last event to take up space to the
# start of this event
$lastevent->{rows} = ($time - $lasttime) / $interval;
} else {
# Adjust last end to an even interval
$lastend = int (($lastend + $interval * 0.5) / $interval) * $interval;
$lastevent->{rows} = int ($lastend - $lasttime) / $interval;
# Create a fake event to fill in the intervening time.
$dailyevents {$day}{$lastend} = {
description => "",
rows => ($time - $lastend) / $interval
};
}
$lastevent = $event;
$lasttime = $time;
$lastend = $event->{endtime};
}
}
# Add headers for the day of the week
print STDOUT "Time\n";
for $day (split /,/, $weekdays) {
$day = get_real_dayname ($day);
print STDOUT "\t $day\n";
}
print STDOUT " ";
# Output the results!
$time = $startminute;
while ($time < $endminute) {
if (($time - $startminute) % $timeinterval == 0) {
print STDOUT "",
minute_to_time ($time), "\n";
} else {
print STDOUT " \n";
}
for $day (split /,/, $weekdays) {
my $dayevents = $dailyevents {$day};
if (exists $dayevents->{$time}) {
$event = $dayevents->{$time};
print STDOUT "\t \n";
if (exists ($event->{starttime})) {
print STDOUT "\t\t",
minute_to_time ($event->{starttime}),
"-",
minute_to_time ($event->{endtime}),
" ",
$event->{description}, "\n";
}
}
}
$time += $interval;
print STDOUT " \n";
}
}
$TABLE = 1;
$TIMELIST = 2;
$EVENTLIST = 3;
$publish = "";
$debug = 0;
$start = "0:00";
$end = "24:00";
$interval = 30;
$timeinterval = 60;
$verbose = 0;
$ampm_time = 0;
$weekdays = "Sun,Mon,Tue,Wed,Thu,Fri,Sat";
$output_format = $TABLE;
$event_order = "";
#----------------------------------------------------------------------
# Read the command line options.
#----------------------------------------------------------------------
if (!getopts ("btl:ad:o:s:e:i:t:f:Zv")) {
usage ();
exit 1
}
if (defined ($opt_b)) {
$output_format = $TABLE;
}
if (defined ($opt_t)) {
$output_format = $TIMELIST;
}
if (defined ($opt_l)) {
$output_format = $EVENTLIST;
$event_order = $opt_l;
}
if (defined ($opt_a)) {
$ampm_time = 1;
}
if (defined ($opt_Z)) {
$debug = 1;
}
if (defined ($opt_v)) {
$verbose = 1;
}
if (defined ($opt_s)) {
$start = $opt_s;
}
if (defined ($opt_e)) {
$end = $opt_e;
}
if (defined ($opt_i)) {
$interval = $opt_i;
}
if (defined ($opt_t)) {
$timeinterval = $opt_t;
}
if (defined ($opt_d)) {
$weekdays = $opt_d;
}
if (defined ($opt_f)) {
$source = $opt_f;
} else {
die "Source file not specified.";
}
if (defined ($opt_o)) {
close (STDOUT);
$dest = $opt_o;
open STDOUT, "> $dest";
}
open (SOURCE, "< $source") || die "$source: Can't read";
print STDOUT "m4_dnl Automated calendar system mkcalendar\n" .
"m4_dnl Copyright 2008 Perette Barella.\n\n";
%dailyevents = (
Sun => {},
Mon => {},
Tue => {},
Wed => {},
Thu => {},
Fri => {},
Sat => {}
);
my $day;
# Read the events from the file
while () {
chomp;
if (m/^\s*\#/ || m/^\s*$/) { next };
my ($days, $times, @rest) = split /\s+/;
$description = join(' ', @rest);
my ($starttime, $endtime) = split /-/, $times;
my $startminute = time_to_minute ($starttime);
my $endminute = time_to_minute ($endtime);
if ($verbose) {
print STDERR "Days: $days\nTimes: $times ($startminute - $endminute)\nEvent: $description\n\n";
}
my $newevent = {
starttime => $startminute,
endtime => $endminute,
description => $description
};
for $day (split /,/, $days) {
# Don't allow multiple events on same day/time to clobber
# each-other.
$hash = $startminute * 100;
while (exists ($dailyevents {$day}{$hash})) {
$hash++;
}
$dailyevents {$day}{$hash} = $newevent;
}
}
if ($output_format == $TABLE) {
generate_table_format ();
} elsif ($output_format == $TIMELIST) {
generate_format_timelist ();
} elsif ($output_format == $EVENTLIST) {
generate_format_eventlist ();
}
close (DEST);
close (SOURCE);
exit (0);