#!/usr/bin/perl
##
## h3. Annotation credits
##
## This is version 0.9 of the Blosxom 2 annotations, by Frank Hecker
## <<a href="mailto:hecker@hecker.org">hecker@hecker.org</a>>. These
## annotations to the <code>blosxom.cgi</code> source code are made available
## under the same license terms as Blosxom itself. Comments and suggestions
## for changes are welcome.
##
## The "online Perl documentation":http://www.perldoc.com/ was indispensable
## in creating these notes. The <code>notes2html</code> script was used to
## create HTML documents from the inline notes.
##
## For more information see the following URLs:
##
##   http://www.blosxom.com/downloads/blosxom.zip
##   http://www.blosxom.com/license.html
##   http://www.hecker.org/blosxom/
###
### h3. For people learning Perl: Comments and #!
###
### All lines starting with '#' are comments, not part of the code itself.
### The first line uses the standard Unix #! convention to identify
### the location of the Perl interpreter. You would need to change this
### line if for some reason the Perl interpreter were in a different directory
### or had a different name.
###
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlrun.html

## h3. Overview of the Blosxom 2 source code
##
## The Blosxom source file is divided into three major sections:
##
## * initial code (lines 1-8) and the configurable variable section (lines
## 12-65) containing variables that need to be modified in order to set up a
## new weblog (as described in the
## "Blosxom user documentation":http://www.blosxom.com/documentation/users/configure/).
## * the main Blosxom code (lines 69-424)
## * the data section defining the default html and rss flavours (lines
## 429-443)
##
## The main Blosxom code itself is further divided into various sections as
## discussed below.
##
## h4. Blosxom initialization (lines 69-214)
##
## In this section the following tasks are carried out:
##
## # declare various global variables (line 69)
## # import needed Perl modules (lines 71-76)
## # set the Blosxom version number (line 78)
## # define additional variables needed (lines 80-83):
## ** <code>$fh</code>: a FileHandle for reading files (line 80)
## ** <code>%month2num</code>: hash to convert a month abbreviation to a
## month number (line 82)
## ** <code>@num2month</code>: array to convert a month number to a month
## abbreviation (line 83)
## # tweak the values of selected configuration variables (lines 86-94):
## ** <code>$url</code>: if a value for the base URL wasn't defined in the
## configurable variables section, set a new value as described below (lines
## 86-88)
## ** <code>$datadir</code>: strip any trailing slash if present (line 91)
## ** <code>$depth</code>: adjust to account for the number of path components
## in <code>$datadir</code> (line 94)
## # extract information about the current requested page (lines 86-88,
## 97-125):
## ** <code>$url</code>: the part of the requested URL corresponding to the
## Blosxom script itself (e.g.,
## <code>http://www.example.com/cgi-bin/blosxom.cgi</code>) (lines 86-88)
## ** <code>$static_or_dynamic</code>: set to 'static' if Blosxom is running
## in static mode, 'dynamic' if Blosxom isrunning in dynamic mode, i.e.,
## through CGI (line 99)
## ** <code>$path_info</code>: the part of the requested URL identifying a
## particular category or individual entry to be displayed, e.g.,
## <code>/society/literature</code> or
## <code>/cooking/italian/bruschetta.html</code> (lines 97, 104-107, 121)
## ** <code>$flavour</code>: the particular flavour of data being requested,
## e.g., 'html' or 'rss' (lines 110-118)
## ** <code>$path_info_yr</code>, <code>$path_info_mo</code>, and
## <code>$path_info_da</code>: the dates for which we are requesting that
## entries be displayed (lines 124-125)
## # template initialization (lines 128-145, 161)
## ## define a default template routine and store a reference to it in
## <code>$template</code> (lines 128-137)
## ## read the default templates from the data section and store them in the
## <code>%template</code> hash keyed by the content type (e.g., 'html' or
## 'rss') and template component (e.g., 'head' or 'foot') (lines 139-145)
## ## override the default template subroutine with the template subroutine
## provided by the first plugin that defines one, if any do (line 161)
## # plugin initialization (lines 148-155)
## ## find all plugins in the plugin directory (lines 148-149)
## ## sort the plugins, taking into account prefixes like '00', '01', etc.
## (line 149)
## ## determine whether a given plugin is enabled or disabled (lines 150-151)
## ## import the plugin packages (line 152)
## ## populate the <code>@plugins</code> array (a list of plugin names, minus
## prefixes) and the <code>%plugins</code> hash (which stores the
## enabled/disabled status for each plugin, keyed by the plugin name)
## (line 153)
## # define a default subroutine to find entries in the data directory
## (storing a reference to the subroutine in <code>$entries</code>) (lines
## 169-214) and then allow overriding it by the first plugin that defines an
## alternate entries subroutine (line 219)
##
## h4. Finding (and filtering) Blosxom entries (lines 221-226)
##
## This section of the code looks for Blosxom entries and related items
## of interest, performing the following tasks:
##
## # search for entries using the subroutine referenced by
## <code>$entries</code>, and build up three hashes (lines 221-222):
## ** <code>%files</code>: files representing individual Blosxom entries
## (e.g., <code>foo.txt</code> if '.txt' is the standard Blosxom file
## extension)
## ** <code>%indexes</code>: directories for which index files might need
## to be created or updated as part of static page generation, as well as
## individual entry files for which static pages might need to be generated
## ** <code>%others</code>: all other files not falling into the above two
## categories
## # filter the list of files in <code>%files</code> and <code>%others</code>
## by invoking the <code>filter</code> subroutine for each and every plugin
## that defines one (line 225)
##
## The hashes <code>%files</code> and <code>%others</code> are keyed by the
## name of the entry file (for <code>%files</code>) or other item (for
## <code>%others</code>), in the form of an absolute pathname; the value for
## each element in <code>%files</code> or <code>%others</code> is the
## date/time last modified for the corresponding entry file or other item.
##
## The hash <code>%indexes</code>  is keyed by the name of the directory or
## entry file for which static page generation should be done, expressed as a
## relative pathname relative to the Blosxom data directory (e.g., 'a/b' or
## '2004/05/22'); the value for elements in <code>%indexes</code> is 1 for
## elements corresponding to category directories or individual entries, and
## for elements corresponding to date directories is the same as the key
## (e.g., '2004/05/22').
##
## h4. Generating output (lines 228-270)
##
## The next section of the Blosxom code generates HTML or other output.
## For dynamic invocation of Blosxom this is relatively simple, since we need
## to generate only one page in response to the requested URL (lines 260-267):
##
## # determine the content type for the requested flavour and create the
## appropriate HTTP header (lines 261-264)
## # call the <code>generate</code> subroutine to create the page output,
## based on the category, date, entry, and flavour information from the
## requested URL (line 266)
## # print the output returned by <code>generate</code> (which includes the
## HTTP header for the appropriate content type) (line 266)
##
## For static invocation of Blosxom page generation is more complex, since
## we may need to generate several pages (lines 230-257):
##
## # loop through each element of <code>%indexes</code> (lines 234-256) and
## then for each element loop through each directory component of the item
## (directory or entry file) corresponding to the element (lines 236-255)
## ## create new directories wherever needed in order to hold index pages
## (line 241)
## ## for each of the required flavours specified by
## <code>@static_flavours</code> (lines 242-254)
## ### create (or rewrite) the required index page
## or static entry page (lines 245-247)
## ### call the <code>generate</code> subroutine to create the output for the
## page (lines 250-252)
## ### write the output to the static file and then close the file (lines
## 249-253)
##
## Finally, we loop through the plugins and call each plugin's end subroutine
## in order to do any final processing (line 270).
##
## h4. The <code>generate</code> subroutine (lines 273-412)
##
## The <code>generate</code> subroutine creates the actual output for a
## page of the desired flavour, taking as input the path information for
## the category, entry file, and/or date, along with the flavour and content
## type, and an indication of whether static or dynamic page generation is
## desired. The <code>generate</code> subroutine also uses the hashes
## <code>%files</code>, <code>%indexes</code>, and <code>%others</code>
## previously populated.
##
## The specific tasks performed by the <code>generate</code> subroutine are as
## follows:
##
## # define a default <code>interpolate</code> subroutine for variable
## interpolation in templates (lines 283-290)
## # call each plugin's skip subroutine and decide if page generation should
## be skipped, otherwise proceeding as described below (lines 280, 292)
## # allow one of the plugins to override the default <code>interpolate</code>
## subroutine (line 297)
## # generate output for the 'head' section (lines 300-307):
## ## determine the proper 'head' template to use, based on the default
## template subroutine or one provided by a plugin (line 300)
## ## allow the plugins to modify the 'head' template (line 303)
## ## interpolate the values of variables (e.g., <code>$blog_title</code>) in
## the 'head' template and add the result to the output (lines 305-307)
## # tweak the <code>$currentdir</code> argument, which holds information on
## the category and/or individual entry for which a page needs to be generated
## (lines 313-319)
## # if a page for an individual entry is to be generated, tweak the
## <code>%f</code> hash (a copy of <code>%files</code>) so that it contains
## information for just that entry (line 315)
## # define a default subroutine for sorting entries (by file modification
## times) and then allow a plugin to override it (lines 322-330)
## # loop through the (sorted) elements of the hashes <code>%f</code> and
## <code>%others</code>, each representing an entry to be added to the
## generated page (lines 332-392)
## ## for category index pages and the main index page, stop looking at
## entries once we've reached the maximum entries per page configured using
## <code>$num_entries</code> (line 333)
## ## skip entries that are in categories other than the one for which a
## page is being generated (line 338)
## ## skip entries whose dates don't match the date(s) for which a page is
## being generated (line 344-354)
## ## do date processing (lines 357-364):
## ### get the appropriate template for the 'date' section (line 357)
## ### allow plugins to modify the template (line 360)
## ### interpolate variables into the template, including the actual date
## values (line 362)
## ### generate output for the date if needed, e.g., at the beginning of a set
## of entries for the same date (line 364)
## ## read the entry file to obtain the entry title (the first line of the
## file) and body (the rest of the file), and generate output for the entry
## (lines 366-389):
## ### get the appropriate template for the 'story' section (line 373)
## ### allow plugins to modify the story template (line 376)
## ### for RSS and similar types of XML-based content, replace problematic
## characters in the story template with the corresponding character entities
## (lines 378-384)
## ### interpolate variables into the story template (line 386)
## ### generate output for the story (line 388) and prepare to process the
## next entry file, if any (lines 389-391)
## # generate output for the 'foot' section (lines 395-401)
## ## determine the proper 'foot' template to use, based on the default
## template subroutine or one provided by a plugin (line 395)
## ## allow the plugins to modify the 'foot' template (line 398)
## ## interpolate the values of variables in the 'foot' template and add the
## result to the output (lines 400-401)
## # call the last subroutines for each and every plugin that defines one, to
## do any final processing for the page (line 404)
## # prepend the HTTP header if needed, and return the generated output
## (lines 409-411)
##
## h4. The <code>nice_date</code> subroutine (lines 415-424)
##
## The <code>nice_date</code> subroutine converts OS-provided time values
## (expressed as the number of seconds since some fixed date) into year,
## month, day, etc., values that we can use for printing date/times and
## creating date-based URLs. For more information see the notes for lines
## 415-424.
##
# Blosxom
# Author: Rael Dornfest <rael@oreilly.com>
# Version: 2.0
# Home/Docs/Licensing: http://www.raelity.org/apps/blosxom/

## h3. For people learning Perl: Packages
##
## <code>package</code> defines a namespace for variables, subroutines, etc.,
## so that their names won't conflict with names defined in other Perl code
## used by Blosxom and pulled in from other places.
##
## See the following URL for more information:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlmod.html#Packages
##
package blosxom;

## h3. For people learning Perl: Package "global" variables
##
## The scope of the configurable variables is within the blosxom package.
## We put "global" in quotes because, as the Perl documentation notes,
## "there's really no such thing as a global variable in Perl", in the sense
## of global variables as used in C and similar languages. However the
## configurable variables are like global variables in that their values are
## visible anywhere in the Blosxom code (unless "hidden" by other variable
## declarations as described in the notes to line 171). See also the notes
## to line 69.
##
## The configurable variables can be referenced from Blosxom plugins as
## <code>$blosxom::foo</code> where <code>$foo</code> is a variable.
## Alternatively, a Blosxom plugin can include a <code>package blosxom</code>
## statement prior to a section of code to allow Blosxom configurable variables
## to be referenced within that code section without having to preface the
## variables' names with "blosxom::". (For example, a plugin would do this
## when defining its own version of the <code>interpolate</code> subroutine;
## see the notes to lines 283 and 285 for more information.)
##
## See the following URL for more information on variable scope:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlmod.html
##
## Note when reading the documentation that the configurable variables are
## considered to be "dynamic" (as opposed to "lexical") variables.
##
# --- Configurable variables -----

# What's this blog's title?
##
## h3. For people learning Perl: Scalar variables
##
## In Perl a variable starting with '$' is a scalar (i.e., single-valued)
## variable. Note that unlike shell syntax the '$' is used when assigning
## to the variable as well as when using its value.
##
## The <code>$blog_title</code> variable is used to hold a string. Like shell
## variables Perl scalar variables can have either string or numeric values.
## String values can be delimited by either single quotes or double quotes;
## like the Unix shell, if the string is within double quotes then it can
## include references to other Perl variables (e.g., <code>"A Blog by
## $author"</code>) and the values of those variables will be interpolated
## into the string, replacing the variable references.
##
## Because of this variable interpolation, if you want to use a '$' in your
## blog title or description then you need to either precede the '$' with a
## '\' (<code>"My \$64,000 Blog"</code>) or use single quotes
## to delimit the string (<code>'My $64,000 Blog'</code>). (If you use single
## quotes for your string delimiter then you will also need to escape any
## single quote character in the string itself by preceding it with a '\',
## e.g., <code>'John\'s $64,000 Blog'</code>; a similar rule holds when you
## want to include a double quote in a string delimited by double quotes.)
##
## For more information on Perl scalar variables see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perldata.html#Scalar-values
##
$blog_title = "My Weblog";

# What's this blog's description (for outgoing RSS feed)?
$blog_description = "Yet another Blosxom weblog.";

# What's this blog's primary language (for outgoing RSS feed)?
$blog_language = "en";

# Where are this blog's entries kept?
$datadir = "/Library/WebServer/Documents/blosxom";

# What's my preferred base URL for this blog (leave blank for automatic)?
$url = "";

# Should I stick only to the datadir for items or travel down the
# directory hierarchy looking for items?  If so, to what depth?
# 0 = infinite depth (aka grab everything), 1 = datadir only, n = n levels down
$depth = 0;

# How many entries should I show on the home page?
$num_entries = 40;

# What file extension signifies a blosxom entry?
$file_extension = "txt";

# What is the default flavour?
$default_flavour = "html";

# Should I show entries from the future (i.e. dated after now)?
$show_future_entries = 0;

# --- Plugins (Optional) -----

# Where are my plugins kept?
$plugin_dir = "";

# Where should my modules keep their state information?
$plugin_state_dir = "$plugin_dir/state";

# --- Static Rendering -----

# Where are this blog's static files to be created?
$static_dir = "/Library/WebServer/Documents/blog";

# What's my administrative password (you must set this for static rendering)?
$static_password = "";

# What flavours should I generate statically?
##
## h3. For people learning Perl: Array variables and <code>qw</code>
##
## In Perl a variable starting with '@' is an array variable that holds
## an ordered list of values indexed by array position (starting from 0
## as the first position).
##
## Here we define a 2-element array with the string values 'html' and 'rss'.
## <code>qw</code> is a function that returns a list of words extracted out
## of a string enclosed within delimiters, e.g., <code>qw/a b/</code> is the
## same as <code>'a', 'b'</code>. (Alternately you could use
## <code>qw(a b)</code> or <code>qw! a b !</code> or whatever.) This is a
## very common Perl idiom, as it eliminates the need to quote each and every
## word within the list.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/perldata.html
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Regexp-Quote-Like-Operators
##
@static_flavours = qw/html rss/;

# Should I statically generate individual entries?
# 0 = no, 1 = yes
$static_entries = 0;

# --------------------------------

## h3. For people learning Perl: <code>use vars</code>
##
## Here we declare global variables used in this package (actually,
## within the file, but the file just contains a single package).
## Note that <code>use vars</code> was deemed obsolete as of Perl 5.6, being
## replaced by <code>our</code>, but as used here supports use of Blosxom with
## earlier Perl 5.x versions.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlmodlib.html#Pragmatic-Modules
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/vars.pm
##
use vars qw! $version $blog_title $blog_description $blog_language $datadir $url %template $template $depth $num_entries $file_extension $default_flavour $static_or_dynamic $plugin_dir $plugin_state_dir @plugins %plugins $static_dir $static_password @static_flavours $static_entries $path_info $path_info_yr $path_info_mo $path_info_da $path_info_mo_num $flavour $static_or_dynamic %month2num @num2month $interpolate $entries $output $header $show_future_entries %files %indexes %others !;

## h3. For people learning Perl: <code>use strict</code>
##
## <code>use strict</code> tells Perl to produce compiler warnings for all
## sorts of things, such as references to variables that were not previously
## defined or declared.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/strict.pm
##
use strict;
##
## h3. For people learning Perl: Importing modules with
## the <code>use</code> function
##
## The next few lines import various Perl modules, making their functions and
## global variables available without needing to qualify the names with package
## names. (In other words, we can refer to <code>bar()</code> rather than
## <code>foo::bar()</code> where <code>bar</code> is a function in the
## package <code>foo</code>.)
##
## On packages vs. modules: per the documentation, "A module is just a set of
## related functions in a library file, i.e., a Perl package with the same
## name as the file." Strictly speaking Blosxom 2.0 is a package but not a
## module; however Blosxom 3.0 will be a full-fledged module.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/use.html
###
### h3. FileHandle
###
### The FileHandle module contains functions for basic file I/O operations:
### <code>open</code>, <code>new</code>, <code>getc</code>, <code>gets</code>,
### <code>seek</code>, <code>close</code>, etc.
###
### For more information see the following URL:
###
###   http://search.cpan.org/~nwclark/perl-5.8.4/lib/FileHandle.pm
###
use FileHandle;
##
## h3. File::Find
##
## The File::Find module contains functions to traverse a directory tree in
## the file system, analogous to the Unix <code>find</code> command. Blosxom
## uses File::Find functions and variables in its own find subroutine below.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/File/Find.pm
##
use File::Find;
##
## h3. File::stat
##
## The File::stat module gets a file's attributes, like the Unix
## <code>stat</code> kernel routine.
## Blosxom uses File::stat functions and variables to get the date/time
## modified for entry files and related information.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/File/stat.pm
##
use File::stat;
##
## h3. Time::localtime
##
## The Time::localtime module gets the current date and time and performs
## other date/time-related operations, like the corresponding Unix functions.
## Blosxom uses Time::localtime functions in the subroutine
## <code>nice_date</code> and elsewhere.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/Time/localtime.pm
##
use Time::localtime;
##
## h3. CGI
##
## The CGI module is used to parse incoming HTTP requests (e.g., to get
## the URL being requested) and to create HTTP headers and HTML pages sent
## in response (see the subroutine <code>generate</code> for an example).
##
## Note that <code>:standard</code> imports a standard set of functions and
## <code>:netscape</code> imports optional functions for Netscape-specific
## HTML extensions.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm
##
use CGI qw/:standard :netscape/;

