#!/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\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\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);