#!/usr/bin/perl -w # Blosxom # Author: Rael Dornfest . Auto-formatting hacked in by Luke Francl, inspired by Scoop # Version: 1+4i # Home/Docs/Licensing: http://www.oreillynet.com/~rael/lang/perl/blosxom/ # --- Configurable variables ----- # What's my blog's title? my $blog_title = 'Just Looking'; # What's my blog's description (for outgoing RSS feed)? my $blog_description = 'Luke Francl\'s Weblog'; # What's my blog's primary language (for outgoing RSS feed)? my $blog_language = 'en'; # Where are my blog entries kept? my $datadir = "/www/data/justlooking.recursion.org/weblog"; # How many entries should I show on the home page? my $num_entries = 15; # should I use autoformatting? my $auto_format = 1; # -------------------------------- use strict; use DirHandle; use FileHandle; use File::stat; use Time::localtime; use CGI::Carp; use CGI qw/:standard :netscape/; # Take a gander at HTTP's PATH_INFO for optional blog name, archive yr/mo/day my $url = url(); my @pi = split m{/}, path_info(); shift @pi; my $content_type = 'text/' . ($pi[-1] && $pi[-1] =~ /xml/ ? pop @pi : 'html'); my $pi_bl = $pi[0] && $pi[0] =~ /^([a-zA-Z]\w*)/ ? shift @pi : undef; # Check the existence and readability of a specified sub-blog $pi_bl and -d "$datadir/$pi_bl" and -r "$datadir/$pi_bl" and $datadir .= "/$pi_bl", $url .= "/$pi_bl", $blog_title .= ": $pi_bl"; my($pi_yr,$pi_mo,$pi_da,$id) = @pi; my $dh = new DirHandle($datadir); my $fh = new FileHandle; # Bring in the templates my %template = (); while () { last if /^(__END__)?$/; my($ct, $comp, $txt) = /^(\S+)\s(\S+)\s(.*)$/; $txt =~ s/\\n/\n/mg; $template{$ct}{$comp} = $txt; } # Header print header($content_type); my $head = join '', $content_type eq 'text/html' && $fh->open("< $datadir/head.html") ? <$fh> : $template{$content_type}{'head'}; $head =~ s/(\$\w+)/$1/gee; print $head; # Send in the blogs my $curdate = ''; foreach ( sort { return -M "$datadir/$a" <=> -M "$datadir/$b"; } grep /.txt$/, $dh->read ) { last if $num_entries-- <= 0 && !$pi_yr; my($fn) = ($_ =~ /^(.*)\.txt$/); # Date fiddling for by-{year,month,day} archive views # Get the timezone offset for pubDate my $epoch_secs = stat("$datadir/$fn.txt")->mtime; my $mtime = ctime($epoch_secs); my($dw,$mo,$da,$ti,$yr) = ( $mtime =~ /(\w{3}) +(\w{3}) +(\d{1,2}) +(\d{2}:\d{2}):\d{2} +(\d{4})$/ ); my $time = localtime($epoch_secs); my $timezone = "CST"; if ( $time->isdst ) { $timezone = "CDT"; } next if $pi_yr && $yr != $pi_yr; last if $pi_yr && $yr < $pi_yr; next if $pi_mo && $mo ne ucfirst(lc $pi_mo); next if $pi_da && $da != $pi_da; last if $pi_da && $da < $pi_da; $content_type eq 'text/html' && $curdate ne "$dw, $da $mo $yr" && print span({-class=>'blosxomDate'}, $curdate = "$dw, $da $mo $yr"); # Entry if (-T "$datadir/$fn.txt" && $fh->open("< $datadir/$fn.txt")) { chomp(my $title = <$fh>); if ($auto_format) { $title = auto_format($title); } chomp(my $body = join '', <$fh>); if ($auto_format) { $body = &auto_format($body); } if ($content_type eq 'text/xml') { # Escape <, >, and &, and to produce valid RSS my %escape = ('<'=>'<', '>'=>'>', '&'=>'&', '"'=>'"'); my $escape_re = join '|' => keys %escape; $title =~ s/($escape_re)/$escape{$1}/g; $body =~ s/($escape_re)/$escape{$1}/g; } $fh->close; my $story = ($content_type eq 'text/html' && $fh->open("< $datadir/story.html")) ? join '', <$fh> : $template{$content_type}{'story'}; $story =~ s/(\$\w+)/$1/gee; print $story; $fh->close; } } # Foot print $content_type eq 'text/html' && $fh->open("< $datadir/foot.html") ? <$fh> : $template{$content_type}{'foot'}; # Auto formats your weblog posts. Mostly leaves HTML alone, though # auto paragraphing is a bit over-zealous and may screw up your HTML. sub auto_format { my $weblog_post = $_[0]; $weblog_post = &auto_blockquote($weblog_post); $weblog_post = &auto_ul($weblog_post); $weblog_post = &auto_ol($weblog_post); $weblog_post = &auto_link($weblog_post); $weblog_post = &auto_bold_italics($weblog_post); $weblog_post = &auto_paragraph($weblog_post); return $weblog_post; } # turns email style _italics_ and *bold* into HTML. sub auto_bold_italics { my $weblog_post = $_[0]; # matches any * which does not preceded by letters or # numbers followed by one non-whitespace char or # one non-whitespace char followed by any number of # chars, followed by one non-whitespace char followed by # a * followed by non letters or numbers or the end of the line $weblog_post =~ s#(?$1#gs; $weblog_post =~ s#(?$1#gs; return $weblog_post; } # Creates links for URLs. Simply type the URL to make a link. # to title the link, use [http://url/is/here link title] sub auto_link { my $weblog_post = $_[0]; my $url_regex = '(?:http|https|ftp|nntp|news|telnet|file)://[^\s<]+'; #greedy # Grab expressions in brackets [] # and if they end in a URL, linkify them. $weblog_post =~ s#\[($url_regex)(?:\s)*?([^\[][^]]+?)\]#$2#gmsio; # make bare urls links $weblog_post =~ s#\s+($url_regex)(?=\w*|$)# $1#gmsio; return $weblog_post; } # auto_paragraph puts a paragraph tag on empty lines # it is too agreessive and puts

