HTML-Calendar-Monthly
view release on metacpan or search on metacpan
script/hcgen view on Meta::CPAN
# Process command line options.
app_options();
# Post-processing.
$trace |= ($debug || $test);
unless ( $title_format =~ /^\</ ) {
$title_format = "<p class='hc_title'>$title_format</p>";
}
################ Presets ################
my $TMPDIR = $ENV{TMPDIR} || $ENV{TEMP} || '/usr/tmp';
################ The Process ################
use HTML::Calendar::Monthly;
my $filter_pat = qr/^([12]\d\d\d)([01]\d)([0123]\d)\.html$/;
my @files;
foreach ( @forced ) {
unless ( /^([12]\d\d\d)([01]\d)$/ ) {
warn("Illegal value in force: $_\n");
next;
}
push(@files, [ $1, $2, 00, undef ] );
}
my $dir = shift || ".";
opendir(my $dd, $dir) or die("$dir: $!\n");
while ( my $d = readdir($dd) ) {
next unless $d =~ $filter_pat;
push(@files, [ $1, $2, $3, $d ]);
pop(@files) if $filter && $d !~ /^$filter/;
}
unless ( @files ) {
warn("No files? Nothing to do.\n");
exit;
}
warn("$dir: ", scalar(@files), " files\n") if $verbose;
@files = sort { $a->[0] <=> $b->[0] or $a->[1] <=> $b->[1] } @files;
@files = reverse(@files) if $reverse;
my $this = "";
my $cal;
my $needhdr = defined($title) ? $title ? 1 : -99 : 0;
my $data = "";
foreach ( @files ) {
my ( $y, $m, $d, $file ) = @$_;
if ( sprintf("%04d%02d", $y, $m) ne $this ) {
if ( $cal ) {
$data .= "<div class='hc'>\n";
$data .= $cal->build_title($title_format) . "\n"
if $needhdr >= 0;
$needhdr++;
$data .= $cal->calendar_month;
$data .= "</div>\n";
}
$cal = HTML::Calendar::Monthly->new
({ 'month' => $m, year => $y });
$this = sprintf("%04d%02d", $y, $m);
}
$cal->add_link( $d, $linkpfx.$file );
}
if ( $cal ) {
$data .= "<div class='hc'>\n";
$data .= $cal->build_title . "\n" if $needhdr > 0;
$data .= $cal->calendar_month;
$data .= "</div>\n";
}
if ( $output ) {
if ( update_if_needed($output, $data) ) {
warn("$output: written\n");
}
else {
warn("$output: not modified\n");
}
}
else {
print $data;
}
exit 0;
################ Subroutines ################
sub HTML::Calendar::Monthly::build_title {
my ($self, $fmt) = @_;
my $t = $title_format;
$t =~ s/\%m/lc($self->month_name)/ge;
$t =~ s/\%M/$self->month_name/ge;
$t =~ s/\%y/$self->year/gie;
return $t;
}
sub update_if_needed($$) {
my ($fname, $new) = @_;
# Do not overwrite unless modified.
if ( -s $fname && -s _ == length($new) ) {
local($/);
my $hh = do { local *F; *F };
my $old;
open($hh, "<", $fname) && ($old = <$hh>) && close($hh);
if ( $old eq $new ) {
return 0;
}
}
open(my $fh, ">", $fname)
or die("$fname (create): $!\n");
print $fh $new;
close($fh);
1;
}
################ Subroutines ################
sub app_options {
my $help = 0; # handled locally
my $ident = 0; # handled locally
my $man = 0; # handled locally
my $pod2usage = sub {
# Load Pod::Usage only if needed.
require Pod::Usage;
Pod::Usage->import;
&pod2usage;
};
# Process options.
if ( @ARGV > 0 ) {
GetOptions('output=s' => \$output,
'prefix=s' => \$linkpfx,
'reverse' => \$reverse,
'title!' => \$title,
'format=s' => \$title_format,
'force=s' => \@forced,
'filter=s' => \$filter,
'ident' => \$ident,
'verbose' => \$verbose,
'trace' => \$trace,
'help|?' => \$help,
'man' => \$man,
'debug' => \$debug)
or $pod2usage->(2);
}
if ( $ident or $help or $man ) {
print STDERR ("This is $my_package [$my_name $my_version]\n");
}
if ( $man or $help ) {
$pod2usage->(1) if $help;
$pod2usage->(VERBOSE => 2) if $man;
}
}
__END__
################ Documentation ################
=head1 NAME
hcgen - generate simple HTML month calendar
=head1 SYNOPSIS
hcgen [options] [dir]
Options:
--output=XXX output file (see below)
--reverse output months in reverse order
--[no]title do [not] provide a title (see below)
--format=XXX title format
--prefix=XXX link prefix (see below)
--ident show identification
--help brief help message
--man full documentation
--verbose verbose information
=head1 OPTIONS
=over 8
=item B<--output=>I<XXX>
Write the generated calendars to this file. If the file exists, and
contains the same calendar, it will not be modified so it is useful as
a make target.
=item B<--reverse>
Generate the calendars in reverse order, e.g., newest month first.
=item B<--title> B<--notitle>
Request titles above the generated calendars. With B<--title>, titles
are always provided. With B<--notitle>, titles are never provided.
Default is to only provide titles when more than one calendar is
generated.
=item B<--format=>I<XXX>
The format for the titles. It may contain the following substitutions:
%m the name of the month, e.g., april
%M same, titlecased, e.g., April
%y %Y the year, e.g., 2009
If the format does I<not> start with a C<< < >> character, it will be output as a HTML C<< <p> >> element:
<p class='hc_title'>...</p>
Default format is C<< "%M %Y" >>.
=item B<--prefix=>I<XXX>
A prefix to add to the generated day links.
=item B<--force=>I<YYYYMM>
Force the generation of a calendar for this year/month, even if there
are no files.
=item B<--filter=>I<YYYYMM>
Process only files for the given year/month.
This option may occur multiple times.
=item B<--help>
Print a brief help message and exits.
=item B<--man>
Prints the manual page and exits.
=item B<--ident>
Prints program identification.
=item B<--verbose>
More verbose information.
=item I<dir>
The directory to process. This directory must contain files (HTML
documents) with names formatted as C<< YYYYMMDD.html >>.
Default is to process the current directory.
=back
=head1 DESCRIPTION
B<hcgen> will read the given directory and build a list of all files
that obey the name format C<< YYYYMMDD.html >>. This list will
determine the years and months for which calendars must be generated.
Each calendar consists of a table of 7 colums. The first row
contains short day names. The other cells contain the date numbers,
possibly with a link to a corresponding HTML document.
=head1 CSS CLASSES
The table can be completely formatted with CSS style sheets.
The CSS classes are shown in the following output excerpt.
<div class='hc'>
<p class='hc_title'>February 2009</p>
<table class='hc_month'>
<th>Sun</th>
....
<th>Sat</th>
<tr>
<td class='hc_empty'></td>
...
<td class='hc_empty'></td>
<td class='hc_date'>1</td>
</tr>
...
<tr>
<td class='hc_date_linked'><a href='20090202.html'>2</a></td>
...
</tr>
<tr>
...
<td class='hc_date_linked'><a href='20090228.html'>28</a></td>
<td class='hc_empty'></td>
</tr>
</table>
</div>
If more tables are generated, each one gets its own C<< <div> >>.
=head1 EXAMPLES
hcgen --output=htdocs/cal.html htdocs
hcgen --force 200902
Example style sheet:
p.hc_title {
font-weight: bold;
}
table.hc_month {
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 14pt;
border-collapse: collapse;
border: 1px solid black;
}
.hc_month th {
font-size: 14pt;
text-align: center;
border: 1px solid black;
padding-top: 5px;
padding-bottom: 5px;
}
.hc_month td {
font-size: 14pt;
border: 1px solid black;
text-align: center;
width: 3em;
padding-top: 5px;
padding-bottom: 5px;
}
.hc_month a {
text-decoration: none;
font-weight: bold;
}
.hc_empty {
background: #e0e0e0;
}
=head1 BUGS
The program and its associated module, L<HTML::Calendar::Monthly>
are currently hard-wired to generate dutch calendars.
=head1 SEE ALSO
L<HTML::Calendar::Monthly>
=head1 AUTHOR
Johan Vromans E<lt>jvromans@squirrel.nlE<gt>
=cut
( run in 0.467 second using v1.01-cache-2.11-cpan-39bf76dae61 )