## h3. The Blosxom version
##
## Blosxom 2.0 is considered stable. Blosxom 3.0 is currently in development.
##
$version = "2.0";

## h3. For people learning Perl: <code>my</code> variables
##
## <code>my</code> creates a private variable visible only within the lexical
## scope within which it is defined (e.g., within a given code block enclosed
## by curly braces), and not visible anywhere else (including subroutines
## called from a given code block). In this case the lexical scope is
## considered to be the entire <code>blosxom</code> package within the
## <code>blosxom.cgi</code> source file.
##
## For more information see
##
##   http://www.perldoc.com/perl5.8.4/pod/perlintro.html#Variable-scoping
##   http://www.perldoc.com/perl5.8.4/pod/perlsub.html#Private-Variables-via-my()
###
### h3. For people learning Perl: Creating objects with <code>new</code>
###
### The FileHandle module presents an object-oriented interface, so
### <code>new</code> in this context produces a new instance of the
### FileHandle class.
###
### In object-oriented terms <code>new</code> is a "constructor", i.e.,
### a so-called "class method" that creates and initializes new objects.
### Unlike object-oriented languages like C++, in Perl a constructor could
### be called something other than "new", but it's a common convention.
###
### For more information see
###
###   http://search.cpan.org/~nwclark/perl-5.8.4/lib/FileHandle.pm
###   http://www.perldoc.com/perl5.8.4/pod/perlobj.html
###
my $fh = new FileHandle;

## h3. For people learning Perl: Hashes
##
## We create a hash table (or plain "hash" in Perl jargon) with month names
## being the keys and month numbers (as strings) being the values. Hashes
## are initialized by providing a list in which the odd entries are the key
## values and the even entries are the corresponding values, e.g.,
## <code>('key1', 'value1', 'key2', 'value2')</code>. The syntax
## <code>(a=>'b', c=>'d')</code> is
## equivalent to <code>('a','b','c','d')</code> and is intended to make hash
## initialization more understandable.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perldata.html
##
%month2num = (nil=>'00', Jan=>'01', Feb=>'02', Mar=>'03', Apr=>'04', May=>'05', Jun=>'06', Jul=>'07', Aug=>'08', Sep=>'09', Oct=>'10', Nov=>'11', Dec=>'12');
##
## h3. For people learning Perl: The <code>keys</code> and <code>sort</code>
## functions
##
## This takes the list of keys in the previously-defined hash table, i.e.,
## the list <code>('nil', 'Jan', 'Feb', ..., 'Dec')</code>, sorts it using a
## comparison function that compares the corresponding values in the hash
## table for each key, i.e., the values '00', '01', etc., and then assigns the
## resulting sorted list of keys to an array indexed by month number.
##
## This is equivalent to defining the array as follows:
##
##   @num2month = ('nil', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
##                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
##
## (Note that the 'nil' value is included because Perl arrays are indexed
## from 0 but month numbers start at 1.)
##
## <code>keys</code> is a function that takes as an argument a hash and
## returns either a list consisting of all the keys in the hash (if used in
## list context) or the number of keys in the hash (if used in scalar
## context). Here we're using <code>keys</code> in list context, because as
## noted below the <code>sort</code> function expects a list as an argument.
##
## <code>sort</code> is a function that takes as arguments the list of items
## to be sorted and (as an optional first argument) a subroutine defining how
## sort comparisons are to be done; in this case that subroutine is an
## "anonymous" inline routine enclosed in curly braces. <code>$a</code> and
## <code>$b</code> are special global variables used to hold the values being
## sorted at each step of the sort algorithm; <code><=></code> is a comparison
## operator that returns -1, 0, or 1 depending on whether the first item is
## respectively less than, equal to, or greater than the second. (This is a
## numeric comparison.)
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/keys.html
##   http://www.perldoc.com/perl5.8.4/pod/func/sort.html
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Equality-Operators
##
@num2month = sort { $month2num{$a} <=> $month2num{$b} } keys %month2num;

# Use the stated preferred URL or figure it out automatically
##
## h3. For people learning Perl: The <code>||=</code> operator
##
## This defines <code>$url</code> to be its existing value (if it has one) or
## (if it has no value) the value returned by the <code>url</code>
## function (part of the CGI module) as described in the next note.
## (Perl has different namespaces for variables and functions, which
## is why we can name the variable the same as the function.)
##
## The <code>||</code> operator is a logical "or" operator similar (but not
## identical) to that used in shell or C programming;
## <code>$url ||= url();</code> is equivalent to
## <code>$url = $url || url();</code> where the original value of
## <code>$url</code> is considered false if it is undefined or its value
## is the empty string '', and true otherwise. So if <code>$url</code>
## already has a value then the second part of the conditional expression
## (after <code>||</code>) is not executed, and that existing value is
## (re)assigned to <code>$url</code>; otherwise the second part is executed
## to obtain the returned value from <code>url()</code>, and that value is
## assigned to <code>$url</code>.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#C-style-Logical-Or
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Assignment-Operators
###
### h3. The value of <code>url()</code>
###
### Note that <code>url()</code> returns only the URL of the Blosxom CGI
### script itself, not the full URL being requested. Thus (for example) if
### the HTTP request were for the URL
###
###   http://www.example.com/cgi-bin/blosxom.cgi/2004/05/22
###
### then <code>url()</code> would return (and <code>$url</code> would be set
### to) the URL
###
###   http://www.example.com/cgi-bin/blosxom.cgi
###
### If you have configured the web server to hide the <code>blosxom.cgi</code>
### part of the URL (as described in the FAQ referenced below) then the value
### of <code>url()</code> will be that part of the full URL which was
### translated into the script location. For example, if you configured Apache
### using the <code>ScriptAlias</code> directive as follows:
###
###   ScriptAlias /blog "/var/www/cgi-bin/blosxom.cgi"
###
### then if the requested URL were
###
###   http://www.example.com/blog/2004/05/22
###
### then <code>url()</code> would return (and <code>$url</code> would be set
### to) the URL
###
###   http://www.example.com/blog
###
### For more information see the following URLs:
###
###   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm#OBTAINING_THE_SCRIPT'S_URL
###   http://www.blosxom.com/faq/cgi/hide_cgi_bit.htm
###
$url ||= url();
##
## h3. Server Side Includes and Blosxom
##
## We assign <code>$url</code> a new value consisting of its previous value
## with the initial string "included:" (if present) replaced with "http:".
## This is intended for the case when output from <code>bloxsom.cgi</code> is
## included in an HTML file by a Server Side Include directive like the
## following:
##
##    <!--#include virtual="/cgi-bin/blosxom.cgi/2004/05/19" -->
##
## When invoked in this way the URL returned by <code>url()</code> above
## would be (for example)
##
##   included://www.example.com/cgi-bin/blosxom.cgi
##
## instead of
##
##   http://www.example.com/cgi-bin/blosxom.cgi
##
## For more information see the following URL:
##
##   http://httpd.apache.org/docs-2.0/howto/ssi.html
##
### h3. For people learning Perl: The <code>=~</code> operator and regular
### expression matching
###
### <code>=~</code> is a special operator that takes the left side
### (<code>$url</code>) and applies to it a pattern match specified on the
### right side (<code>s/^included:/http:/</code>),
### in this case a pattern match that actually does substitution, using
### regular expressions modeled on those used in the Unix shell and utilities.
### (So, for example, in this case the '^' tells Perl to look for a match
### starting at the beginning of the string.) The result is that the value
### of <code>$url</code> is modified if the match succeeds.
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Binding-Operators
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Regexp-Quote-Like-Operators
###
$url =~ s/^included:/http:/; # Fix for Server Side Includes (SSI)
##
## h3. For people learning Perl: More on regular expressions and substitution
##
## This statement strips off a trailing slash from the URL value if present;
## the '$' in the regular expression tells Perl to look for a match at
## the end of the string.
##
## Note that the value returned by the <code>url()</code> function doesn't
## have a trailing slash, but the person configuring Blosxom may have
## included a trailing slash when specifying a non-default value for the
## <code>$url</code> variable.
##
$url =~ s!/$!!;

# Drop ending any / from dir settings
$datadir =~ s!/$!!; $plugin_dir =~ s!/$!!; $static_dir =~ s!/$!!;
  
# Fix depth to take into account datadir's path
##
## h3. Adjusting <code>$depth</code>
##
## If <code>$depth</code> is non-zero (i.e., limiting search to <i>n</i>
## directories deep) then we take the <code>$datadir</code> path, count the
## number of path components, subtract 1, and add that to <code>$depth</code>
## to get the new value. For example, if the value of <code>$data_dir</code>
## is <code>/a/b/c</code> then a <code>$depth</code> value of 2 would get
## changed to a value of 4.
##
## The new value of <code>$depth</code> can be interpreted as follows: Search
## through a directory only if the number of components in its path is
## <code>$depth</code> or less. So in the previous example the directory
## <code>/a/b/c/d</code> would be searched but the directory
## <code>/a/b/c/d/e</code> would not.
##
### h3. For people learning Perl: The <code>tr</code> and <code>and</code>
### operators
###
### Counting the number of path components is done using the <code>tr</code>
### operator, which is typically used to modify a string by transliterating
### one set of characters with another, e.g., <code>$s =~ tr[a-z][A-Z]</code>
### to change lowercase characters in <code>$s</code> to uppercase. However in
### this case the set of replacement characters is empty (<code>[]</code>) so
### no replacement is done; instead we simply use the standard return value
### from <code>tr</code>, namely the number of times the character(s) in the
### search list (i.e., the '/' character in this case) was found.
###
### Since the value of <code>$datadir</code> is an absolute path (i.e., it
### starts with '/') and we trimmed any trailing '/' characters (see above)
### the number of '/' characters will be equal to the number of components
### in the path.
###
### <em>[Note: There is a minor potential bug here: If the value of
### <code>$datadir</code> were specified with multiple trailing slashes, e.g.,
### <code>/a/b/c//</code>, then the code above would remove only a single
### trailing '/', leaving one extra '/' at the end, and the number of
### directory components would be miscounted as being higher than it actually
### is. The fix is simple: Replace the existing statement
### <code>$datadir =~ s!/$!!;</code> with the statement
### <code>$datadir =~ s!/*$!!;</code> to look for zero or more '/' characters
### at the end of the string and remove any found; even safer would be
### <code>$datadir =~ s!/*\s*$!!;</code> to remove trailing whitespace as
### well.]</em>
###
### The <code>and</code> operator here is used to conditionally change
### <code>$depth</code> only if it is non-zero; if <code>$depth</code> is
### zero then it is interpreted as false and the expression after the
### <code>and</code> is not executed. However any non-zero value will be
### interpreted as true and <code>$depth</code> modified as described above.
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Quote-and-Quote-like-Operators
###   http://www.perldoc.com/perl5.8.4/pod/perlreref.html
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Logical-And
###
$depth and $depth += ($datadir =~ tr[/][]) - 1;

# Global variable to be used in head/foot.{flavour} templates
$path_info = '';

## h3. Static vs. dynamic mode
##
## We set the variable <code>$static_or_dynamic</code> to 'static' or
## 'dynamic' to reflect the mode we're in. We're in static mode if all the
## following are true:
##
## * the GATEWAY_INTERFACE environment variable is not set (i.e., we
## are not executing as a CGI routine) 
##
## * the parameter <code>-password</code> has a value
##
## * the variable <code>$static_password</code> is defined (see above)
##
## * the value of the <code>-password</code> parameter is the same as the
## value of <code>$static_password</code>
##
## Otherwise we're in dynamic mode.
##
### h3. For people learning Perl: The <code>eq</code> operator and
### <code>CGI::param()</code> function
###
### We saw the <code>and</code> operator above. The <code>eq</code> operator
### tests for string equality. The expression <code>$a ? $b : $c</code> is like
### that used in C: if <code>$a</code> is true then return <code>$b</code>,
### otherwise return <code>$c</code>.
###
### <code>param()</code> is a CGI function, but it can also return values when
### the Perl script is invoked from the command line, e.g.
###
###   perl blosxom.cgi -password='secret'
###
### would assign the string value 'secret' to the parameter
### <code>-password</code>.
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Equality-Operators
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Conditional-Operator
###   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm#DEBUGGING
###   http://www.blosxom.com/documentation/users/configure/static.html
###
$static_or_dynamic = (!$ENV{GATEWAY_INTERFACE} and param('-password') and $static_password and param('-password') eq $static_password) ? 'static' : 'dynamic';
##
## h3. For people learning Perl: Setting parameters using the
## <code>CGI::param()</code> function
##
## If we're in dynamic mode then we set the value of the <code>-quiet</code>
## parameter to be 1. When setting parameters the <code>param()</code>
## function takes an argument list similar in syntax to the way hashes are
## initialized, e.g., <code>param(-name=>'a', -value=>'b')</code> would set
## the parameter <code>a</code> to the value <code>b</code>.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm#SETTING_THE_VALUE(S)_OF_A_NAMED_PARAMETER:
##
$static_or_dynamic eq 'dynamic' and param(-name=>'-quiet', -value=>1);

# Path Info Magic
# Take a gander at HTTP's PATH_INFO for optional blog name, archive yr/mo/day
##
## h3. <code>PATH_INFO</code>
##
## <code>PATH_INFO</code> (the CGI environment variable whose value is
## returned by the <code>path_info</code> function) contains any path
## information in the URL after the part of the URL that identifies the CGI
## script. For example, if the requested URL were
## <code>http://www.example.com/cgi-bin/blosxom.cgi/2004/05</code>
## then the value returned by <code>path_info()</code> would be
## <code>/2004/05</code>.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm#FETCHING_ENVIRONMENT_VARIABLES
##
### h3. For people learning Perl: The <code>split</code> function
###
### We use <code>my</code> to define a private array variable
### <code>@path_info</code>. To set this variable we first use the
### <code>split</code> function on the string returned by the
### <code>path_info()</code> function (if it's non-empty), splitting that
### value into different components separated by the '/' character.
### (<code>m{/}</code> is a regular expression that will match a single '/'.)
### The <code>split</code> function returns a list of strings, which is why
### we use an array to hold the result.
###
### If for some reason <code>path_info()</code> returns an empty string then
### we split the value of the <code>path</code> CGI parameter instead. This
### would allow you to use a URL like
###
###   http://www.example.com/cgi-bin/blosxom.cgi?path=/2004/05/22
###
### if you wished to do so. Note that the <code>||</code> operator has a
### higher precedence than the comma operator, so the decision whether to
### use the value of <code>path_info()</code> or <code>param('path')</code>
### is made before that value is passed to the <code>split</code> function.
### 
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/func/split.html
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Operator-Precedence-and-Associativity
###
my @path_info = split m{/}, path_info() || param('path'); 
###
### h3. For people learning Perl: The <code>shift</code> function
###
### The <code>shift</code> function discards the first element of an array.
### We do this because <code>path_info()</code> returns a path with an initial
### '/', and the <code>split</code> function as used above on that path will
### produce an empty string as the first element of the returned array; for
### example, the expression <code>split m{/}, "/a/b/c"</code> will return the
### list <code>('', 'a', 'b', 'c')</code>. We don't want the initial empty
### string so we use <code>shift</code> to get the list
### <code>('a', 'b', 'c')</code> instead.
###
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/func/shift.html
###
shift @path_info;

## h3. Interpreting Blosxom URLs
##
## Recall that after the part of the URL that references the Blosxom script
## itself (stored in <code>$url</code>), a Blosxom URL can contain an
## additional path consisting of three
## possible parts: an optional set of categories, an optional set of year,
## month, and day values, and an optional reference to an individual entry. For
## example, the following are values that might be returned by the
## <code>path_info()</code> function as applied to Blosxom URLs:
##
##   /society/literature
##   /2004/05/19
##   /music/index.rss
##   /personal/resolutions/2003/07
##   /cooking/italian/bruschetta.html
##
## From the path returned by <code>path_info()</code> we end up setting the
## following variables:
##
## * <code>$path_info</code>: either an individual entry path including
## categories, subcategories, and entry name (e.g.,
## <code>/cooking/italian/bruschetta.html</code>) or a category/subcategory
## path for which we wish to see all entries (e.g.,
## <code>/society/literature</code> or <code>/music</code>)
## * <code>$flavour</code>: the desired flavour, whether explicitly specified
## in the URL (e.g., 'html' for <code>/cooking/italian/bruschetta.html</code>
## or 'rss' for <code>/music/index.rss</code>) or defaulted (e.g., as in
## <code>/society/literature/</code>)
## * <code>$path_info_yr</code>, <code>$path_info_mo_num</code>, and
## <code>$path_info_da</code>: the year, month, and day if present in the URL
## (e.g., for <code>/personal/resolutions/2003/07</code> the year and month
## would be '2003' and '07' respectively while the day would be undefined)
##
## Our first task is to extract the path information relating to categories;
## since we know that category names can't begin with a digit we can simply
## look for path components starting with alphabetic characters. However
## we have to stop before we get to any reference to an individual entry;
## we identify such entries by the presence of a '.' character in their
## names.
##
## <em>[Note: This implies two additional restrictions in Blosxom as
## currently designed: you can't have a category name containing a '.',
## and you can't reference individual entries using URLs that don't have
## a file extension at the end (as recommended by the W3C, among others.]</em>
##
## For more information see the following URLs:
##
##   http://www.blosxom.com/documentation/users/view.html
##   http://www.w3.org/Provider/Style/URI
##
### h3. For people learning Perl: The <code>while</code> loop
###
### A <code>while</code> loop executes a block of code (in curly braces) as
### long as a given condition (in parentheses) is true. In this case before
### executing the code block we first check to see if the first element of
### <code>@path_info</code> is defined and non-empty; otherwise there are no
### more components and we're done. (<code>$a[i]</code> is the i'th
### element of the array <code>@a</code>; note that it's distinct from the
### scalar variable <code>$a</code>.)
###
### If we have a further component, we then check to see if its value starts
### with an alphabetic character, by trying to match it against the regular
### expression character class <code>[a-zA-Z]</code> starting at the beginning
### of the string ('^'); otherwise the component represents a date and not a
### category, and we're done.
###
### Finally we check to verify that the component's value does not have a
### literal period (<code>\.</code>) in it; otherwise the component represents
### an individual entry (e.g., "a.html") and we're done. (The operator
### <code>!~</code> is the reverse of <code>=~</code>, returning a true value
### when the pattern match fails.)
###
### See the notes for line 112 below for the meaning of the parentheses
### in the regular expression <code>/(.*)\.(.*)/</code> used to check for a
### period in in the path component. For now we simply note that as used here
### the regular expression could have been replaced with the simpler regular
### expression <code>/.*\..*/</code> without affecting things.
###
### If the first element of <code>@path_info</code> looks like a category then
### we append it to the scalar variable <code>$path_info</code>, preceded by a
### '/', and remove the element from the <code>@path_info array</code>.
### (<code>$path_info</code> was defined above, with its initial value set to
### the empty string.) Note that <code>shift @path_info</code> both does the
### removal and returns the removed element as a result. The <code>.</code>
### operator concatenates two strings, in this case '/' and the removed
### first element. The <code>.=</code> assignment operator is like the
### <code>||=</code> and <code>+=</code> operators seen above, so that
### <code>$a .= 'b'</code> is the same as <code>$a = $a . 'b'</code>, where
### the <code>.</code> operator concatenates two strings.
### 
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlsyn.html#Compound-Statements
###   http://www.perldoc.com/perl5.8.4/pod/perlreref.html#CHARACTER-CLASSES
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Additive-Operators
###
while ($path_info[0] and $path_info[0] =~ /^[a-zA-Z].*$/ and $path_info[0] !~ /(.*)\.(.*)/) { $path_info .= '/' . shift @path_info; }

