<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl
#
# make-index - make an index.html page
#
# $Id: make-index.pl,v 1.4 2009/01/08 18:59:08 esm Exp $
#
(our $ME = $0) =~ s|.*/||;
(our $VERSION = '$Revision: 1.4 $ ') =~ tr/[0-9].//cd;

use strict;
use warnings;

use CGI qw(:standard);
use SelectSaver;
use XML::Parser;

###############################################################################
# BEGIN user-customizable section

our $Outfile = "index.html";

our @All_Categories = qw(Brunch Salad Main Dessert Miscellaneous);

# END   user-customizable section
###############################################################################

###############################################################################
# BEGIN boilerplate args checking, usage messages

END {
  use POSIX qw(_exit);
  # This is required if the code might send any output to stdout
  # E.g., even --version or --help.  So it's best to do it unconditionally.
  close STDOUT
    or (warn "$ME: closing standard output: $!\n"), _exit (1);
}

sub usage($) {
  my ($exit_code) = @_;
  my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
  if ($exit_code != 0) {
    print  $STREAM "Try `$ME -help' for more information.\n";
  } else {
    print  $STREAM &lt;&lt;EOH;
Usage: $ME [OPTIONS]

blah blah blah

OPTIONS:

  --dry-run    make no changes, but display new crontab to stdout
  --help       display this message
  --version    display program name and version
EOH
  }

  exit $exit_code;
}

# Command-line options
my $debug   = 0;
my $dry_run = 0;
my $force   = 0;
use Getopt::Long;
GetOptions( 'debug!'     =&gt; \$debug,
	    'dry-run|n!' =&gt; \$dry_run,
	    force        =&gt; \$force,
	    help         =&gt; sub { usage 0 },
	    version      =&gt; sub { print "$ME version $VERSION\n"; exit 0 },
) or usage(1);

# END   boilerplate args checking, usage messages
###############################################################################

#############
#  _navbar  #
#############
sub _navbar() {
  return &lt;&lt;"+";

&lt;!-- Navbar --&gt;
&lt;table class="navbar" width="100%" border="0" cellpadding="0" cellspacing="0"&gt;
 &lt;tr&gt;
  &lt;td align="left"&gt;&amp;nbsp;&lt;small&gt;&lt;a href="../"&gt;Ed Santiago&lt;/a&gt;
  &lt;img src="../images/arrow_navbar.gif" width=13 height=9 align="bottom" alt="-&amp;gt;"&gt;
  &lt;b&gt;Recipes&lt;/b&gt;&lt;/small&gt;
  &lt;/td&gt;
 &lt;/tr&gt;
&lt;/table&gt;
+
}

###############################################################################
# BEGIN HTML Style handler

package Recipe::Index::HTML;

my @tag_stack;

sub StartDocument {
  @tag_stack = ();
}

sub StartTag {
  my $self = shift;
  my $element = shift;

  push @tag_stack, $element;
  if ($element eq 'recipe') {
    exists $_{name}
      or die "$ME: No name\n";
    $main::name = $_{name};

    exists $_{category}
      and push @main::categories, split(/,\s*/, $_{category});
  }
}
sub EndTag {
  pop @tag_stack;
}
sub Text {
  grep($_ eq 'blurb', @tag_stack)
    and $main::blurb .= $_;
}

package main;

# END   HTML Style
###############################################################################

############################## CODE BEGINS HERE ###############################

my @files = (@ARGV ? @ARGV : glob("*.xml"));

@files
  or die "$ME: No .xml files found\n";

my $p = XML::Parser-&gt;new( Style =&gt; "Stream", Pkg =&gt; "Recipe::Index::HTML" );

# Kludge alert!  The code above modifies variables in our namespace.
our $blurb;
our $name;
our @categories;

my %recipes;
my %blurb;
my %name;
foreach my $f (@files) {
  # Reset blurb, name, categories
  $blurb = $name = "";
  @categories = ();

  # Parse the XML file.  The code above will save results in our variables.
  $p-&gt;parsefile($f);

  # Mark the results.  There really should be a better way, such as
  # having parsefile() return something.
  $blurb{$f} = $blurb;
  $name{$f} = $name;

  # No categories?  Warn.
  @categories == 0
    and warn "$ME: Uncategorized recipe '$f'\n";

  # Reverse map: push this recipe onto a by-category list.
  foreach my $cat (@categories) {
    # Skip "Hidden" recipes, like Mima's flan, which we don't want to publish.
    $cat =~ /hidden/i
      and next;

    # Allow any form of capitalization, but no mipselings.
    my @match = grep(lc $_ eq lc $cat, @All_Categories);
    if (@match == 1) {
      push @{$recipes{$match[0]}}, $f;
    } else {
      warn "$ME: Unknown category '$cat'\n";
    }
  }
}

#
# Start output.  Create a temporary output file.
#
my $tmp = "$Outfile.TMP.$$";
unlink $tmp;

open OUT, '&gt;', $tmp
  or die "$ME: Could not create $tmp: $!\n";

my $saver = SelectSaver-&gt;new(*OUT);

# HTML boilerplate start stuff
print start_html(-title  =&gt; "Ed's Recipes",
		 -author =&gt; 'esm',
		 -style  =&gt; { src =&gt; 'recipes.css' }), "\n",
       _navbar,"\n",
       h1("Ed's Recipes"),"\n",
       p,"\n";

# Section for each category.  Make it a (borderless) table with name, blurb.
foreach my $cat (@All_Categories) {
  # Empty category?  Skip it.
  exists $recipes{$cat}
    or next;

  print hr,"\n",
        h2($cat),"\n",
        p,"\n",
        "&lt;table cellpadding=4&gt;\n";

  # Each row in the table
  foreach my $f (@{$recipes{$cat}}) {
    (my $html = $f) =~ s/\.xml$/\.html/;

    print  "\n",
           " &lt;!-- $f : $name{$f} --&gt;\n",
           " &lt;tr&gt;\n",
           "  &lt;td&gt;&lt;a href=\"$html\"&gt;$name{$f}&lt;/a&gt;&lt;/td&gt;\n",
           "  &lt;td&gt;$blurb{$f}&lt;/td&gt;\n",
           " &lt;/tr&gt;\n";
  }
  print  "&lt;/table&gt;\n";
}

# Add signature line
(my $now = scalar localtime) =~ s/\s+\d+:\d+:\d+\s+/, /;
print hr,"\n",
      "Last Updated: $now\n",
      p,"\n",
      "&lt;address&gt;&lt;a href=\"../\"&gt;Ed Santiago&lt;/a&gt;&amp;nbsp;&amp;lt;&lt;a href=\"mailto:ed\@edsantiago.com\"&gt;ed\@edsantiago.com&lt;/a&gt;&amp;gt;&lt;/address&gt;\n",
      end_html,"\n";

# Move into place
chmod 0444 =&gt; $tmp;
unlink                     "$Outfile.BAK";
link           $Outfile =&gt; "$Outfile.BAK";
rename $tmp =&gt; $Outfile
  or die "$ME: Could not rename $tmp: $!\n";
</pre></body></html>