tags where they aren't # needed (such as before lists) sub auto_paragraph { my $weblog_post = $_[0]; $weblog_post =~ s#\n\s*\n#\n

#gs; return $weblog_post; } # Creates blockquote tags if you intent a line by two or more spaces # Doesn't work for multiple lines, each will have its own blockquote # would be nice if it saved state between lines for multi-line quotes # should probably be made to work with only one \t as well as 2 whitespace chars sub auto_blockquote { my $weblog_post = $_[0]; $weblog_post =~ s#^\s{2,}([^\S].*?)$#

$1
#mg; return $weblog_post; } # creates a bulleted list if you use two or more * in a row as # the first character on the line sub auto_ul { my $weblog_post = $_[0]; # Match series of lines (at least two) beginning in "*" $weblog_post =~ s#((?:^\*\s+.*(?:\n|$)){2,})# my $item = $1; $item =~ s!^\*!
  • !gm; "\n
      \n" . $item . "
    \n" #gme; return $weblog_post; } # creates a numbered list if you use two or more numbers followed by # a period in a row as the first thing on the line. Example: # 1. foo # 1. bar sub auto_ol { my $weblog_post = $_[0]; $weblog_post =~ s#((?:^[0-9]+\.\s+.*(?:\n|$)){2,})# my $item = $1; $item =~ s!^[0-9]+\.!
  • !gm; "\n
      \n" . $item . "
    \n" #gme; return $weblog_post; } # Default HTML and RSS template bits __DATA__ text/html head $blog_title
    $blog_title

    text/html story

    $title
    $body
    Posted at $ti link Google for '$title'

    \n text/html foot

    Powered -- for some narrow definition of powered -- by Blosxom
    text/xml head \n\n\n\n\n \n $blog_title\n $url\n $blog_description\n $blog_language\n text/xml story \n $title\n http://justlooking.recursion.org/$yr/$mo/$da#$fn\n $body\n $dw, $da $mo $yr $ti $timezone\n \n text/xml foot \n