# Flavour specified by ?flav={flav} or index.{flav}
$flavour = '';

## h3. Determining the flavour, part 1
##
## If the flavour is specified by <code>index.{flav}</code>, as in
##
##   http://www.example.com/cgi-bin/blosxom.cgi/music/index.rss
##
## then it must be parsed from the <code>PATH_INFO</code> value stored in
## <code>@path_info</code>. However if the flavour is specified by
## <code>?flav={flav}</code>, as in
##
##   http://www.example.com/cgi-bin/blosxom.cgi/music?flav=rss
##   
## then its value must be obtained using <code>param()</code>, since anything
## in the URL after a '?' is considered a CGI parameter and not part of
## <code>PATH_INFO</code>.
## 
### h3. For people learning Perl: <code>$#path_info</code>
###
### <code>$#path_info</code> returns the index of the last element of the array
### <code>@path_info</code>. We match the value of that last element against a
### regular expression consisting of one or more characters followed by a
### literal '.' character followed by one or more characters to the end of the
### string. This match will succeed when the last element looks like, e.g.,
### 'a.b', where we'll interpret 'b' as the flavour.
###
### (Note that this regular expression is slightly different from the one
### used in the <code>while</code> loop on line 107; the previous expression
### matched zero or more characters followed by a '.' followed by zero or more
### characters. In other words, the test at line 107 will match <code>.</code>
### by itself, <code>.a</code>, <code>a.</code>, and so on, while the test
### here will not. In practice this doesn't matter: the first test was simply
### intended to reject path components that weren't categories, which can't
### contain '.'; the second test is intended to find flavour values, and for
### that purpose we need a component that actually has something after the
### '.', as well as before.)
###
### The regular expression uses parentheses to save parts of the component
### that are matched, for later use. In particular, the regular expression
### <code>/(.+)\.(.+)/</code> is used (instead of the simpler
### <code>/.+\..+/)</code> to save the flavour value (matched by the
### expression in the second set of parentheses) and the entry name (matched
### by the expression in the first set of parentheses). The saved values can
### then be referenced by the special variables <code>$1</code> (first part
### matched, the entry name) and <code>$2</code> (second part matched, the
### flavour).
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perldata.html#Variable-names
###   http://www.perldoc.com/perl5.8.4/pod/perlreref.html#SYNTAX
###
if ( $path_info[$#path_info] =~ /(.+)\.(.+)$/ ) {
##
## h3. For people learning Perl: "Greedy" matching
##
## If the last value in <code>@path_info</code> does contain a '.' character
## then as noted above the value of the variable <code>$2</code> will be the
## string to the right of the '.', and we save that value in
## <code>$flavour</code>.
##
## Because of the way regular expression matching works, if the final
## component actually has two or more periods, e.g., "example.com-news.html",
## <code>$2</code> will be set to the string after the final '.', not the
## string after the first one. This "greedy" matching (i.e., match as many
## characters as you can) is exactly what we want to happen.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlreref.html#QUANTIFIERS
##
  $flavour = $2;
##
## h3. Indexes vs. individual entries
##
## If the first part (before the '.') of the last path component is not
## equal to 'index' then that component points to an individual entry,
## and we save both the entry name and flavour by appending them to the
## <code>$path_info</code> variable that stores the category components of
## the path.
##
## On the other hand, if the first part is 'index' then the original URL
## was not a request for an individual entry but rather a request for
## all entries in a particular category or for a particular day, month,
## or year, displayed using a specified flavour. For such requests the path
## might be something like <code>/a/b/index.rss</code> or
## <code>/2004/05/index.rss</code>.
## In this case we don't need to save the value 'index.rss' (or whatever)
## as part of <code>$path_info</code>, since all we need is the flavour value. 
##
  $1 ne 'index' and $path_info .= "/$1.$2";
##
## h3. For people learning Perl: The <code>pop</code> function
##
## Now that we've extracted the needed information from the last element
## of <code>@path_info</code> we use the <code>pop</code> function to remove
## it.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/pop.html
##
  pop @path_info;
} else {
##
## h3. Determining the flavour, part 2
##
## If the final component of the path does not contain a period then either
## the flavour was specified using the <code>flav</code> parameter, as in the
## URL
##
##   http://www.example.com/cgi-bin/blosxom.cgi/a/b?flav=rss
##
## or the flavour was omitted entirely. In the latter case we set
## <code>$flavour</code> to the default flavor defined in the configurable
## variables section.
##
  $flavour = param('flav') || $default_flavour;
}

# Strip spurious slashes
##
## h3. For people learning Perl: Alternative patterns in regular expressions
##
## Using <code>|</code> in a regular expression lets you search for (and in
## this case replace) two or more alternative patterns, in this case zero or
## more '/' characters at the beginning of <code>$path_info</code> and zero
## or more at the end. The 'g' option replaces all patterns found, so we
## replace both '/' characters found at the beginning and any found at the
## end.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlretut.html#Matching-this-or-that
##
$path_info =~ s!(^/*)|(/*$)!!g;

# Date fiddling
##
## h3. Date references
##
## At this point we've extracted from <code>@path_info</code> any category
## names (at the beginning of the path) and any final path component
## associated with either an individual entry or an <code>index.{flav}</code>
## reference. So the only components left in <code>@path_info</code> should be
## date references (if any) from URLs containing sequences like
## <code>/2004/05/19</code>, <code>/2004/05</code>, or <code>/2004</code>.
##
### h3. For people learning Perl: Assigning into a list
###
### This statement assigns <code>$path_info[0]</code> (i.e., the
### first element in the array <code>@path_info</code>) to
### <code>$path_info_yr</code>, <code>$path_info[1]</code> to
### <code>$path_info_mo</code>, and <code>$path_info[2]</code> to
### <code>$path_info_da</code>. If <code>@path_info</code> doesn't have
### three elements then some or all of the three variables may end up
### undefined (starting with <code>$path_info_da</code>).
###
### In general you can assign a list of scalar values into a list of scalar
### variables:
###
###   ($a, $b, $c) = (1, 2, 3);
###   ($a, $b, $c) = @d;
###
### where the righthand side could be a constructed list (using ','), an
### array, a function returning a list, or any other expression returning
### a list.
###
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perldata.html#List-value-constructors
###
($path_info_yr,$path_info_mo,$path_info_da) = @path_info;
##
## h3. Month abbreviations in Blosxom URLs
##
## <em>[Note: Although I don't believe the online documentation mentions this,
## based on this code it appears that you can use Blosxom URLs that identify
## months by their three-letter abbreviations instead of month numbers; so,
## for example, rather than identifying the date as <code>/2004/01/31</code>
## it appears that you could request it as <code>/2004/Jan/31</code>.</em>
##
## <em>If so, there's no danger in mistaking a month abbreviation for a
## category name since the month must be preceded by a four-digit year,
## and Blosxom stops parsing the URL for categories as soon as it hits
## a component starting with a digit.]</em>
##
### h3. For people learning Perl: The <code>lc</code>, <code>ucfirst</code>,
### and <code>undef</code> functions
###
### This statement can be paraphrased as follows: if
### <code>$path_info_mo</code> has a (non-empty) value, then check to see if
### that value is a string with (at least) two digits (i.e., it matches the
### regular expression <code>\d{2}</code>); if so, assign the value
### of <code>$path_info_mo</code> to <code>$path_info_num</code>. If
### <code>$path_info_mo</code> has a value that doesn't contain
### two digits, then put the value in "initial cap" form and look it up in
### the <code>%month2num</code> hash to see if the value is a month
### abbreviation; if so, assign the month number from the hash to
### <code>$path_info_num</code>.
###
### If the value of <code>$path_info_mo</code> doesn't look like a month
### number or month abbreviation, or if it's empty or undefined, then
### <code>$path_info_mo_num</code> is undefined as well.
###
### The function <code>lc</code> returns the lower-case equivalent of its
### string argument, and the <code>ucfirst</code> function returns a copy of
### its argument with the first letter (only) capitalized. Hence
### <code>ucfirst(lc 'jaN')</code> returns the value 'Jan', which is
### the capitalization style used in <code>%month2num</code>.
###
### The function <code>undef</code> returns an undefined value that (as in this
### case) can be assigned to a variable.
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlreref.html#CHARACTER-CLASSES
###   http://www.perldoc.com/perl5.8.4/pod/perlreref.html#QUANTIFIERS
###   http://www.perldoc.com/perl5.8.4/pod/func/lc.html
###   http://www.perldoc.com/perl5.8.4/pod/func/ucfirst.html
###   http://www.perldoc.com/perl5.8.4/pod/func/undef.html
###
$path_info_mo_num = $path_info_mo ? ( $path_info_mo =~ /\d{2}/ ? $path_info_mo : ($month2num{ucfirst(lc $path_info_mo)} || undef) ) : undef;

# Define standard template subroutine, plugin-overridable at Plugins: Template
##
## h3. The template subroutine
##
## The template subroutine is used to look for and return the contents of
## flavour template files (e.g., <code>head.html</code>,
## <code>foot.html</code>, etc.). It can be overridden by a plugin that defines
## its own template subroutine; see the notes for line 161.
###
### h3. For people learning Perl: Anonymous subroutines and references
###
### <code>sub { ... }</code> defines an "anonymous" (i.e., not named)
### subroutine, a reference to which is then assigned to the variable
### <code>$template</code>. (References are basically names that can be used
### to refer to variables and subroutines, and are the third type of value
### that a scalar variable can have, along with numbers and strings.) The
### subroutine can then be called using the syntax <code>&$template()</code>
### where you can put subroutine arguments inside the parentheses.
###
### The template subroutine is defined in this way (using a reference stored
### in a variable rather than a named subroutine) so that the
### subroutine can be overridden; a plugin can define its own template
### subroutine, and a reference to that can be assigned to
### <code>$template</code>, replacing the reference to the original
### subroutine defined here.
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlsub.html
###   http://www.perldoc.com/perl5.8.4/pod/perlref.html
###
$template = 
  sub {
## h3. Template subroutine arguments
##
## <code>$flavour</code> is the flavour for which we are looking, e.g., 'html',
## 'rss', etc. <code>$chunk</code> is the type of template we are looking for,
## e.g., 'head', 'foot', 'story', etc. <code>$path</code> is the directory
## at which we should start our search, expressed as a relative pathname
## relative to the Blosxom data directory.
##
###
### h3. For people learning Perl: Argument passing using <code>@_</code>
###
### Arguments to the subroutine are passed in a special array variable
### <code> @_</code>, with the first three elements of that assigned to the
### private variables <code>$path</code>, <code>$chunk</code>, and
### <code>$flavour</code> respectively.
###
    my ($path, $chunk, $flavour) = @_;

## h3. For people learning Perl: The <code>do while</code> loop
##
## A <code>do while</code> loop is like a
## <code>while</code> loop except that the condition is checked at the
## bottom (after the loop is executed at least once) instead of at the top.
##
## (The similarity between <code>while</code> and <code>do while</code> loops
## is only superficial, since in Perl the <code>do {...} while</code> construct
## isn't considered to be a true loop. In particular, you can't put
## <code>next</code> and <code>last</code> statements within a <code>do {...}
## while</code>; see the notes for lines 141 and 240.)
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/do.html
##
    do {
##
## h3. For people learning Perl: The <code>join</code> and <code>open</code>
## functions
##
## The following statement is basically a backwards if statement: First
## we use the FileHandle <code>$fh</code> (created above) and try to open
## a template file for read access ("<"), constructing a template pathname
## from the values of <code>$datadir</code>, <code>$path</code>,
## <code>$chunk</code>, and <code>$flavour</code>. So, for example, if
## <code>$datadir</code> is '/blosxom', <code>$path</code> is '/a/b',
## <code>$chunk</code> is 'head', and $flavour is 'html', we look for a
## flavour template file '/blosxom/a/b/head.html'.
##
## (Because the FileHandle module provides an object-oriented interface,
## we use the method invocation <code>$fh->open(...)</code> rather than
## the function call <code>open($fh, ...)</code>. Also note that if we have
## already opened a file using the FileHandle <code>$fh</code> that file
## will be closed first before we open a new one.)
##
## If the open succeeds (i.e., the template file exists and is readable) then
## we read in all the lines of the template file using the <code>$fh</code>
## FileHandle and return a string containing all those lines concatenated
## together.
##
## (<code>&lt;$fh&gt;</code> would normally read only one line of the file,
## but using the <code>join</code> function causes <code>&lt;$fh&gt;</code>
## to be used in a list context -- because <code>join</code> expects a list
## as its second argument -- and that causes <code>&lt;$fh&gt;</code> to read
## all lines and return them as an array, with each array element being
## a newline-terminated line. The <code>join</code> function then returns a
## string consisting of all the array elements concatenated together
## separated by the <code>join</code> function's first argument, which in
## this case happens to be the empty string. So the returned result is a
## single string containing all the lines in the flavour template file, each
## terminated by a newline, e.g.,
##
##   <html>\n<body>\n<h1>A Blog</h1>\n...
##
## for a typical head section.)
##
## For more information see the following URLs:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/FileHandle.pm
##   http://www.perldoc.com/perl5.8.4/pod/perlopentut.html
##   http://www.perldoc.com/perl5.8.4/pod/func/open.html
##   http://www.perldoc.com/perl5.8.4/pod/func/join.html
##   http://www.perldoc.com/perl5.8.4/pod/func/return.html
##
      return join '', <$fh> if $fh->open("< $datadir/$path/$chunk.$flavour");
##
## h3. For people learning Perl: Retrying the template file search
##
## If the open fails (e.g., there was no file at the location we looked)
## then we modify the value of <code>$path</code> by stripping off the last
## path component (e.g., if <code>$path</code> has the value <code>/a/b</code>
## we change it to <code>/a</code>) and then we go back to the top of the
## loop and try the open again. (In other words, we search for the template
## file in the parent directory of the directory we just looked in.)
##
## (To explain the regular expression a bit: '\/' matches a literal '/'
## and '[^\/]' matches anything but a slash, so '\/*[^\/]*' matches zero
## or more '/' characters followed by zero or more other characters. The
## regular expression <code>\/*[^\/]*$</code> means look for this pattern
## at the end of the string, so that when the substitution is done -- replacing
## the matched pattern by an empty string -- it removes the last component of
## <code>$path</code>. Finally, we use parentheses to save the matched
## pattern in the <code>$1</code> variable for later checking, hence
## <code>(\/*[^\/]*)$</code> is the final regular expression used.)
##
## If we never succeed in opening a template file then the loop ends when
## all the path components have been removed, the matched pattern is an
## empty string so that <code>$1</code> is empty and hence false, and the
## <code>and</code> test fails.
##
    } while ($path =~ s/(\/*[^\/]*)$// and $1);

## h3. For people learning Perl: Values in nested hashes
##
## If we never succeed in opening a template file (i.e., we drop out of the
## <code>do while</code> loop) then we return a string consisting of lines
## from a flavour template already stored in a multidimensional hash, using
## <code>$flavour</code> and <code>$chunk</code> as keys. (This hash is
## defined below; recall that right now we are defining the subroutine, not
## executing it. See the notes for line 144 for more information.)
##
    return join '', ($template{$flavour}{$chunk} || $template{error}{$chunk} || '');
  };
# Bring in the templates
###
### h3. For people learning Perl: Initializing a hash to be empty
###
### We set the <code>%template</code> hash variable to contain nothing,
### i.e., no keys and no values.
###
%template = ();
##
## h3. Default templates
##
## Read in and store the default templates defined in the data section of
## this file, saving them in <code>%template</code>.
##
### h3. For people learning Perl: <code>&lt;DATA&gt;</code>
###
### <code>&lt;DATA&gt;</code> causes lines to be read from the data section
### of this file (i.e., <code>blosxom.cgi</code>). The data section starts
### after a line consisting of <code>__DATA__</code> by itself. In this
### context <code>&lt;DATA&gt;</code> returns a line at a time, returning an
### undefined value (and thus ending the <code>while</code> loop) when we
### reach the end of the file.
###
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perldata.html
###
while (<DATA>) {
##
## h3. For people learning Perl: <code>__END__</code> and <code>last</code>
##
## Using <code>&lt;DATA&gt;</code> would continue to read lines after
## <code>__DATA__</code> until the end of the <code>blosxom.cgi</code> file.
## However in our case we may want to put some additional text after the
## <code>__END__</code> line (which marks the end of what the Perl compiler
## parses). We therefore explicitly check for the presence of
## <code>__END__</code> on a line by itself, and if we find it we use the
## <code>last</code> command to exit the <code>while</code> loop immediately.
##
## Note that since we are not using the <code>=~</code> operator the string
## pattern match is done against the special variable <code>$_</code> that
## holds the line just read from the data section using
## <code>&lt;DATA&gt;</code>.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlsyn.html#Loop-Control
##
## Note that there are a couple of subtle points about the test for
## <code>__END__</code>. First, the test is actually for either zero or one
## occurrence of <code>__END__</code>, so the test would succeed (and
## reading of data end) if the <code>__DATA__</code> section contained a
## blank line at some point. Second, the pattern match requested is for
## <code>__END__</code> starting from the beginning of the line (^) and
## ending at the end of the line ($), with nothing else present. But the
## string being tested against (the value of the <code>$_</code>) variable
## does in fact have something else in it, namely a newline at the end of
## the string.
##
## Why then does the test work? Because as noted in the Perl online
## documentation, "the '^' character is guaranteed to match only the
## beginning of the string, the '$' character only the end (<em>or before the
## newline at the end</em>), ..." (emphasis added). In other words, the newline
## at the end of <code>$_</code> is ignored for the purpose of matching the
## specified pattern <code>/^(__END__)?$/</code>.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlre.html#Regular-Expressions
##
  last if /^(__END__)?$/;
##
## h3. For people learning Perl: Parsing template lines and pattern matching
## in a list context
##
## As can be seen by looking at the data sections below, the default
## templates are each defined as a single line containing the flavour,
## the type of template, and the template data itself, each field
## separated by whitespace. We therefore parse each line of the data
## section into three whitespace-separated fields, and then assign the
## values to the private variables <code>$ct</code>, <code>$comp</code>,
## and <code>$txt</code> respectively.
##
## In the code thus far we have seen pattern matching done in a scalar
## context; in that context a pattern match will return the number of
## matches found, or zero if no match exists. However here the pattern match
## is being done in a list context because of the assignment to <code>($ct,
## $comp, $txt)</code>. (Recall that this is comparable to an assignment of
## the form <code>@a = ...</code> where <code>@a</code> is an array variable.)
##
## When done in a list context a pattern match will return an array
## <code>($1, $2, ...)</code> containing the parts of the string that were
## matched. Hence in this context <code>$ct</code> will be assigned the
## value of <code>$1</code>, <code>$comp</code> will be assigned the value
## of <code>$2</code>, and <code>$txt</code> will be assigned the value of
## <code>$3</code>.
##
## To expand a bit on the regular expression: <code>\s</code> matches a
## whitespace character (space, tab, etc.) and <code>\S</code> matches a
## non-whitespace character. The first field gets matched by
## <code>^(\S+)</code>, the second field gets matched by <code>(\S+)</code>,
## and the third field (which can contain spaces) gets matched by
## <code>(.*)$</code>; the field patterns are then separated by the
## <code>\s</code> pattern.
##
## <em>[Note: The regular expression looks for a
## single whitespace character between the fields. On each line in the data
## section there is in fact only a single space between the flavour
## specifier and the template type specifier, on each line, so this works
## out OK. However on some lines there is more than one space between the
## template type specifier and the template content. This does not cause
## any problem in practice, since the pattern for the third field can
## match spaces; the extra spaces are simply included as leading whitespace
## in the value matched for the third field and then assigned to
## <code>$txt</code>.]</em>
##
  my($ct, $comp, $txt) = /^(\S+)\s(\S+)\s(.*)$/;
##
## h3. For people learning Perl: Multiline mode in regular expressions
##
## We modify <code>$txt</code> to change literal occurrences of '\n' (i.e.,
## the '\' character followed by the character 'n') to occurrences of the
## newline character. 
##
## '\\' in the pattern being searched for matches for a literal
## '\', and '\n' in the replacement string is interpreted as a newline
## character. The <code>g</code> option does a global search and replace as
## noted above while the <code>m</code> option searches in multiline mode.
##
## Multiline mode treats the string as a multiline buffer, so you can use
## '^' and '$' to match at the beginning and end of newline terminated
## substrings within the string as a whole.
##
## <em>[Note: It's not exactly clear why multiline mode is used in this
## context, particularly since the regular expression doesn't use either '^'
## or '$'; in testing the substitution seemed to work fine even without the
## <code>m</code> option.]</em>
##
  $txt =~ s/\\n/\n/mg;
##
## h3. For people learning Perl: Nested hashes
##
## We store the default flavour template text read from the data section,
## indexing it by the flavour and type of content.
##
## The usage <code>$a{$b}{$c}</code> is an example of the use of Perl
## references to simulate multi-dimensional arrays or nested hashes.
## To expand on this: the syntax <code>$a{$b}{$c}</code> is equivalent to
## <code>$a{$b}->{$c}</code>, which in turn is equivalent to
## <code>${$a{$b}}{$c}</code>. Here <code>%a</code> is a hash, the value of
## <code>$b</code> is a key for that hash, and the hash value
## <code>$a{$b}</code> is a reference that points to another hash. (The
## second hash is anonymous, i.e., it has no name of its own.) To refer to a
## value in the second hash we use <code>${$a{$b}}{$c}</code> where
## the value of <code>$c</code> is a key in the second hash. As noted above
## we can also use the syntax <code>$a{$b}->{$c}</code> instead, and can in
## turn shorten that to <code>$a{$b}{$c}</code>.
##
## When we make an assignment like <code>$a{$b}{$c} = "def"</code> Perl
## automagically creates the anonymous hash and stores a reference to it in
## <code>$a{$b}</code>. If Perl didn't do this then you'd have to go through
## the following machinations to make the same assignment (assuming that the
## hash <code>%a</code> already existed):
##
##   %h = ();                # Create an empty hash %h
##   $h{$c} = "def";         # Store value "def" in %h at key $c
##   $a{$b} = \%h;           # Store reference to %h in hash %a at key $b
##
## In this example the value could then be referenced as either
## <code>$h{$c}</code> or <code>${$a{$b}}{$c}</code>. Per the online Perl
## documentation, "Anywhere you'd put an identifier ... as part of a variable
## ... name, you can replace the identifier with a simple scalar variable
## containing a reference of the correct type". So we are replacing the
## identifier "h" in <code>$h{$c}</code> with the scalar variable
## <code>$a{$b}</code> that contains a hash reference. We could
## actually use the syntax <code>$$a{$b}{$c}</code> for this but we use the
## extra pair of curly braces to clarify what's going on.
## <code>${$a{$b}}{$c}</code> then becomes <code>$a{$b}{$c}</code> through
## the alternative syntax discussed above.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlreftut.html
##   http://www.perldoc.com/perl5.8.4/pod/perlref.html#Using-References
## 
  $template{$ct}{$comp} = $txt;
}

# Plugins: Start
##
## h3. For people learning Perl: The <code>opendir</code> function
##
## If there's a plugin directory defined we open it and look for plugins,
## using the file handle <code>PLUGINS</code>; we use the <code>opendir</code>
## function instead of <code>open</code> because we are opening a directory,
## not a regular file.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/opendir.html
##
if ( $plugin_dir and opendir PLUGINS, $plugin_dir ) {
##
## h3. For people learning Perl: The <code>readdir</code>, <code>grep</code>,
## and <code>-f</code> functions and the <code>foreach</code> loop
##
## Working backwards from the end of the statement: We use the
## <code>readdir</code> function to return a list of all the entries
## in the plugin directory, and then use the <code>sort</code> function to
## sort those entries in the default (alphabetical) order.
## (<code>readdir</code> returns all directory entries because
## it's being executed in a list context, since <code>sort</code> expects a
## list argument; otherwise <code>readdir</code> would return one directory
## entry at a time.)
##
## We then use the <code>grep</code> function to test each of the sorted
## directory entries against the specified expression (in curly braces) and
## return a list consisting of only those entries for which the expression
## is true. In this case the expression for <code>grep</code> is a compound
## expression consisting of a regular expression and a file test function
## anded together.
##
## We first test using <code>/^\w+$/</code> to make sure that the directory
## entry starts with and contains only alphanumeric characters or '_'; this
## eliminates directory entries for <code>.</code> (the current directory),
## <code>..</code> (the parent directory), and hidden files (e.g.,
## <code>.a</code>). (Note that we don't use the <code>=~</code> operator here
## because we are matching against the special variable <code>$_</code> that
## <code>grep</code> sets in turn to hold the value of each element of the
## list passed to it.)
##
## We then test using the file test function <code>-f "$plugin_dir/$_"</code>
## to verify that the directory entry actually is a file and not something
## else; this eliminates directory entries for the plugin state directory and
## other subdirectories that might be present, as well as directory entries
## for special files like device files, named pipes, and the like. (Again we
## reference the special <code>$_</code> variable set by <code>grep</code>.)
##
## <em>[Note: Symbolic links do pass the <code>-f</code> test (at least on
## Unix and Unix-like systems) if (and only if) they point to regular files.
## Unless other considerations apply, this should allow you to put a plugin
## file in another directory and put a symlink in the plugin directory
## itself.]</em>
##
## Finally, we use a <code>foreach</code> loop to iterate over each element in
## the list of plugins, assigning the value of each element to the variable
## <code>$plugin</code> in turn and executing the statements in the following
## code block.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/readdir.html
##   http://www.perldoc.com/perl5.8.4/pod/func/grep.html
##   http://www.perldoc.com/perl5.8.4/pod/func/-X.html
##   http://www.perldoc.com/perl5.8.4/pod/perlsyn.html#Foreach-Loops
##   http://www.perldoc.com/perl5.8.4/pod/perlvar.html
##
  foreach my $plugin ( grep { /^\w+$/ && -f "$plugin_dir/$_"  } sort readdir(PLUGINS) ) {
##
## h3. For people learning Perl: Parsing plugin names
##
## Recall that plugins can have a (normally two-digit) number at the beginning
## of their names (to enforce a particular plugin order) and can also have an
## underscore character ('_') at the end of their names to disable them from
## being used.
##
## Here we use a regular expression to match and save the actual plugin name
## and look for a concluding '_' if present. (We no longer need the numeric
## prefix since we are now processing the plugins in the proper sort order.)
## Note that the regular expression as written allows underscores to be used
## as part of the plugin name itself; only an underscore at the end is
## special.
##
## The plugin name and the (optional) trailing underscore are saved in the
## special variables <code>$1</code> and <code>$2</code> and then assigned to
## the private variables <code>$plugin_name</code> and <code>$off</code>
## respectively. (See the note to line 142 for more information on pattern
## matching in a list context.)
##
    my($plugin_name, $off) = $plugin =~ /^\d*(\w+?)(_?)$/;
##
## h3. For people learning Perl: Determining if a plugin is disabled
##
## If the final underscore is present (<code>$off</code> has the value '_')
## we set <code>$on_off</code> to -1 to indicate that the plugin is disabled;
## otherwise <code>$on_off</code> is set to 1 to indicate an active plugin.
##
    my $on_off = $off eq '_' ? -1 : 1;
##
## h3. For people learning Perl: The <code>require</code> function
##
## We include the code for the current plugin. (This is somewhat analogous
## to <code>#include</code> in C.) Note that since we are supplying a
## pathname the <code>require</code> function will look for the plugin at
## the pathname (instead of looking in the directories specified by
## <code>@INC</code>, the Perl search path analogous to
## <code>LD_LIBRARY_PATH</code> and similar environment variables in Unix.)
##
## <em>[Note: The Perl online documentation for <code>require</code> mentions
## only searching in <code>@INC</code> directories for a filename, and does
## not explicitly address using a full pathname. This is presumably just an
## oversight.]</em>
## 
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/require.html 
##
    require "$plugin_dir/$plugin";
##
## h3. For people learning Perl: Calling a plugin's start routine
##
## Now that the code for this plugin has been loaded we can call subroutines
## defined in the plugin. We first call the plugin's start routine, using
## the plugin's name in a method invocation (see below). Assuming that the 
## start routine exists and returns a true value, we then use the plugin's
## name as a key to put the plugin's <code>$on_off</code> value into the
## <code>%plugins</code> hash. Finally, we create a new element in the
## <code>@plugins</code> array and set its value to the plugin name. (Recall
## that <code>%plugins</code> and <code>@plugins</code> are entirely
## different variables that just happen to share the same name.)
##
## Note that we set <code>$on_off</code> to the value -1 for off instead of
## 0 because otherwise the middle expression (between the two
## <code>and</code>'s) would have evaluated false, and we would never have
## executed the third expression to set <code>@plugins</code>.
##
## h4. Start routine invocation
##
## For those wanting a more in-depth explanation, calling the start routine
## works as follows:
##
## A plugin "abc" has to define a package <code>abc</code>, as noted in the
## Blosxom plugin developer documentation. So as a result of the "abc" plugin
## being loaded (by <code>require</code>) we can now refer to subroutines
## and variables defined by the package. (Strictly speaking we can't refer
## to everything defined by the package, but let's ignore that for now.) For
## example, if a scalar variable <code>$foo</code> is defined by plugin "abc"
## (i.e., package <code>abc</code>) then we could refer to it as
## <code>$abc::foo</code> to obtain its value. Similarly we could call the
## start subroutine in package <code>abc</code> using the notation
## <code>abc::start()</code>.
##
## However we have a problem: the Blosxom code doesn't know beforehand that
## there's going to be a plugin "abc" (or "foo", or whatever), so the
## Blosxom code can't use <code>abc::start()</code> to invoke package
## <code>abc</code>'s start subroutine. The solution is to use a different
## way to call a routine defined in a plugin: Blosxom invokes
## <code>abc::start</code> as a method rather than calling it as a subroutine.
##
## Methods are a concept from object-oriented (OO) programming, in which
## (in theory) everything of interest is an "object", objects can belong to
## "classes", classes can have "methods" that operate on objects of that
## class, classes can be "subclasses" of higher-level classes, and so on.
##
## For Blosxom (at least Blosxom 2.0) we don't need to worry about the
## full OO story, we simply need to know that in Perl terms an object is
## just a reference, a class is simply a package and a method is a
## subroutine defined by a package. So in our example rather than using
## <code>abc::start()</code> to call the start subroutine in package
## <code>abc</code>, we can use the method invocation notation
## <code>abc->start()</code> instead. (Method invocation
## doesn't work exactly like subroutine calling, particularly in terms
## of which arguments are passed, but we can ignore that for now.)
##
## However we still have the problem of Blosxom not knowing about
## package <code>abc</code> beforehand, so using <code>abc->start()</code>
## won't work either. Fortunately in method invocation instead of a package
## identifier to the left of the <code>-></code> we can substitute a scalar
## variable whose value is a string representing a valid package name. In
## particular, rather than using <code>abc->start()</code> to invoke the
## start subroutine (using the package identifier <code>abc</code>), we can
## set a scalar variable <code>$foo</code> to the value "abc", and then use
## <code>$foo->start()</code> to invoke the subroutine. (We're using
## <code>$foo</code> as an example; Blosxom actually uses the variable
## <code>$plugin_name</code> previously assigned.)
##
## For more information see the following URLs:
##
##   http://www.blosxom.com/documentation/developers/plugins.html
##   http://www.perldoc.com/perl5.8.4/pod/perlobj.html#Method-Invocation
##
## h4. Method invocation vs. symbolic references
##
## <em>[Note: (This is for people like me who get led astray reading Perl
## documentation.) The usage <code>$foo->start()</code> looks
## similar to the use of <code>-></code> with Perl references as previously
## discussed, and it's tempting to think of <code>$foo</code> in this context
## as a kind of reference, in particular a symbolic reference, a Perl concept
## where a scalar variable containing the name of a variable or subroutine
## can get interpreted as a (real) reference to that (second) variable or
## subroutine.</em>
##
## <em>However as far I can tell there is no connection between symbolic
## references and use of a scalar variable to specify the package (class)
## name in method invocation. This is supported by the fact that Blosxom
## does a <code>use strict</code>, which flags use of symbolic references as
## an error; however this doesn't affect the use of scalar variables in
## method invocation.]</em>
##
    $plugin_name->start() and ( $plugins{$plugin_name} = $on_off ) and push @plugins, $plugin_name;
  }
##
## h3. For people learning Perl: The <code>closedir</code> function
##
## Having cycled through all the plugins, we now close the
## <code>PLUGINS</code> file handle we used to open the plugins directory.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/closedir.html
## 
  closedir PLUGINS;
}

# Plugins: Template
# Allow for the first encountered plugin::template subroutine to override the
# default built-in template subroutine
##
## h3. Overriding the default template subroutine
##
## We loop through the <code>@plugins</code> array, which now contains a list
## of plugin names for both active and disable plugins. For each plugin we
## look up its name in the <code>%plugin</code> hash and determine whether the
## plugin is enabled (1) or disabled (-1). If a plugin is enabled we then use
## the plugin name to invoke the <code>can</code> method to see if a template
## subroutine is defined by the plugin's package.
##
## If so then we invoke the plugin's template subroutine, which returns a
## reference to a new (anonymous) subroutine to handle templates; we save the
## reference to that subroutine in the <code>$template</code> variable
## (overriding the value set earlier, representing the default template
## subroutine), and then we exit the loop (and don't bother to look at the
## other plugins).
##
### h3. For people learning Perl: The <code>can</code> method
###
### Earlier we saw a method invocation used to call a plugin's start
### subroutine, using the expression <code>$plugin_name->start()</code>
### where the value of the scalar variable <code>$plugin_name</code> was a
### string with the plugin's name (which is the same name as its package).
### The expression <code>$plugin->can('start')</code> looks similar, except
### for the addition of an argument to be passed to the method.
###
### However plugins don't actually define a <code>can</code> method; where
### then does it come from? Here we see more of the object-oriented features
### of Perl: When doing method invocation (but not when doing a standard
### subroutine call) Perl will look for a method not only in that
### package/class (recall that they are the same in Perl), but also in
### higher-level classes from which the class in question inherits methods.
###
### In particular, Perl has a package <code>UNIVERSAL</code> from which all
### packages inherit the <code>can</code> method. The expression
### <code>abc->can('foo')</code> will invoke the <code>can</code> method and
### check to see if the package <code>abc</code> has the <code>foo</code>
### method defined; if so, it returns a reference to the method, or an
### undefined value if no such method exists. The Blosxom code uses a similar
### expression but using a scalar variable holding the package name instead
### of the package identifier (which it can't know a priori).
### 
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlobj.html#Default-UNIVERSAL-methods
###
#### h3. For people learning Perl: Inside the <code>can</code> method
####
#### By knowing a little bit about how Perl represents subroutines internally
#### we can get a general idea of how the <code>can</code> method works. Internally Perl
#### identifiers for variables, subroutines, etc., are stored in a special
#### hash known as a "symbol table". Every package has its own symbol table,
#### among other things to support the Perl feature that different packages
#### can have different variables that happen to have the same names. A
#### package's symbol table has entries for variables and subroutines defined
#### in that package (except for lexically-scoped items, which we ignore here).
####
#### So if package <code>abc</code> (corresponding to the "abc" plugin) has
#### defined a template subroutine/method, then in the symbol table for
#### package <code>abc</code> (which can be accessed from Perl as the hash
#### variable <code>%abc::</code>) there will be a hash element with key
#### 'template' that will have as its value a special data object called a
#### "typeglob" (the typeglob value is accessible from Perl as
#### <code>$abc::{'template'}</code> or <code>*abc::template</code>); that
#### typeglob in turn can be used to find a reference to the template
#### subroutine (accessible as <code>$abc::template{CODE}</code> using a
#### hash-like notation).
#### 
#### Given a package and a string with the name of the desired method, the
#### <code>can</code> method looks in the package's symbol table to find an
#### entry for that name, and then looks at the typeglob to see if there's
#### actually a subroutine defined with that name. (After all, the package
#### might have a scalar variable, hash, or array with the same name as the
#### subroutine.) The <code>can</code> method then returns the subroutine
#### reference obtained from the typeglob, or an undefined value if no such
#### reference was found.
####
#### One question remains: How does the <code>can</code> method know the
#### package for which it's searching for a method? Because when the
#### <code>can</code> method is invoked Perl passes it an extra argument
#### containing the name of the package/class on which the <code>can</code>
#### method was originally invoked (the <code>abc</code> package in our
#### example).
####
#### Such an extra argument is passed as the first argument to any subroutine
#### invoked as a method (although in some types of method invocation the
#### first argument is a reference and not a class/package name). The presence
#### of this additional argument is another way in which method invocation is
#### different than a subroutine call.
####
#### If you happen to read code for plugins, this is why some subroutines
#### have an argument <code>$pkg</code> (or whatever) that's not shown in the
#### Blosxom code invoking that subroutine. The <code>$pkg</code> argument is
#### present only for plugin subroutines that take arguments in the first
#### place, since in that case the subroutine has to skip over the
#### <code>$pkg</code> argument before getting to the "real" arguments. Plugin
#### subroutines that don't take arguments (like the start and template
#### subroutines) don't worry about this; they just ignore any arguments
#### passed, including the package name argument.
####
#### For more information see the following URLs:
####
####   http://www.perldoc.com/perl5.8.4/pod/perlmod.html#Symbol-Tables
####   http://www.perldoc.com/perl5.8.4/pod/perlref.html
####
my $tmp; foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('template') and defined($tmp = $plugin->template()) and $template = $tmp and last; }

# Provide backward compatibility for Blosxom < 2.0rc1 plug-ins
##
## h3. The <code>load_template</code> subroutine
##
## <em>[Note: Since I've never seen code for Blosxom versions earlier than 2.0
## I'm just going to ignore this code and not worry about it. It doesn't seem
## relevant for current 2.0-based plugins.]</em>
##
sub load_template {
  return &$template(@_);
}

# Define default find subroutine
##
## h3. Default entries subroutine
##
## We define a default subroutine to find entries, just as we previously
## defined a default subroutine to handle flavour templates. We define this
## as an anonymous subroutine and then store a reference to that subroutine
## in the variable <code>$entries</code>. A plugin can then have a
## subroutine <code>entries</code> (not to be confused with
## <code>$entries</code>) that defines a new anonymous subroutine
## and returns its reference as a replacement for the reference in
## <code>$entries</code>.
##
$entries =
  sub {
##
## h3. The return values from the entries subroutine
##
## The entries subroutine returns a list containing three things: a hash
## of all the files representing individual entries (<code>%files</code>),
## (for static rendering only) a hash of all directories needing index pages
## generated and individual entry files needing static pages generated
## (<code>%indexes</code>), and a hash of all other files found
## (<code>%others</code>). 
##
## Note that the private lexical variables <code>%files</code>,
## <code>%indexes</code>, and <code>%others</code> declared here are entirely
## distinct from the global variables of the same names declared on line 69.
## In general using <code>my</code> to declare a private variable within a 
## given lexical scope will "hide" any global variables of the same name, as
## well as private variables of the same name declared at a higher-level
## lexical scope. (See the notes to lines 333 and 357 for another example of
## such hiding.)
##
    my(%files, %indexes, %others);
##
## h3. For people learning Perl: The <code>find</code> subroutine
##
## The default entries subroutine uses the <code>find</code> subroutine from
## File:Find to do all the work. The <code>find</code> subroutine is
## analogous to the Unix <code>find</code> command and takes two arguments,
## a list of directories in which to search (here just <code>$datadir</code>,
## the Blosxom data directory) and a reference to a subroutine that will be
## called by <code>find</code> for each directory entry (e.g., file,
## subdirectory, symlink, etc.) found in the search. (Here we define that
## subroutine as an anonymous subroutine, which automatically produces the
## reference to be passed in.)
##
## To help clarify how <code>find</code> is used, if we wanted to mimic the
## operation of the simple Unix command
##
##   find /blosxom/data -name 'index.*' -print
##
## (find all items whose filenames start with "index.", and print their
## pathnames) we could call <code>find</code> as follows:
##
##   find( sub { /^index\..*\z/s && print "$name\n"; }, '/blosxom/data'); 
##
## Here <code>$name</code> (also known as <code>$File::Find::name</code>) is
## a variable that <code>find</code> sets to the current pathname being
## processed.
##
## For more information see the following URL:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/File/Find.pm
##
    find(
      sub {
        my $d; 
##
## h3. For people learning Perl: <code>$File::Find::dir</code>
##
## The value of <code>$File::Find:dir</code> is the absolute path of the
## directory currently being searched. We count '/' characters in the path
## using <code>tr</code> to obtain the number of directory components in
## the path.
##
        my $curr_depth = $File::Find::dir =~ tr[/][]; 
##
## h3. Interpretation of <code>$depth</code>
##
## We don't process the entries in a directory if it exceeds a specified
## search depth limit. Recall that if <code>$depth</code> was originally set
## to a non-zero value (i.e., to limit the depth of search) then that value
## was adjusted to account for the number of components in the path to the
## Blosxom data directory. See the notes for line 94 for more information.
##
        return if $depth and $curr_depth > $depth; 
     
## h3. Recognizing a Blosxom entry file
##
## As noted above, <code>$File::Find::name</code> contains the absolute
## pathname of the item we are currently processing. We check to see if the
## current item appears to be a Blosxom entry: Its filename has the proper
## extension (<code>.txt</code> by default), it's not an index file or
## hidden file, and it's readable as a file (e.g., as opposed to being a
## directory with a name that looks like a blosxom entry). If so, we do
## further processing on the item as described below to build the
## <code>%files</code> list. Otherwise we consider adding the item to the
## <code>%others</code> list, as described in the notes for line 208.
##
        if ( 
          # a match
##
## h3. For people learning Perl: Regexp matching for entries
##
## The regular expression matching here has some subtleties worth
## exploring. Items that are entries are going to look like, e.g.,
## <code>/blosxom/data/foo.txt</code> (for an entry in the Blosxom data
## directory itself) or <code>/blosxom/data/a/b/bar.txt</code> (for an entry
## in a subdirectory somewhere below the Blosxom data directory). For reasons
## that will become more clear below, we want to save the basename of the
## item's filename (e.g., <code>foo</code> or <code>bar</code> respectively
## in our example) as well as the sequence of subdirectories between the data
## directory and the filename (e.g., '' and <code>a/b</code> respectively in
## our example).
##
## With that in mind let's look more closely at the pattern match. First,
## we use <code>m!...!</code> to delimit the pattern to be matched, as
## opposed to the usual <code>/.../</code>, because the '/' character is part
## of the pattern itself and we don't want to have to escape it (i.e., as
## "\/"). We then match the beginning of the path against the data directory
## with <code>^$datadir/</code>; this would match <code>/blosxom/data/</code>
## in our example above..
##
## To match the subdirectory components we use the pattern
## <code>(?:(.*)/)?</code>. The pattern <code>.*/</code> by itself would
## match subdirectories up to the final '/' (e.g., in the example item
## <code>...a/b/bar.txt</code> above), and in order to save the subdirectory
## components (minus the trailing '/') we could use the pattern
## <code>(.*)/</code>. However we also have to account for the possibility
## that the entry might be in the data directory itself, in which case there
## wouldn't be any subdirectory names and no second '/' character; we could
## handle this case using the pattern <code>((.*)/)?</code> (i.e., match
## either one or zero occurrences of <code>(.*)/</code>).
##
## However now we're capturing the subdirectory part of the path twice:
## one without trailing '/' (e.g., <code>a/b</code>) and once with it (e.g.,
## <code>a/b/</code>); to avoid this redundancy we instead use the pattern
## <code>(?:(.*)/)?</code>. <code>(?:...)</code> is like <code>(...)</code>
## except that it doesn't capture the matched string; as a result
## <code>(?:(.*)/)?</code> captures only the string matched by
## <code>(.*)</code>, and puts it into <code>$1</code>.
##
## To match the item's filename we would use a pattern like
## <code>(.+)\.txt$</code> if we knew the extension would always be
## <code>.txt</code>: we look for one or characters, then a literal '.',
## then the extension at the end of the string, and we capture the basename
## (i.e., the characters before the '.') for later use. In the case of
## Blosxom the value of the extension we're looking for is in a variable,
## so we use the pattern <code>(.+)\.$file_extension$</code> instead,
## where the value of <code>$file_extension</code> gets interpolated into
## the pattern as it would into a double-quoted string.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlre.html#Extended-Patterns
##
          $File::Find::name =~ m!^$datadir/(?:(.*)/)?(.+)\.$file_extension$!
          # not an index, .file, and is readable
##
## h3. Skipping faux entries
##
## We skip over faux entries like <code>index.txt</code>,
## <code>.foo.txt</code>, and <code>foo.txt</code> where <code>foo.txt</code>
## can't be read as a file (e.g., it's a directory instead).
## Note that the last test also implies that Blosxom will silently ignore
## entry files if the web server userid (e.g., "http") does not have
## permission to read them (but does have permission to search the directory
## in which they're located).
##
## <em>[Note: I need more information on the treatment of symlinks by
## Blosxom. A symlink can pass the <code>-r</code> test if it points to a
## readable file. Are there any other considerations that come into
## play here?]</em>
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/-X.html
##
          and $2 ne 'index' and $2 !~ /^\./ and (-r $File::Find::name)
        ) {
##
## h3. For people learning Perl: Chaining <code>and</code> operators
##
## If the current item passes our initial test to see if it might be
## an entry, we do a series of additional tests and operations, in the
## form of a series of expressions <code>a and b and c and ... f</code>
## where each expression is evaluated and we stop if any expression evaluates
## to a false value. Note that in this case some of the expressions anded
## together are parenthesized expressions of the form <code>(x or y or
## ... z)</code>.

            # to show or not to show future entries
##
## h3. For people learning Perl: File modification times
##
## If we're showing future entries (i.e., <code>$show_future_entries</code>
## is true) then we proceed to the next test, otherwise
## the "last modified" time of the current item must be less than the
## current time. Note that <code>stat(...)->mtime</code> is a method call
## where the left hand side of the <code>-></code> operator is an object
## reference (as opposed to a class/package name), in this case a
## File::stat object returned by <code>stat(...)</code>. Both
## <code>mtime</code> and <code>time</code> are expressed in seconds since
## some fixed date ("the epoch") and hence are directly comparable.
##
## For more information see the following URLs:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/File/stat.pm
##   http://www.perldoc.com/perl5.8.4/pod/func/stat.html
##   http://www.perldoc.com/perl5.8.4/pod/func/time.html
            ( 
              $show_future_entries
              or stat($File::Find::name)->mtime < time 
            )

              # add the file and its associated mtime to the list of files
##
## h3. The <code>%files</code> hash
##
## The <code>%files</code> hash has the entry's absolute pathname as a key
## and its modification time as a value. If we didn't have to worry about
## modification times we could just use an array of entry pathnames but we
## need to keep a record of the entry modification times, in particular to
## do sorting of entries and to display the dates for entries.
##
              and $files{$File::Find::name} = stat($File::Find::name)->mtime

                # static rendering bits
##
## h3. Regenerating index files when static rendering
##
## Here we figure out which <code>index.*</code> files we will need to generate
## (or regenerate) when we're doing static rendering, passed on the presence
## of new and/or updated entries.
##
## <em>[Note: It appears that the <code>%indexes</code> hash will be populated
## even if we are doing dynamic rendering, although it's not clear that
## %<code>indexes</code> will be used in that case.]</em>
##
## In general we will have two types of index files that need to be
## generated: index files for directories corresponding to categories (e.g.,
## <code>a/b</code> for an entry <code>foo.txt</code> in that directory) and
## index files corresponding to dates (e.g., <code>2004</code>,
## <code>2004/05</code>, and <code>2004/05/22</code> for an entry
## <code>foo.txt</code> last modified on May 22, 2004). (Note that the main
## Blosxom data directory is a special case of a category directory.)
##
## As we determine which index files need to be (re)generated we build up
## a list (in <code>%indexes</code>) of the directories in which they need
## to be created. We also use <code>%indexes</code> to build up a list of
## individual entries for which static pages need to be generated.
##
                and (
##
## h3. The <code>-all</code> parameter for static rendering
##
## If the <code>-all</code> parameter was passed in with value 1 (i.e.,
## <code>-all=1</code> on the command line) then we (re)generate all
## <code>index.*</code> files.
##
## For more information see the following URL:
##
##   http://www.blosxom.com/documentation/users/configure/static.html
##
                  param('-all') 
##
## h3. Creating new index files
##
## If there is no index file of the default flavour (e.g.,
## <code>index.html</code>) for the directory in which the entry is located
## (<code>$static_dir/$1</code>) then we generate a new one. Recall that
## <code>@static_flavours</code> is the list of flavours to be generated
## statically; <code>$static_flavours[0]</code> is 'html' by default. 
##
## (Note that we actually end up generating index files for all the flavours
## in <code>@static_flavours</code>, not just the first flavour. It's just
## more convenient to check for only one flavour, assuming that if its index
## file needs to be generated then the index files for the other static
## flavours do too.)
## 
                  or !-f "$static_dir/$1/index." . $static_flavours[0]
##
## h3. Updating old index files for new or updated entries
##
## If the default index file (e.g., <code>index.html</code>) is older than
## the entry being processed then we update the <code>index.*</code> files
## in the entry's directory.
##
## (Again, we're checking the index file for one flavour and extrapolating
## the results for the other static flavours.)
##
                  or stat("$static_dir/$1/index." . $static_flavours[0])->mtime < stat($File::Find::name)->mtime
                )
##
## h3. The <code>%indexes</code> hash and category directories
##
## The <code>%indexes</code> hash uses the directory pathname relative to the
## Blosxom data directory (e.g., <code>a/b</code>) as a key. This relative
## pathname can also be thought of as a relative URL, with the base URL
## being the URL that resolves to the Blosxom script.
##
## For an <code>%indexes</code> element corresponding to a category directory
## (e.g., <code>a/b</code>) we set the value of the element (e.g.,
## <code>$indexes{'a/b'}</code>) to 1. (See the note for line 203
## for the value of <code>%indexes</code> entries for date directories,
## e.g., <code>2004/05/22</code>.)
##
                  and $indexes{$1} = 1
##
## h3. For people learning Perl: Date directories and array slices
##
## If an entry was created on a certain date (e.g., May 22, 2004) then we
## need to create index files in a subdirectory corresponding to that date
## (e.g., <code>2004/05/22/index.html</code>) so that date-based Blosxom
## URLs will work properly.
##
## Note that the <code>nice_date</code> subroutine (defined below) takes a
## time in seconds since the epoch (here the entry's "last modified" time as
## stored in <code>%files</code>) and returns a list containing the various
## parts of the date/time broken out.
##
## Here we need only the year, month number, and day, so rather than using
## the entire list returned by <code>nice_date</code> we just use the
## elements we need, using Perl slice notation: <code>@a[5,2,3]</code> means
## a list consisting of <code>$a[5]</code>, <code>$a[2]</code>, and
## <code>$a[3]</code>, where here <code>@a</code> is replaced by
## <code>(nice_date(...))</code>. (The parentheses around
## <code>nice_date(...)</code> are needed for proper Perl syntax.)
##
## We then take the slice, e.g., <code>("2004", "05", "22")</code>, and
## join the elements with '/' to get the  relative path we need, e.g.,
## <code>2004/05/22</code>.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perldata.html#Slices
##
                    and $d = join('/', (nice_date($files{$File::Find::name}))[5,2,3])
  
##
## h3. The <code>%indexes</code> hash and date directories
##
## We add the date subdirectory (e.g., <code>2004/05/22</code>) to the
## <code>%indexes</code> hash.
##
## For an <code>%indexes</code> element corresponding to a date directory
## we set the value of the element (e.g., <code>$indexes{'2004/05/22'}</code>)
## to the relative pathname of the date directory itself (e.g.,
## <code>2004/05/22</code>, same as the key). (Recall from the notes for line
## 200 that for <code>%indexes</code> elements corresponding to category
## directories we set the values of the elements to 1.)
##
                      and $indexes{$d} = $d
##
## h3. The <code>%indexes</code> hash and static entry pages
##
## If we are generating static entry pages then we also add the entry's
## relative pathname (e.g., <code>a/b/foo.txt</code>) to
## <code>%indexes</code>. (We can't just use <code>$File::Find:name</code>
## as the key here, as we did in <code>%files</code>, because that's an
## absolute pathname that includes the Blosxom data directory.)
##
## We use the conditional expression <code>($1 ? "$1/" : "")</code> because
## we have to handle specially the case when the entry is in the Blosxom
## data directory itself and not in a subdirectory somewhere underneath it;
## in that case the subdirectory part of the entry's pathname (the middle
## part stored in <code>$1</code>) will be empty, and we don't want to add
## an extra '/' we don't need. 
##
## For a <code>%indexes</code> element corresponding to an individual entry we
## set the value of the element (e.g., <code>$indexes{'a/b/foo.txt'}</code>)
## to 1, the same as for <code>%indexes</code> elements for category
## directories.
##
                        and $static_entries and $indexes{ ($1 ? "$1/" : '') . "$2.$file_extension" } = 1

            } 
            else {
##
## h3. The <code>%others</code> hash and non-entry files
##
## As noted above, we come to the <code>else</code> block when the item being
## processed does not appear to be a Blosxom entry file (e.g., it might be
## an existing file like <code>foo.html</code>).
##
## If the item is not a directory and it's readable then we add it to the
## <code>%others</code> hash, using its absolute pathname as the key and its
## "last modified" time as the value. (This is the same way the
## <code>%files</code> hash is structured.)
##
              !-d $File::Find::name and -r $File::Find::name and $others{$File::Find::name} = stat($File::Find::name)->mtime
            }
##
## h3. Completing the arguments to <code>find</code>
##
## We've finally come to the end of the first argument to <code>find</code>,
## the anonymous subroutine to process items, and we include
## <code>$datadir</code> as the second argument, the directory at which we
## wish to start searching for items.
##
      }, $datadir
    );

##
## h3. For people learning Perl: Returning reference values
##
## At the end of the default entries subroutine we return a list of
## references to the <code>%files</code>, <code>%indexes</code>, and
## <code>%others</code> hashes.
##
## Recall that <code>%files</code>, <code>%indexes</code>, and
## <code>%others</code> were defined as private variables of this anonymous
## subroutine using <code>my</code>. This makes them so-called
## "lexical" variables whose scope is limited to the subroutine, i.e., they
## would not normally be visible outside this subroutine. However by passing
## back references we make it possible for other parts of the Blosxom code
## to use the values of the <code>%file</code>, <code>%indexes</code>, and
## <code>%others</code> variables, and we
## ensure that the values of the variables stick around as long as we need
## to access them. As the Perl online documentation puts it, "So long as
## something else references a lexical, that lexical won't be freed... This
## means that you can pass back or save away references to lexical
## variables".
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlsub.html#Persistent-Private-Variables
##
    return (\%files, \%indexes, \%others);
  };

# Plugins: Entries
# Allow for the first encountered plugin::entries subroutine to override the
# default built-in entries subroutine
##
## h3. For people learning Perl: Overriding the default entries subroutine
##
## This is exactly the same approach we used earlier to allow plugins to
## override the default template subroutine. See the notes for line 161 for
## more information concerning how this code works.
##
my $tmp; foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('entries') and defined($tmp = $plugin->entries()) and $entries = $tmp and last; }

## h3. For people learning Perl: Calling the entries subroutine
##
## We invoke the entries subroutine to search for entries and build the
## <code>%files</code>, <code>%indexes</code>, and <code>%others</code>
## hashes. Because <code>$entries</code> is a reference to an
## anonymous subroutine (either the one we defined above or one defined by a
## plugin to override the default) we use <code>&</code> to dereference the
## reference and actually call the subroutine.
##
## Also recall that the entries subroutine returns a list of references to
## hashes, not the hashes themselves. That's why we assign the list of
## returned values into scalar variables, e.g., <code>$files</code> will now
## have as its value a reference to the <code>%files</code> hash created in
## the subroutine.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlref.html#Using-References
##
my ($files, $indexes, $others) = &$entries();
##
## h3. For people learning Perl: Using references to create hash copies
##
## We dereference the returned references in <code>$files</code>,
## <code>$indexes</code>, and <code>$others</code> to set our own hash
## variables <code>%files</code>, <code>%indexes</code>, and
## <code>%others</code>.
##
## Note that despite having the same names these are separate and distinct
## variables from the <code>%files</code>, <code>%indexes</code>, and
## <code>%others</code> variables defined in the default entries subroutine:
## the <code>%files</code>, etc., variables in the entries subroutine are
## private lexical variables while the <code>%files</code>, etc., variables
## here are global variables for the Blosxom code (originally defined above
## at line 69 with <code>use vars</code>).
##
## Also note that the assignments <code>%files = %$files</code>, etc.,
## actually create copies of the original hashes constructed by the entries
## subroutine, just like an assignment <code>%files = %h</code> where
## <code>%h</code> is some existing hash.
##
## Finally, the code used to assign <code>%others</code> reflects the fact
## that (as shown in the example in the Blosxom plugin developer's
## documentation) a plugin might not actually build a <code>%others</code>
## list and return a reference to it; in that case <code>$others</code>
## would be undefined or empty. We therefore use the <code>ref</code> function
## to verify that <code>$others</code> is a proper reference before we attempt
## to deference it, otherwise we assign <code>%others</code> to be an empty
## hash.
##
## For more information see the following URLs:
##
##   http://www.blosxom.com/documentation/developers/plugins.html
##   http://www.perldoc.com/perl5.8.4/pod/func/ref.html
##
%files = %$files; %indexes = %$indexes; %others = ref $others ? %$others : ();

# Plugins: Filter
##
## h3. For people learning Perl: Calling plugin filter subroutines
##
## Having constructed the lists of entries and other files, we allow plugins
## to modify that list themselves by defining a filter subroutine. The code
## here is similar to the code used for the template and entry subroutines:
## we iterate over all plugins, check to see that the plugin is enabled and
## it defines a filter method, and if so then we invoke the method, passing
## references to the <code>%files</code> and <code>%others</code> hashes. The
## major difference here is that we do not terminate the loop early as soon
## as we find a plugin with a filter subroutine; instead we call the filter
## subroutine for each and every plugin that defines one.
##
## Note that although the code passes references to both <code>%files</code>
## and <code>%others</code> the Blosxom developer documentation mentions
## passing only the <code>%files</code> reference. (One more reason to read
## the actual code :-) Since the filter subroutine is passed references to
## the hashes it can modify them directly by deleting, modifying, or even
## adding hash elements.
##
## Finally, note that although the return value from the filter subroutine
## is assigned into the <code>$entries</code> variable used earlier to hold
## a reference to the entries subroutine, the return value is simply a 0 or
## 1 return code indicating whether the filter subroutine for a given plugin
## succeeded or failed. Since we already called the entries subroutine and
## won't do so again, we no longer need the original value of
## <code>$entries</code>; from this point on in the code
## <code>$entries</code> is used simply to save return values from plugin
## subroutines.
##
## <em>[Note: Arguably it's bad coding style to re-use <code>$entries</code>
## in this potentially confusing way. As it happens it doesn't appear to be
## necessary to use a variable for this purpose anyway, since
## <code>$entries</code> is assigned to but never referenced -- why not just
## use code like</em>
##
##   foreach my $plugin ( @plugins ) { ... and $plugin->filter(...) }
##
## <em>where we just test the return value directly and don't save it?]</em>
##
## For more information see the following URL:
##
##   http://www.blosxom.com/documentation/developers/plugins.html
##
foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('filter') and $entries = $plugin->filter(\%files, \%others) }

# Static
##
## h3. Deciding whether to generate static or dynamic pages
##
## We check to see if we are generating static pages or dynamic pages,
## and execute the appropriate code.
##
## <em>[Note: The conditional expression below exactly duplicates the
## expression used at line 99 above to set the variable
## <code>$static_or_dynamic</code>; why not just use the code</em>
##
##   if ($static_or_dynamic eq 'static') {
##
## <em>instead?]</em>
##
if (!$ENV{GATEWAY_INTERFACE} and param('-password') and $static_password and param('-password') eq $static_password) {

## h3. Generating static pages: The <code>-quiet</code> option
##
## We print a status message (on stdout) unless the option
## <code>-quiet</code> was passed on the command line.
##
  param('-quiet') or print "Blosxom is generating static index pages...\n";

  # Home Page and Directory Indexes
##
## h3. Generating static pages: The <code>%done</code> hash
##
## The <code>%done</code> hash is used to keep track of whether we've done
## static page generation for a particular directory; see the notes for line
## 240 below.
##
  my %done;
##
## h3. Generating static pages: Iterating over <code>%indexes</code>
##
## We iterate over all index-related items stored in the 
## <code>%indexes</code> hash.
##
## Recall that if we are generating static pages then <code>%indexes</code>
## will contain three types of items, all expressed as relative pathnames
## (relative to the Blosxom data directory): category directories for which
## <code>index.*</code> pages need to be generated (e.g., <code>a/b</code>),
## date directories that need to be created with <code>index.*</code> pages
## to support date-based URLs (e.g., <code>2004/05/22</code>), and individual
## entries for which static pages need to be generated (e.g.,
## <code>a/b/foo.txt</code>).
##
## For each item we will need to create not only static pages for those
## items, but also the directories needed to contain those static pages,
## the higher-level directories containing those directories (e.g.,
## subdirectory <code>a</code> under the data directory for a category
## directory <code>a/b</code>, or directories <code>2004</code> and
## <code>2004/05</code> for a date directory <code>2004/05/22</code>), and
## index pages for those higher-level directories.
##
  foreach my $path ( sort keys %indexes) {
##
## h3. Generating static pages: Keeping track of parent directories
##
## As noted above we have to worry not only about static pages corresponding
## directly to each <code>%indexes</code> key (e.g., the index page
## <code>a/b/index.html</code> where <code>$path</code> is the
## <code>%indexes</code> item <code>a/b</code>), but also static pages for
## any higher-level directories (e.g., the index page
## <code>a/index.html</code> for directory <code>a</code> as well as the
## index page <code>index.html</code> for the data directory itself, the
## parent directory of <code>a</code>).
##
## The variable <code>$p</code> is used to iterate over all directory
## components in <code>$path</code> and make sure that the necessary
## directories are created and index pages generated. We start off at
## <code>$p = ''</code>, representing the Blosxom data directory itself.
##
    my $p = '';
##
## h3. Generating static pages: Iterating over <code>$path</code>
## components
##
## We iterate over each component of the relative pathname stored in
## <code>$path</code>, in order to create higher-level directories and
## their corresponding static pages where appropriate. We include the empty
## string '' as the first element of the <code>foreach</code> list in order
## to handle index files at the level of the Blosxom data directory.
##
## Thus, for example, if <code>$path</code> is <code>a/b</code> then we will
## iterate over '', <code>a</code>, and <code>b</code>. If <code>$path</code>
## is <code>2004/05/22</code> then we will iterate over '',
## <code>2004</code>, <code>05</code>, and <code>22</code>.
##
    foreach ( ('', split /\//, $path) ) {
##
## h3. Generating static pages: Building the relative pathname <code>$p</code>
##
## We add the current subdirectory component to the relative pathname being
## built up. Since <code>$p</code> is initially the empty string '' and the
## first element of the <code>foreach</code> loop is '' as well,
## <code>$p</code> will be set to '/' the first time through the loop, and
## we'll then need to remove the leading '/'. On subsequent iterations
## <code>$p</code> will end up being set to, e.g., <code>2004</code>,
## <code>2004/05</code>, etc., assuming a value for <code>$path</code> of
## <code>2004/05/22</code>.
##
      $p .= "/$_";
      $p =~ s!^/!!;
##
## h3. Generating static pages: Make relative path available to plugins
##
## We save the current relative pathname (in <code>$p</code>) as
## <code>$path_info</code> so that plugins will have access to it (as a global
## variable in the <code>blosxom</code> package).
##
      $path_info = $p;
##
## h3. Generating static pages: Relative path already processed?
##
## We keep track of whether we have seen this relative path before.
## If not (i.e., if <code>$done{$p}</code> is false) then we increment
## <code>$done{$p}</code> by 1 and proceed to process it. Otherwise we skip
## to the next item in the <code>foreach</code> loop.
##
### h3. For people learning Perl: <code>$a++</code> vs. <code>++$a</code>
###
### Note that the check here works because <code>++</code> is used as a
### suffix operator, and hence <code>$done{$p}</code> is incremented after
### its value is checked. Also, if <code>$done{$p}</code> is undefined (which
### would be the case initially, since <code>%done</code> is not otherwise
### initialized) then its value will be converted to zero prior to
### incrementing it.
###
### For more information see the following URL:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Auto-increment-and-Auto-decrement
###
      $done{$p}++ and next;
##
## h3. Generating static pages: Creating directories as needed
##
## We check to see if there is already an existing directory corresponding to
## the path we're working on, or if the path represents an individual
## entry. Otherwise the path represents a directory that needs to be created,
## and we use the <code>mkdir</code> function to create the directory. (We
## attempt to set the directory's access permissions to "rwxr-xr-x" so that
## anyone can look up files in the directory, but this may be made more
## restrictive by the <code>umask</code> setting of the user executing
## <code>blosxom.cgi</code> in static mode. Note that at a minimum the userid
## associated with the web server, e.g., "httpd", needs "r" access to the
## static pages and "rx" access to the directories containing them.)
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/-X.html
##   http://www.perldoc.com/perl5.8.4/pod/func/mkdir.html
##
      (-d "$static_dir/$p" or $p =~ /\.$file_extension$/) or mkdir "$static_dir/$p", 0755;
##
## h3. Generating static pages: Creating pages for all needed flavours
##
## We iterate over all the flavours for which we need to create static pages.
##
      foreach $flavour ( @static_flavours ) {
##
## h3. Generating static pages: Determining the content type for a flavour
##
## We use the reference stored in <code>$template</code> to call a subroutine
## to determine what content type we should pass to the generate subroutine.
## (Recall that <code>$template</code> was set to a reference to an anonymous
## subroutine returned by a template subroutine, either the default defined
## in <code>blosxom.cgi</code> or one provided by a plugin to override the
## default.)
##
## In the case of the default subroutine we look for a file with filename
## <code>content_type.<i>$flavour</i></code> (e.g.,
## <code>content_type.html</code>) in the directory specified
## by <code>$p</code> or in its parent directories (up to and including the
## Blosxom data directory) and, if found, use the value of
## <code>content_type</code> that it defines. Otherwise we use the default
## value of <code>content_type</code> found in the <code>%templates</code>
## hash; for example, for the 'html' flavour we would use
## a content type of 'text/html'.
##
## We look for a newline in the <code>content_type</code> value and delete
## it and anything after it. This might be the case if the content type were
## defined in a file; we only need the first line of the file (prior to
## the first newline) and can ignore the rest.
##
        my $content_type = (&$template($p,'content_type',$flavour));
        $content_type =~ s!\n.*!!s;
##
## h3. Generating static pages: Relative pathname for the page to be created
##
## We determine the relative pathname for the static page we need to create,
## up to but not including the extension. If the path <code>$p</code>
## represents an individual entry (e.g., <code>a/b/foo.txt</code>) then
## <code>$fn</code> will be, e.g., <code>a/b/foo</code>; otherwise
## <code>$p</code> represents a directory in which index files need to be
## created and <code>$fn</code> will be, e.g., <code>a/b/index</code>.
##
## <em>[Note: Unlike <code>$content_type</code> (which depends on the
## specific flavour for which we need to create a static page), the value of
## <code>$fn</code> could have been determined before entering the static
## flavour <code>foreach</code> loop, since it will be the same no matter
## what the flavour happens to be.]</em>
## 
        my $fn = $p =~ m!^(.+)\.$file_extension$! ? $1 : "$p/index";
        param('-quiet') or print "$fn.$flavour\n";
##
## h3. For people learning Perl: Opening files for writing
##
## We attempt to create (or rewrite, i.e., open and truncate) the static page
## for this favour.
##
## For more information see the following URLs:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/FileHandle.pm
##   http://www.perldoc.com/perl5.8.4/pod/func/open.html
##
        my $fh_w = new FileHandle "> $static_dir/$fn.$flavour" or die "Couldn't open $static_dir/$p for writing: $!";  
##
## h3. Generating static pages: Beginning output for a page
##
## <code>$output</code> is the global variable used by the
## <code>generate</code> subroutine to build up the data for the page.
##
        $output = '';
##
## h3. Generating static pages: Generating a page
##
## We call the <code>generate</code> subroutine to generate the data for
## the static page and then write it to the just-opened file.
##
## If the current <code>%indexes</code> element has the value 1 then it
## corresponds to a category directory or individual entry, and we pass
## <code>$p</code> to the <code>generate</code> subroutine as its
## <code>$currentdir</code> argument and the empty string '' as the
## <code>$date</code>  argument.
## Otherwise the <code>%indexes</code> element represents a date-related
## index page and we pass <code>$p</code> as the date and the empty string
## '' as the <code>$currentdir</code> argument.
##
## See the notes for lines 266 (generating a dynamic page) and 273 and 274
## (the <code>generate</code> subroutine) for more information about the
## arguments passed.
##
        print $fh_w 
          $indexes{$path} == 1
##
## h3. For people learning Perl: Referencing the <code>generate</code>
## subroutine
##
## <em>Note: In this expression we use</em>
##
##   &generate(...)
##
## <em>instead of</em>
##
##   generate(...)
##
## <em>as one might expect. According to the online Perl documentation the
## initial '&amp;' is typically optional and may be omitted. Using '&amp;' does
## disable checking of prototypes, but the <code>generate</code> subroutine
## doesn't use prototypes. Is there some other reason for using '&amp;'
## here?</em>
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlsub.html
##
            ? &generate('static', $p, '', $flavour, $content_type)
            : &generate('static', '', $p, $flavour, $content_type);
##
## h3. Generating static pages: Finished with a page
##
## We have finished writing this static page; close the FileHandle and go
## on to the next static flavour.
##
        $fh_w->close;
      }
    }
  }
}

# Dynamic
##
## h3. Generating a dynamic page
##
## The code for a dynamic page is much simpler than that for static pages;
## all it has to do is to create the content type header and call the
## <code>generate</code> subroutine to create the content to be returned
## in the HTTP response.
##
else {
##
## h3. Generating a dynamic page: Content type
##
## See the notes for line 243 in the code for static pages for more
## information about <code>$content_type</code>.
##
  my $content_type = (&$template($path_info,'content_type',$flavour));
  $content_type =~ s!\n.*!!s;

##
## h3. Generating a dynamic page: HTTP headers
##
## We store the content type in an anonymous hash referenced by
## <code>$header</code>, under the key '-type'.
##
## Note that this variable will later be passed to the <code>CGI::header</code>
## function as its single argument. (See the notes to line 409.) By using a
## hash to store the arguments we allow Blosxom plugins to cause additional
## HTTP headers to be output (i.e., other than the Content-type header) by
## adding additional key/value pairs to the hash referenced by
## <code>$blosxom::header</code>. For example, this is done by the cookies,
## lastmodified, and xhtml plugins.
##
## For more information see the following URL:
##
##   http://www.blosxom.com/plugins/headers/index.html
##
### h3. For people learning Perl: Arguments to the <code>CGI::header</code>
### function
###
### The <code>CGI::header</code> function can be called in three different
### ways. First, it can be called with a single argument that is the content
### type in the form of a string, e.g.,
###
###   header('text->html')
###
### It can also be called with multiple named arguments, of which the content
### type might be only one. When using multiple arguments there are two
### possible styles of argument passing, e.g.,
###
###   header(-type => 'text/html', -expires => '+3d')
###
### or
###
###   header({-type => "text/html", -expires => "+3d"})
###
### The former style is basically passing an array of arguments and is
### equivalent to, e.g.,
###
###   header('-type', 'text/html', '-expires', '+3d')
###
### while the latter is passing a reference to an anonymous hash.
###
### The Blosxom code assumes the third style of argument passing shown above,
### using the variable <code>$header</code> to store a reference to an
### anonymous hash (as discussed in the previous note).
###
### Note that older versions of the CGI module do not support all
### styles of argument passing. In particular, versions prior to 2.0 do not
### support passing multiple arguments to the <code>CGI::header</code>
### function, and versions prior to 2.37b7 do not support putting curly braces
### around the argument list (i.e., passing the argument list as a hash
### reference).
###
### If your hosting service does not support a recent version of the
### CGI module then you may need to patch Blosxom to fix the
### way the content type is handled. The simplest patch is to revert to the
### original style of passing a single string argument to
### <code>CGI::header</code>:
###
###   $header = $content_type;
###
### Note that if you use this patch then you will not be able to use Blosxom
### plugins that add their own HTTP headers. (See the previous note.)
###
### For more information see the following URLs:
###
###   http://search.cpan.org/~lds/CGI.pm-3.05/CGI.pm#CALLING_CGI.PM_ROUTINES
###   http://stein.cshl.org/WWW/software/CGI/#named_param
###
  $header = {-type=>$content_type};

## h3. Generating a dynamic page: Page generation
##
## We call the <code>generate</code> subroutine to do the actual work of
## generating the page, passing the following arguments:
##
## * <code>'dynamic'</code>: Generate a dynamic page.
## * <code>$path_info</code>: A relative path containing the category and
## individual entry information we found in the originally-requested URL.
## Note that <code>$path_info</code> will be empty if the URL contained
## date references only or the URL was requesting a top-level index, i.e.,
## at the level of the Blosxom data directory. See the notes for lines
## 102 through 121 for more information.
## * <code>"$path_info_yr/$path_info_mo_num/$path_info_da"</code>:
## We pass a string containing whatever date information we found in the
## originally requested URL. Note that the date string passed may be partial
## (e.g., '2004//' or '2004/05/') or "empty" ('//') if the original URL didn't
## reference a date. See the notes for lines 124 and 125 for more
## information.
## * <code>$flavour</code>: The flavour of page requested; see the notes for
## lines 110 through 118 for more information.
## * <code>$content_type</code>: The content type (determined by the flavour);
## see the notes for lines 261 and 262 above.
##
  print generate('dynamic', $path_info, "$path_info_yr/$path_info_mo_num/$path_info_da", $flavour, $content_type);
}

# Plugins: End
##
## h3. Calling plugin end subroutines
##
## We call the end subroutine for each plugin (if it defined one). The
## approach here is identical to that used for calling the filter subroutine
## and other plugin subroutines that are called for each plugin; see the
## notes for line 225 for an explanation of the code.
##
## Note that the end subroutine is not passed any arguments; however it could
## use information previously stored in global variables in the plugin's
## package.
##
## Once the end subroutines have been called we are done with processing.
##
foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('end') and $entries = $plugin->end() }

##
## h3. Blosxom subroutines
##
## This marks the end of the main Blosxom code section. The remainder
## of the code defines two subroutines:
##
## * <code>generate</code>: does the main work of page generation
## * <code>nice_date</code>: parses Perl date/time values for easier
## processing
##
# Generate 
##
## h3. The <code>generate</code> subroutine
##
## The <code>generate</code> subroutine does the actual work of generating a
## page, and returns a (multiline) string containing the generated output for
## the page.
##
sub generate {
##
## h3. Arguments to the <code>generate</code> subroutine
##
## The generate subroutine takes the following arguments:
##
## * <code>$static_or_dynamic</code> has the value 'static' if we are
## generating a static page and 'dynamic' if we are generating a dynamic page.
## * <code>$currentdir</code> contains category and individual entry
## entry information, in the form of a relative path, e.g., <code>a/b</code>
## or <code>a/b/foo.html</code>. Note that <code>$currentdir</code> will be
## empty if the request being processed or the static page being generated
## is for the index page at the top level (i.e., the Blosxom data directory)
## or is for an index of all entries for a particular date.
## * <code>$date</code> contains date information, in the form of a string
## 'yyyy/mm/dd'. Note that <code>$date</code> may be "empty" ('//') if no date
## information is associated with the request or the static page being
## generated; <code>$date</code> may also have a partial value (e.g.,
## '2004//' or '2004/05//'). 
## * <code>$flavour</code> is the flavour for which a page is being
## generated, e.g., 'html' or 'rss'.
## * <code>$content_type</code> is the MIME type for the page, e.g.,
## 'text/html' for an HTML page or 'text/xml' for an RSS page.
##
  my($static_or_dynamic, $currentdir, $date, $flavour, $content_type) = @_;

## h3. For people learning Perl: Global variables in the
## <code>generate</code> subroutine
##
## Besides its arguments, the <code>generate</code> subroutine also has
## access to the global variables <code>%files</code>, etc. We make a local
## copy of the <code>%files</code> hash containing information about all the
## entries we might need to include on this page.
##
  my %f = %files;

  # Plugins: Skip
  # Allow plugins to decide if we can cut short story generation
##
## h3. Calling the plugin skip subroutines
##
## We loop through all enabled plugins to see if any of them define a skip
## subroutine; if so we invoke it, set the returned value to
## <code>$skip</code>, and if the returned value is true end the loop.
## Otherwise <code>$skip</code> will end up set to false (i.e., we are not
## skipping story generation).
###
### h3. For people learning Perl: Calling the plugin skip subroutines
###
### For more information on how this code works see the earlier notes for
### lines 161 and 225 discussing the template and filter subroutines.
###
  my $skip; foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('skip') and defined($tmp = $plugin->skip()) and $skip = $tmp and last; }
  
  # Define default interpolation subroutine
##
## h3. The default interpolate subroutine
##
## The default interpolate subroutine is used to replace occurrences of
## Blosxom variables with the values of those variables. (For example, in
## the head section it would replace occurrences of the string
## '<code>$blog_title</code>' with the value of the <code>$blog_title</code>
## variable.) It is called with one argument, the template string in which
## interpolation is to be done.
##
## The interpolate subroutine is defined as an anonymous subroutine whose
## reference is stored in <code>$interpolate</code>. This is the same
## approach used with the template subroutine, etc.
##
## <em>[Note: The default interpolate subroutine is newly defined each time
## we call the <code>generate</code> subroutine. This is presumably necessary
## because overriding the default interpolate subroutine (unlike overriding
## the template or entries subroutines) is not necessarily a one-time decision:
## different plugins might choose to define their own interpolate
## subroutine at different times for different reasons.]</em>
##
  $interpolate = 
    sub {
##
## h3. For people learning Perl: Variables used for interpolation
##
## We (re)specify the <code>blosxom</code> package here to ensure that we are
## using the <code>blosxom</code> package namespace when we execute this
## subroutine. This is necessary for us to properly interpolate Blosxom
## global variables when we call this subroutine from a plugin.
##
## <em>[Note: I need to double-check that this is the actual reason. Also,
## I presume that for a variable to be interpolated it must be a global
## variable in the <code>blosxom</code> package, i.e., no lexical variables
## can be interpolated even if they are of file scope.]</em>
##
      package blosxom;
      my $template = shift;
##
## h3. How the interpolate subroutine works
##
## <code>$template</code> (the first and only argument to the interpolate
## subroutine) is the template contents to be processed.
##
## We look for substrings in <code>$template</code> that appear to be Perl
## identifiers, either unqualified identifiers like <code>$foo</code> or
## package-qualified identifiers like <code>$abc::foo</code> (but not, for
## example, variable references like <code>${foo}</code> or
## <code>$abc::def::foo</code>). For any strings we find that are actual
## defined Perl variables we replace the string with the result of evaluating
## the variable, otherwise we replace it with the empty string ('').
##
### h3. For people learning Perl: Recognizing and evauating a Perl scalar
### variable
###
### The regular expression here matches a literal '$' followed by one or more
### "word" characters (alphanumeric or underscore) followed by an optional
### '::' if the identifier is package-qualified, followed by zero or more
### word characters (for any identifier after the '::'). We use
### <code>(?:::)?</code> instead of <code>(::)?</code> because we don't need
### to or want to capture the '::' string for later reference.
###
### Note that the regular expression used will not match package-qualified
### identifiers of the form <code>$abc::def::foo</code>. This is not a
### problem in practice because neither the <code>blosxom</code> package nor
### the plugin packages use package names of the form <code>abc::def</code>.
### The regular expression also will not match variables of the form
### <code>${foo}</code>. Again, this should not be a problem in practice
### because the braces are normally used to disambiguate variable references
### in a context where they would be ambiguous, e.g., <code>"$foo's
### blog"</code> where the single quote could be interpreted as an old-style
### Perl package qualifier; however in our case we are looking at the variable
### in isolation, without any context, and that eliminates (or at least
### reduces) any possibly ambiguities.
###
### (The only problem would be if we wanted to put alphanumeric characters
### immediately after the variable reference, e.g., if the template contents
### contained a string like <code>"$blog_titlexxx"</code> then we would try
### to interpolate the variable <code>$blog_titlexxx</code> (and fail) instead
### of concatenating the value of <code>$blog_title</code> with three 'x'
### characters.)
###
### In the replacement string we use the <code>ee</code> option to treat the
### string as a Perl expression and evaluate it as such at runtime. So, for
### example, if the pattern matched is <code>$blog_title</code> (i.e., a
### literal '$' followed by the word 'blog_title') then the replacement string
### becomes the Perl expression
###
###   if defined $blog_title ? $blog_title : ''
###
### In other words, if evaluating <code>$blog_title</code> produces a defined
### value (e.g., 'My First Blog'), then use that value to replace the matched
### pattern (<code>$blog_title</code>),  otherwise use the empty string '' as
### the replacement string. This Perl expression is then evaluated at run-time
### to produce the desired result.
###
### The <code>g</code> option matches all occurrences of things that look like
### Perl scalar variables. The net effect is that all apparent Perl scalar
### variables in the template contents are replaced with the value of the
### variables in question, or with the empty string if no such variables
### exist (or they exist but do not have defined values).
###
### <em>[Note: I have two open questions here: First, why is the replacement
### string enclosed in double-quotes, i.e.,</em>
###
###   $template =~ s/(\$\w+(?:::)?\w*)/"defined $1 ? $1 : ''"/gee;
###
### <em>instead of</em>
###
###   $template =~ s/(\$\w+(?:::)?\w*)/defined $1 ? $1 : ''/gee;
###
### <em>Second, why use the <code>defined</code> function at all? In testing
### the following code seemed to work identically and without any errors:</em>
###
###   $template =~ s/(\$\w+(?:::)?\w*)/$1/gee;
###
### <em>In what circumstances might an error occur with this simpler
### code?]</em>
###
### For more information see the following URLs:
###
###   http://www.perldoc.com/perl5.8.4/pod/perlre.html
###   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Regexp-Quote-Like-Operators
###   http://www.perldoc.com/perl5.8.4/pod/func/defined.html
###
      $template =~ 
        s/(\$\w+(?:::)?\w*)/"defined $1 ? $1 : ''"/gee;
      return $template;
    };  

## h3. Skipping page generation
##
## Now begins the bulk of the work, which we skip entirely if some plugin
## has told us to skip it.
##
  unless (defined($skip) and $skip) {

    # Plugins: Interpolate
    # Allow for the first encountered plugin::interpolate subroutine to 
    # override the default built-in interpolate subroutine
##
## h3. For people learning Perl: Overriding the default interpolate subroutine
##
## For more information on how this code works see the previous notes for
## line 161 concerning overriding the default template subroutine.
##
    my $tmp; foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('interpolate') and defined($tmp = $plugin->interpolate()) and $interpolate = $tmp and last; }
        
    # Head
##
## h3. Obtaining the template for the top of the generated page
##
## We dereference <code>$template</code> to invoke the template subroutine
## being used (either the default subroutine or one supplied by a plugin) and
## ask it to return the template used for the top of the page ('head'), for
## the specific flavour.
##
## (For the 'html' flavour this template would typically include the DOCTYPE,
## &lt;html&gt; tag, &lt;head&gt; section, and the
## beginning of the &lt;body&gt; section, including the blog title.)
##
## As noted previously, the default template subroutine will start looking
## for template files (e.g., <code>head.html</code> for the 'html' flavour) in
## the directory <code>$currentdir</code> (a relative pathname relative to
## the Blosxom data directory) and will continue looking in the parent
## directories of <code>$currentdir</code>, up to and including the Blosxom
## data directory itself. (If <code>$currentdir</code> is the empty string ''
## then the search will start and end in the Blosxom data directory.) If no
## template files are found then the default template subroutine will return
## the appropriate template previously read from the data section of
## <code>blosxom.cgi</code>.
##
    my $head = (&$template($currentdir,'head',$flavour));
  
    # Plugins: Head
##
## h3. Calling the plugin head subroutines
##
## We loop over the plugins and call the head subroutine for any plugins
## that have defined one, passing the subroutine the path for which
## which we are generating a page, as well as a reference to
## <code>$head</code> so that the subroutine can modify it in place.
##
### h3. For people learning Perl: The package name argument
###
### For more information on how this code works see the notes for line 225
### concerning calling the plugin filter subroutines.
###
### Note that since we are actually invoking <code>head</code> as a method
### the head subroutine will be passed the package name as its added first
### argument. The subroutine can simply ignore this.
###
    foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('head') and $entries = $plugin->head($currentdir, \$head) }
  
## h3. Interpolate Perl variables in the head section
##
## Now that all plugins have had a chance to modify the contents of
## <code>$head</code>, interpolate any variable references in the contents of
## <code>$head</code> and then append the contents of<code>$head</code> to the
## output being generated for the page.
##
    $head = &$interpolate($head);
  
    $output .= $head;
    
    # Stories
    my $curdate = '';
##
## h3. Keeping track of the number of entries per page
##
## Recall that <code>$num_entries</code> is the default number of entries
## to show on a page.
##
    my $ne = $num_entries;

## h3. Checking for individual entry pages
##
## We check to see if <code>$currentdir</code> actually refers to an
## individual entry as opposed to an index page.
##
### h3. For people learning Perl: Identifying an individual entry reference
###
### In the regular expression we attempt to look for patterns of the form
### <code>.../foo.bar</code> where the final component of the path has a file
### extension of some sort. If we find such a match then <code>$1</code> will
### be everything up to (but not including) the final '/', <code>$2</code>
### will be the basename of the final component, and <code>$3</code> will be
### the file extension. If <code>$2</code> is not 'index' then we assume this
### is a reference to an individual entry (e.g., <code>a/b/foo.html</code>).
###
    if ( $currentdir =~ /(.*?)([^\/]+)\.(.+)$/ and $2 ne 'index' ) {
##
## h3. Handling individual entries, part 1
##
## For an individual entry we reassign <code>$currentdir</code> to have the
## standard Blosxom file extension instead of whatever file extension it
## happened to have had. This has the effect of converting, e.g.,
## <code>a/b/foo.html</code> to <code>a/b/foo.txt</code>.
##
## This is necessary because we need to find the actual entry file from which
## to generate the output for whatever flavour was associated with the original
## request for the entry.
##
      $currentdir = "$1$2.$file_extension";
##
## h3. Handling individual entries, part 2
##
## If we are generating a page for an individual entry then we do not need to
## worry about all the other entries. Thus we modify <code>%f</code> (our
## local copy of <code>%files</code>) to be a new hash with a single element;
## we take the key and value for the sole element of <code>%f</code> from
## the element in <code>%files</code> for this entry.
##
## (This is assuming that we did in fact find an entry file corresponding to
## the entry being requested, as evidenced by there being an associated
## element in <code>%files</code>. What happens if we have a request for an
## individual entry, e.g., <code>a/b/foo.html</code> and there is no entry
## file <code>a/b/foo.txt</code>? In that case <code>%f</code> will retain its
## prior value as a copy of <code>%files</code>. We will then proceed
## to iterate over the elements of <code>%f</code> in the <code>foreach</code>
## loop from lines 332 to 392, but the test on line 338 will always fail,
## i.e., no element will ever be matched. The result will be a page with
## a 'head' and 'foot' section but no content in between.)
##
      $files{"$datadir/$1$2.$file_extension"} and %f = ( "$datadir/$1$2.$file_extension" => $files{"$datadir/$1$2.$file_extension"} );
    } 
    else { 
##
## h3. Handling index pages
##
## If <code>$currentdir</code> does not correspond to an individual entry
## then we remove the final path component if it is of the form
## <code>index.foo</code>. It should now have the form of a pure
## directory reference, e.g., <code>a/b/index.html</code> gets changed to
## <code>a/b/</code> and <code>2004/05/index.rss</code> gets changed to
## <code>2004/05/</code>.
##
      $currentdir =~ s!/index\..+$!!;
    }

    # Define a default sort subroutine
##
## h3. For people learning Perl: Sorting entries in chronological order
##
## We define an anonymous subroutine to do sorting of entries, and store
## a reference to it in <code>$sort</code>.
##
## The sort subroutine is passed a reference to a hash assumed to be of
## the same form as <code>%files</code> (hence the name
## <code>$files_ref</code> for the argument).
##
## We get a list of all keys in the hash referenced by
## <code>$files_ref</code>, and then sort that list by comparing the values
## corresponding to each key, returning the sorted list.
##
## In the <code>%files</code> hash (and hashes modelled on it) the keys are
## (absolute) pathnames for files and the values are the "last modified"
## times for those files, so this returns a list of file pathnames in
## chronological order based on when the files were last modified.
##
    my $sort = sub {
      my($files_ref) = @_;
      return sort { $files_ref->{$b} <=> $files_ref->{$a} } keys %$files_ref;
    };
  
    # Plugins: Sort
    # Allow for the first encountered plugin::sort subroutine to override the
    # default built-in sort subroutine
##
## h3. For people learning Perl: Overriding the default sort subroutine
##
## For more information on how this code works see the previous notes for
## line 161 concerning overriding the default template subroutine.
##
    my $tmp; foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('sort') and defined($tmp = $plugin->sort()) and $sort = $tmp and last; }
  
##
## h3. Iterating over all entries of interest
##
## We iterate over the sorted list of entry files (which may contain just one
## entry file if we are generating a page for an individual entry) and the
## list of other files. The files are sorted by file modification time if
## we're using the default sort subroutine, or possibly by some other criteria
## if a plugin has defined a different sort subroutine.
##
## Note that although the code passes references to both the hashes
## <code>%f</code> (the <code>generate</code> subroutine's local copy of
## <code>%files</code>) and <code>%others</code> as arguments to the sort
## subroutine, in the default version of the sort subroutine the second
## argument (<code>\%others</code>) is ignored.
##
    foreach my $path_file ( &$sort(\%f, \%others) ) {
##
## h3. No more entries for this page
##
## We end the loop if we have exceeded the maximum number of entries per
## page and we are not requesting entries for a specific date. On the other
## hand, if we are requesting entries for a specific date (i.e., the
## <code>$date</code> argument contains at least a year value, e.g.,
## <code>/2004//</code>) then we display all entries regardless of the value
## of the <code>$num_entries</code> configuration variable.
##
## <em>[Note: Although the Blosxom documentation mentions the use of
## <code>$num_entries</code> only in connection with a weblog's home page,
## it is also used to limit the number of entries displayed on category
## pages.]</em>
##
## For more information see the following URL:
##
##   http://www.blosxom.com/documentation/users/configure/
##
### h3. For people learning Perl: The case of the two <code>$date</code>
### variables
###
### The check here on line 333 and the statement on line 351 use the
### value of the <code>$date</code> argument passed to the
### <code>generate</code> subroutine, i.e., the <code>$date</code> variable
### declared on line 274 using <code>my</code>.
###
### This variable is <em>not</em> the same as the <code>$date</code> variable
### declared on line 357 and referenced on lines 360 through 364, even though
### all the references to <code>$date</code> from line 333 to line 364 appear
### within the same <code>foreach</code> loop. For more information see the
### notes for line 357.
###
      last if $ne <= 0 && $date !~ /\d/;
##
## h3. The global variables <code>$path</code> and <code>$fn</code>
##
## <em>[Note: Presumably <code>$path</code> and <code>$fn</code> are
## declared as global variables because they are referenced in the default
## templates (in particular, the story templates) and thus will need to
## be visible to the <code>interpolate</code> subroutine; this would not be
## the case if the variables were declared with <code>my</code> as being of
## lexical scope.]</em>
##
      use vars qw/ $path $fn /;
##
## h3. Parsing the directory path and basename for an entry file
##
## The value of the loop variable <code>$path_file</code> is an absolute
## pathname as used in <code>%f</code> (<code>%files</code>) and
## <code>%others</code>. We extract from that pathname the directory path
## relative to the data directory (<code>$path</code>) and the filename minus
## the file extension (<code>$fn</code>).
##
## Note that the directory path may be empty if the file is in the data
## directory itself (e.g., <code>$datadir/foo.txt</code>). That accounts for
## the use of the regular expression <code>(?:(.*)/)?</code> when matching
## the directory path.
##
      ($path,$fn) = $path_file =~ m!^$datadir/(?:(.*)/)?(.*)\.$file_extension!;
  
      # Only stories in the right hierarchy
##
## h3. Determining which entries to process
##
## We want to generate output only for entries whose files are in the
## current directory (whose value is in <code>$currentdir</code> as a
## pathname relative to the Blosxom data directory) or in
## subdirectories underneath the current directory. So, for example, if the
## current directory is <code>a/b</code> then the entry files
## <code>a/b/foo.txt</code> or <code>a/b/c/bar.txt</code> should be
## processed, but the entry file <code>a/baz.txt</code> should not. In the
## latter case <code>$path</code> will be <code>a</code>, which does not
## contain <code>a/b</code> (<code>$currentdir</code>) at the beginning,
## and hence the test will fail.
##
## We also have to take into account the possibility that the value of
## <code>$currentdir</code> represents an individual entry file and not a
## directory. In that case we check to verify that <code>$path_file</code>
## (the full absolute pathname of the file being processed) matches the
## absolute pathname <code>$datadir/$currentdir</code>.
##
## If both of these tests fail (the current file is not in the right
## hierarchy, nor does it match the individual entry we want) then we skip
## to processing the next item.
##
      $path =~ /^$currentdir/ or $path_file eq "$datadir/$currentdir" or next;
  
      # Prepend a slash for use in templates only if a path exists
##
## h3. For people learning Perl: The <code>&&=</code> operator
##
## "If a path exists" here means "if <code>$path</code> is non-empty". As
## noted above <code>$path</code> will be empty if the file in question is
## in the data directory itself.
##
## The <code>&&=</code> operator works similarly to the <code>||=</code>
## operator discussed in the notes for line 86: <code>$a &&= $b</code> is
## equivalent to <code>$a = $a && $b</code>, i.e., if the value of
## <code>$a</code> is true (defined and non-empty) then assign the value of
## <code>$b</code> to <code>$a</code>. So in this case if <code>$path</code>
## is non-empty then we assign it the value <code>"/$path"</code>, the effect
## of which is to prepend a '/' to the original value of <code>$path</code>.
##
## There are a number of other ways to express this; for example,
##
##   $path and $path = "/$path";
##
## would have worked as well, as would
##
##   $path and $path = '/' . $path;
##
## However the syntax chosen is the most economical, if not necessarily the
## most understandable to Perl newbies.
##
## For more information see the following URLs:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#C-style-Logical-And
##   http://www.perldoc.com/perl5.8.4/pod/perlop.html#Assignment-Operators
##
      $path &&= "/$path";

      # Date fiddling for by-{year,month,day} archive views
##
## h3. Parsing the entry file's modification time.
##
## In the next series of lines we call the <code>nice_date</code> subroutine
## to extract individual year, month, date, etc., values for the entry file's
## modification time and store them in global variables.
##
## <em>[Note: Presumably we use global variables here so that plugins can
## have access to the date information without having to reparse the files'
## modification time values.]</em>
##
## The <code>nice_date</code> subroutine doesn't return the hours and minutes
## as individual values, so we split those out of <code>$ti</code> using ':'
## as the separator.
##
## Finally, the <code>nice_date</code> subroutine returns a 24-hour time
## value, so we convert that to a 12-hour value (with am/pm indicator) for
## convenience. We also remove any zero on the left of the hour (e.g., change
## '02' to '2') and adjust "zero hour" values to the normal am/pm notation
## where hour values range from 1 to 12..
##
      use vars qw/ $dw $mo $mo_num $da $ti $yr $hr $min $hr12 $ampm /;
      ($dw,$mo,$mo_num,$da,$ti,$yr) = nice_date($files{"$path_file"});
      ($hr,$min) = split /:/, $ti;
      ($hr12, $ampm) = $hr >= 12 ? ($hr - 12,'pm') : ($hr, 'am'); 
      $hr12 =~ s/^0//; $hr12 == 0 and $hr12 = 12;
  
      # Only stories from the right date
##
## h3. Determining the date(s) for which we want to display entries
##
## <code>$date</code> will either be "empty" ('//')  or will be a full or
## partial date of the form yyyy/mm/dd, e.g., <code>2004/05/22</code>,
## <code>2004/05/</code>, or <code>2004//</code>. We split this up (using '/'
## as the separator) to obtain individual year, month, day values (some of
## which may end up being empty for a given value of <code>$date</code>).
##
      my($path_info_yr,$path_info_mo_num, $path_info_da) = split /\//, $date;
##
## h3. Checking for entries for the year we want
##
## If we are generating output for a particular year
## (i.e., <code>$path_info_yr</code> has a non-empty value) then we skip to
## processing the next item if the year in which the entry file being
## processed was last modified (<code>$yr</code>) is not the same as the
## year we want (<code>$path_info_yr</code>).
##
## We exit the loop entirely if the file was last modified in a year earlier
## than the year from the URL.
##
## <em>[Note: How would this second check ever succeed, given
## the previous check? We would get to the second check only if
## <code>$path_info_yr</code> were empty or undefined, or if
## <code>$yr</code> were equal to <code>$path_info_yr</code>. So it would
## seem that the second check is guaranteed to always fail.]</em>
## 
      next if $path_info_yr && $yr != $path_info_yr; last if $path_info_yr && $yr < $path_info_yr; 
##
## h3. Checking for entries for the month we want
##
## If we are generating output for a particular month (i.e.,
## <code>$path_info_mo_num</code> has a non-empty value) then we skip to
## processing the next item if the month in which the file being processed
## was last modified is not the same as the month we want.
##
## Note that <code>$mo</code> as returned from <code>nice_date</code> is
## actually a three-letter month abbreviation, while
## <code>$path_info_mo_num</code> is a two-digit month number; hence we have
## to convert <code>$path_info_mo_num</code> before comparing it to
## <code>$mo</code>.
##
## <em>[Note: Why not just use <code>$mo_num</code> as returned by
## <code>nice_date</code>, instead of <code>$mo</code>?]</em>
##
      next if $path_info_mo_num && $mo ne $num2month[$path_info_mo_num];
##
## h3. Checking for entries for the day we want
##
## If we are generating output for a particular day of the month (i.e.,
## <code>$path_info_da</code> has a non-empty value) then we skip to
## processing the next item if the day on which the file being processed was
## last modified (<code>$da</code>) is not the same as the day we want
## (<code>$path_info_da</code>).
##
## We exit the loop entirely if the file was last modified on a day earlier
## than the day from the URL.
##
## <em>[Note: How would this second check ever succeed, given
## the previous check? We would get to the second check only if
## <code>$path_info_da</code> were empty or undefined, or if
## <code>$da</code> were equal to <code>$path_info_da</code>. So it would
## seem that the second check is guaranteed to always fail.]</em>
##
      next if $path_info_da && $da != $path_info_da; last if $path_info_da && $da < $path_info_da; 
  
      # Date 
##
## h3. Obtaining the date template
##
## We invoke the template subroutine being used (either the default subroutine
## or one supplied by a plugin) to return the template used for date formats
## for the specific flavour. (For example, for the 'hmtl' flavour the date
## template will be
##
##   <h3>$dw, $da $mo $yr</h3>\n
##
## if the default template subroutine is used and no <code>date.html</code>
## file is found.)
##
### h3. For people learning Perl: The new <code>$date</code> variable
###
### Previous to this line references to <code>$date</code> referred to the
### <code>$date</code> variable declared on line 274 and used to store the date
### argument passed to the <code>generate</code> subroutine. By using
### <code>my</code> here to declare a new private variable <code>$date</code>,
### we cause the previous <code>$date</code> variable to be hidden, i.e., its
### value is no longer accessible to us.
###
### The scope of lexical variables declared with <code>my</code> is limited to
### the code block in which they were declared; in this case the enclosing code
### block is the <code>foreach</code> loop used to loop over entries, which
### extends from line 332 to line 392. However the scope of this new
### <code>$date</code> variable does not extend over the entire
### <code>foreach</code> loop; rather it extends only from the point at which
### it was declared on line 357 to the end of the loop at line 392.
### References to <code>$date</code> in the <code>foreach</code> loop prior to
### line 357 refer to the original <code>$date</code> argument declared on
### line 274.
###
      my $date = (&$template($path,'date',$flavour));
      
      # Plugins: Date
##
## h3. Calling the plugin date subroutines
##
## We let each and every plugin have a chance to modify the contents of the
## date template if desired (e.g., by rearranging the order in which the
## date-related variables appear in the template). We pass in a number of
## date-related variables that the plugin subroutine(s) can use in making
## decisions about what to change.
##
      foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('date') and $entries = $plugin->date($currentdir, \$date, $files{$path_file}, $dw,$mo,$mo_num,$da,$ti,$yr) }
  
## h3. Filling in the date
##
## We interpolate any variable references in <code>$date</code>; among other
## things this will replace date-related variables such as <code>$yr</code>,
## <code>$my</code>, and <code>$da</code> with the actual date values.
##
      $date = &$interpolate($date);
  
## h3. Output the date section for the first entry on that date
##
## If we have a number of entries for the same date then we want to output
## the date section only once. If we haven't previously output a date
## section for this page (<code>$curdate</code> is empty or otherwise not
## equal to the date section we're now processing) then we set
## <code>$curdate</code> to the current date string and append the date
## section to the page output.
##
      $curdate ne $date and $curdate = $date and $output .= $date;
      
## h3. The global variables <code>$title</code>,
## <code>$body</code>, and <code>$raw</code>
##
## <em>[Note: Here we declare <code>$title</code>, <code>$body</code>, and
## <code>$raw</code> as global variables. Presumably this is because these
## variables (or at least <code>$title</code> and <code>$body</code>) are
## referenced in the default story template and hence have to be visible in the
## <code>interpolate</code> subroutine; if the variables were of lexical
## scope (i.e., using <code>my</code>) then they would not be visible to be
## interpolated.]</em>
##
      use vars qw/ $title $body $raw /;
##
## h3. For people learning Perl: Reading an entry file
##
## If the file identified by <code>$path_file</code> exists then we attempt
## to open it to read it. If this is successful we read the first line of
## the file and assign it to <code>$title</code>; the <code>chomp</code>
## function removes any trailing newline in <code>$title</code> after it gets
## assigned. We then read the rest of the file and assign the lines to
## <code>$body</code>, removing any trailing newline. (Within
## <code>$body</code> the multiple lines from the file are separated by
## newlines.)
##
## The <code>join</code> function is used to cause <code><$fh></code>
## to be evaluated in list context instead of scalar context, so that it
## will read the entire file (or more precisely, what's left of the file
## after reading the first line) instead of just reading a single line.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/chomp.html
##
      if (-f "$path_file" && $fh->open("< $path_file")) {
        chomp($title = <$fh>);
        chomp($body = join '', <$fh>);
        $fh->close;
##
## h3. The raw contents of the entry file
##
## Note that given the way that $<code>title</code> and <code>$body</code>
## were assigned, <code>$raw</code> essentially recovers the raw contents of
## the entry file into a single multi-line string, minus any final newline
## in the file.
##
## <em>[Note: The global variable <code>$raw</code> is not otherwise
## used in the main Blosxom code, and is not included in any of the default
## templates. Perhaps it's defined for the benefit of any plugins that
## might want to use it?]</em>
##
        $raw = "$title\n$body";
      }
##
## h3. Obtaining the story template
##
## We invoke the template subroutine being used (either the default subroutine
## or one supplied by a plugin) to return the template used for the story
## section for the specific flavour.
##
      my $story = (&$template($path,'story',$flavour));
  
      # Plugins: Story
##
## h3. Calling the plugin story subroutines
##
## We let each and every plugin have a chance to modify the story section if
## desired. Note that the plugins' story subroutines have access both to
## the story template (<code>$story</code>) and to the story contents
## (<code>$title</code> and <code>$body</code>).
## 
##
      foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('story') and $entries = $plugin->story($path, $fn, \$story, \$title, \$body) }
      
##
## h3. Escaping characters special to XML
##
## If the content_type is an XML-based content type (e.g., 'text/xml')
## then we need to modify the generated output so that characters like '<'
## are properly escaped by replacing them with XML character entities. 
##
## <em>[Note: The escaping is not done if the content_type is 'text/html',
## so HTML markup in the story (i.e., for the 'html' flavour) is not affected.
## However, if your blog pages were in XHTML and you had specified the content
## type to be 'application/xhtml+xml' (as recommended by
## "Ian Hickson":http://www.hixie.ch/advocacy/xhtml and the
## "W3C":http://www.w3.org/TR/xhtml-media-types/) then your XHTML markup would
## presumably be mangled. (Of course, almost everybody with "XHTML" pages is
## actually serving them as 'text/html' because MSIE doesn't support the
## 'application/xhtml+xml' content type.)]</em>
##
##
      if ($content_type =~ m{\Wxml$}) {
        # Escape <, >, and &, and to produce valid RSS
##
## h3. For people learning Perl: The <code>%escape</code> hash
##
## The <code>%escape</code> hash maps problematic characters to their
## respective character entities.
##
        my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');  
##
## h3. For people learning Perl: The <code>$escape_re</code> regular
## expression
##
## The <code>$escape_re</code> variable holds a string value that can be
## used in a regular expression to look for alternate strings to match.
## In particular, the value of <code>$escape_re</code> will be
## <code><|>|&|"</code> given the definition of <code>%escape</code>.
##
## Note that the expression
##
##   join '|' => keys %escape
##
## as used in this context is equivalent to
##
##   join '|', keys %escape
##
## The latter is the form typically used in the Blosxom code.
##
## <em>[Note: I wonder if there was a particular reason for using
## <code>=></code> here?]</em>
##
        my $escape_re  = join '|' => keys %escape;
##
## h3. Escaping the title and body
##
## We modify both <code>$title</code> and <code>$body</code> to replace the
## problematic characters with the equivalent character entities. Note that
## this takes advantage of the Perl feature where the search string and
## replacement string undergo interpolation to replace references to Perl
## variables (<code>$escape_re</code> and <code>$escape{...}</code> in this
## case) with the values of those variables.
##
## Note that this is different from the approach used by the
## <code>interpolate</code> subroutine. There we did not know what the
## actual variable names were going to be, so we had to "eval" the
## replacement string using the <code>ee</code> option to the pattern match.
## Here we know what the variable names are at compile time, so we don't need
## the <code>ee</code> option, just the normal variable interpolation that
## Perl does as a matter of course.
##
## <em>[Note: I need to double-check the ordering of variable interpolation.
## In order for the replacement string to work properly the value of
## <code>$1</code> has to be known prior to interpolation taking place.]</em>
##
        $title =~ s/($escape_re)/$escape{$1}/g;
        $body =~ s/($escape_re)/$escape{$1}/g;
      }
  
## h3. Interpolating variables in the story and generating story output
##
## We interpolate any variables present in the contents of the story section,
## and then append the resulting content to the output string being built.
##
      $story = &$interpolate($story);
    
      $output .= $story;
##
## h3. Finished processing an entry
##
## We're now done with the file for this entry, and so can close its
## FileHandle.
##
## Having added another entry to the output, we decrement <code>$ne</code>
## to keep track of how many more entries we can add before hitting the
## specified maximum entries per page. (We don't check the number of entries
## when generating date-based pages, but we decrement <code>$ne</code> anyway.)
##
      $fh->close;
  
      $ne--;
    }
  
    # Foot
##
## h3. Obtaining the template for the foot section
##
## We invoke the template subroutine being used (either the default subroutine
## or one supplied by a plugin) to return the template used for the foot
## section for the specified flavour. For example, for the 'html' flavour
## this would typically include the &lt;/body&gt; and &lt;/html&gt; closing
## tags.
##
    my $foot = (&$template($currentdir,'foot',$flavour));
  
    # Plugins: Foot
##
## h3. Calling the plugin foot subroutines
##
## We let each and every plugin have a chance to modify the contents of the
## foot section if desired.
##
    foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('foot') and $entries = $plugin->foot($currentdir, \$foot) }
  
## h3. Interpolating variables in the foot section and generating output
##
## We interpolate any variables present in the contents of the foot section,
## and then append the resulting content to the output string being built.
##
    $foot = &$interpolate($foot);
    $output .= $foot;

    # Plugins: Last
##
## h3. Calling the plugin last subroutines
##
## We let each and every plugin have a chance to do any final processing for
## this page. Note that the last subroutine is not passed arguments, but it
## has access to Blosxom global variables, including <code>$output</code>.
##
    foreach my $plugin ( @plugins ) { $plugins{$plugin} > 0 and $plugin->can('last') and $entries = $plugin->last() }

  } # End skip

  # Finally, add the header, if any and running dynamically
##
## h3. Adding the HTTP header
##
## Note that the HTTP header (if any) goes at the front of the generated
## output, and is needed only for dynamic page generation. The variable
## <code>$header</code> contains the content type value as well as the values
## for any other HTTP headers added by plugins; see the notes to line 264.
##
  $static_or_dynamic eq 'dynamic' and $header and $output = header($header) . $output;
  
## h3. For people learning Perl: The <code>generate</code> subroutine return
## value
##
## We return the <code>$output</code> string as the  value of the
## <code>generate</code> subroutine. (The <code>return</code> keyword is
## optional in Perl.)
##
  $output;
}


## h3. The <code>nice_date</code> subroutine
##
## The subroutine <code>nice_date</code> converts OS-provided time values
## (expressed as the number of seconds since some fixed date) into year,
## month, day, etc., values that we can use for printing date/times and
## creating date-based URLs.
##
sub nice_date {
##
## h3. For people learning Perl: The <code>$unixtime</code> argument
##
## The subroutine argument is called <code>$unixtime</code> but it's not
## specific to Unix; it's the time value returned by the Perl function
## <code>time</code> and similar routines. The value is always a number in
## seconds, but its interpretation can differ slightly from OS to OS (for
## example, between Unix and Mac OS).
##
  my($unixtime) = @_;
  
##
## h3. For people learning Perl: The <code>ctime</code> function
##
## We don't use the value of <code>$unixtime</code> directly, we just pass
## it to the <code>Time::localtime::ctime</code> routine to return a
## human-readable string representing the date/time, e.g., "Sat May 29
## 06:58:29 2004".
##
## For more information see the following URLs:
##
##   http://search.cpan.org/~nwclark/perl-5.8.4/lib/Time/localtime.pm
##   http://www.perldoc.com/perl5.8.4/pod/func/localtime.html
##
  my $c_time = ctime($unixtime);
##
## h3. For people learning Perl: Interpreting the time value
##
## The value returned by <code>ctime</code> has the format "Dow Mon dd
## hh:mm:ss yyyy" where "Dow" is the three letter abbreviation for the day
## of the week (e.g., "Sun", "Mon", etc.) and "Mon" is the three letter
## abbreviation for the month (e.g., "Jan, "Feb", etc.). The other fields
## have the usual numeric values for day of the month, hours, minutes, and
## seconds, and the (four-digit) year; however note that the day of the
## month may be expressed as either one or two digits.
##
## We use a pattern to match the <code>$c_time</code> string, capture the
## values of interest, and assign them to individual variables. Note that the
## regular expression <code>\w{3}</code> matches exactly three alphanumeric
## characters (actually, alphanumeric plus underscore), while
## <code>\d{1,2}</code> matches either one or two digits (no more, no less),
## to account for the way that <code>ctime</code> returns the day of the month.
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perlre.html#Regular-Expressions
##
  my($dw,$mo,$da,$ti,$yr) = ( $c_time =~ /(\w{3}) +(\w{3}) +(\d{1,2}) +(\d{2}:\d{2}):\d{2} +(\d{4})$/ );
##
## h3. For people learning Perl: The <code>sprintf</code> function
##
## Since the day of the month may be returned as either a one or two digit
## value (e.g., "1" or "10") we use the <code>sprintf</code> function (like
## the corresponding function in C) to modify the value of <code>$da</code>
## to be two digits, zero-padded on the left (e.g., "01" instead of "1").
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/func/sprintf.html
##
  $da = sprintf("%02d", $da);
##
## h3. Converting month name to month number
##
## Since we also want the month number as well as the name, we use the
## month name as a key to look up the month number in the
## <code>%month2num</code> hash defined above.
##
  my $mo_num = $month2num{$mo};
  
  return ($dw,$mo,$mo_num,$da,$ti,$yr);
}


## h3. For people learning Perl: <code>__DATA__</code> and
## <code>__END__</code>
##
## The <code>__DATA__</code> line marks the end of the Blosxom code and the
## beginning of the flavour data. The <code>__END__</code> line marks the
## end of the program as a whole. Anything after that is considered a
## comment; this area is used by some Perl developers to include a change
## history for the program, program documentation, license terms, and/or
## other useful information..
##
## For more information see the following URL:
##
##   http://www.perldoc.com/perl5.8.4/pod/perldata.html
##
# Default HTML and RSS template bits
__DATA__
html content_type text/html
html head <html><head><link rel="alternate" type="type="application/rss+xml" title="RSS" href="$url/index.rss" /><title>$blog_title $path_info_da $path_info_mo $path_info_yr</title></head><body><center><font size="+3">$blog_title</font><br />$path_info_da $path_info_mo $path_info_yr</center><p />
html story <p><a name="$fn"><b>$title</b></a><br />$body<br /><br />posted at: $ti | path: <a href="$url$path">$path</a> | <a href="$url/$yr/$mo_num/$da#$fn">permanent link to this entry</a></p>\n
html date <h3>$dw, $da $mo $yr</h3>\n
html foot <p /><center><a href="http://www.blosxom.com/"><img src="http://www.blosxom.com/images/pb_blosxom.gif" border="0" /></a></body></html>
rss content_type text/xml
rss head <?xml version="1.0"?>\n<!-- name="generator" content="blosxom/$version" -->\n<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">\n\n<rss version="0.91">\n  <channel>\n    <title>$blog_title $path_info_da $path_info_mo $path_info_yr</title>\n    <link>$url</link>\n    <description>$blog_description</description>\n    <language>$blog_language</language>\n
rss story   <item>\n    <title>$title</title>\n    <link>$url/$yr/$mo_num/$da#$fn</link>\n    <description>$body</description>\n  </item>\n
rss date \n
rss foot   </channel>\n</rss>
error content_type text/html
error head <html><body><p><font color="red">Error: I'm afraid this is the first I've heard of a "$flavour" flavoured Blosxom.  Try dropping the "/+$flavour" bit from the end of the URL.</font>\n\n
error story <p><b>$title</b><br />$body <a href="$url/$yr/$mo_num/$da#fn.$default_flavour">#</a></p>\n
error date <h3>$dw, $da $mo $yr</h3>\n
error foot </body></html>
__END__
