# Blosxom Plugin: blox-org
# Authors: Stu MacKenzie <http://groups.yahoo.com/group/blosxom/messages>
#        : lists() subroutine and $WORD def modified from formatter.pm (Kwiki0.18) 
#          by Brian Ingerson
# Version: v0.99 2004-10-30 (2004-10-24 0.97-11e)
# License: MIT/Public Domain
# blox home: http://www.enilnomi.net/download.html
# Documentation at the bottom of this file or type: perldoc blox

#
#  The blox plugin reads plain text entry files and generates 
#  html code for blosxom stories. By default, leaving a blank 
#  line between your entry paragraphs creates html "paragraph" 
#  tags. Optionally, blox will add html "break" tags wherever 
#  a single line ends. Optionally, a simple markup can be used 
#  to create html heads, lists, blockquotes, anchors, links, 
#  rules, images, and tags for bold, italic, underline, and code.
#
#  Of course, you're free to use html markup in your entries; 
#  blox won't change any of your existing tags.  However, in 
#  cases where you have a tag at the start or end of a block 
#  (such as "<b>" or "</a>"), a single space character must be 
#  added before or after the tag to get blox to add its open- 
#  or close-paragraph tag.
#
#  If the following configuration instructions aren't clear, 
#  read the text at the end of this file for more details on 
#  using blox, and a link to the complete documentation.
#

package blox-org;

# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
#
#  Configuration Section
#
# = = = = = = = = = = = = = = = =

  $org_base_h_level = 4;

#
# Open and Close tags --
#       The text entered between the single quote marks for $open_p_tag 
#       and $close_p_tag becomes the exact tags inserted before and after 
#       each untagged block of text in your entry files.
#
#      What are your html open- and close-paragraph tags?
#       (Normal is '<p>' and '</p>')
  $open_p_tag = '<p>';
  $close_p_tag = '</p>';
#
# Initial and final tags --
#       You can stop blox from adding a tag at the very beginning or 
#       the very end of your entries by setting these to 0 [zero].
#
#      Should blox place an open-tag at the start of the very first block?
#       0 = no; 1 = yes  (normal is 1)
  $add_initial_open_tag = 1;
#
#      Should blox place a close-tag at the end of the very last block?
#       0 = no; 1 = yes  (normal is 1)
  $add_final_close_tag = 1;
#
# = = = = = = = = = = = = = = = =
# Breaking single lines --
#      Should blox throw a break between single lines?
#       0 = no; 1 = yes  (normal is 1)
  my $break_singles = 0;
#
#      What html tag should be used for these breaks?
#       normal is '<br>'; could be '<br clear="all">', etc.
  my $break = '<br>';
#
# = = = = = = = = = = = = = = = =
# Simple markup --
#      Should blox use its simple wiki-like markup system?
#       0 = no; 1 = yes
  $markup_active = 1
        unless defined $markup_active;
#
# = = = = = = = = = = = = = = = =
# Ignoring files or directories --
#      blox will ignore any story with a single line set to 
#       '<!--noblox-->' (no quotes). You can also set files and 
#       directories to ignore by entering paths into a file named 
#       'noblox' (no quotes) located in Blosxom's plugins state 
#       directory. [If you don't plan to use a noblox file, setting 
#       to 0 (zero) will save your server a tiny bit of work.]
#
#      Should blox take the time to read a list of files to skip over?
#       0 = no; 1 = yes  (normal is 1)
  $use_noblox_file = 1;
#
#      What's the complete path to the noblox file?
#       (leave empty for automatic configuration using Blosxom's plugins state dir)
  $noblox_file_path = "";
#
# = = = = = = = = = = = = = = = =
# Cooperating with other plugins --
#      Should blox automatically ignore entries that set a value 
#       for meta-markup via the meta plugin?
#       0 = no; 1 = yes  (normal is 1)
  my $play_nice = 1;
#
# = = = = = = = = = = = = = = = =
# Advanced markup config --
#      Styled text tags:
  my $i_tag = 'i';         # might be 'em'; normal is 'i'
  my $b_tag = 'b';         # might be 'strong'; normal is 'b'
  my $u_tag = 'u';         # might be...; normal is 'u'
  my $mono_tag = 'code';   # might be 'tt' or 'kbd'; normal is 'code'
#
# XHTML 1.0?
#      Set to 1 to close <br>, <hr>, and <img> tags with " />"
#      Normal is 0
  my $use_xhtml_tags = 0;
#
# Should list items have close tags?
#      0 = no; 1 = yes  (normal is 0)
  my $close_list_item = 0;
#
# Should anchors be empty?
#      non-breaking space = 1; empty = 0  (normal is 0)
  my $anchor_text = 0;

# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

sub start {
  !$use_noblox_file and return 1;
  !$noblox_file_path and $noblox_file_path = "$blosxom::plugin_state_dir/noblox";
                                             # process noblox file: 
  open(NOBLOX, "< $noblox_file_path") or 1; my $str = join '', <NOBLOX>; close(NOBLOX);
  $str =~ s/\r\n|\r/\n/gm;
  @skips = ();
  @keeps = ();
  foreach (split /\n/, $str) {
    !$_ or /^\s*#/ and next;
    (s/^!// and push(@keeps, "$blosxom::datadir/$_")) or 
    push(@skips, "$blosxom::datadir/$_");
  }

  1;
}

sub filter {
  my ($pkg, $files_ref) = @_;
  !$use_noblox_file and return 0;

  %blox_skip_files = (); 
  foreach $skip (@skips) {                   # check skips
    foreach (keys %$files_ref) {
      /^$skip/ and $blox_skip_files{$_}=1;
    }
  }
  foreach $keep (@keeps) {                   # check keeps
    foreach (keys %blox_skip_files) {
      /^$keep/ and $blox_skip_files{$_}=0;
    }
  }

  1;
}


# word chars (modified def from Kwiki.pm 0.18):
my $WORD = "A-Za-z0-9\xc0-\xff_";
my $LWORD = "!$WORD";                        # add ! for escaping

# conformance adjustments
$close_empty_tag = $use_xhtml_tags ? " />" : ">" ;
$close_list_item = $close_list_item ? "</li>" : "" ;
$anchor_text = $anchor_text ? "&nbsp;" : "" ;
$use_xhtml_tags and $break =~ s/(<br.*)>$/$1 \/>/i;
$list_break = $use_xhtml_tags ? "<br />" : "<br>" ;

# generate close tags (from potentially multi-word open tags)
my ($i_close) = $i_tag =~ m/(\w+)/;
my ($b_close) = $b_tag =~ m/(\w+)/;
my ($u_close) = $u_tag =~ m/(\w+)/;
my ($mono_close) = $mono_tag =~ m/(\w+)/;

# adjust chunks with spaces to force 
# paragraphs; remove \n\n padding.
sub balance {
  my ($t_ref, $c_ref) = @_;
  for (my $i=1; $i<scalar @$c_ref; $i++) {
    if ($i % 2) {
      if ((@$c_ref[$i-1] =~ m/\n\n$|^$|^\n$/) and (@$c_ref[$i+1] =~ m/^[^\n]/)) {
        @$c_ref[$i] =~ s/^/ /s;           # force an open-tag here
      } elsif ((@$c_ref[$i-1] !~ m/^\n$|\n\n$/) and (@$c_ref[$i+1] =~ m/^\n/)) {
        @$c_ref[$i] =~ s/$/ /s;           # force a close-tag here
      }
    }
  }
  $$t_ref = join '', @$c_ref;
  $$t_ref =~ s/\n\n$//;
  $$t_ref =~ s/^\n\n//;
}


# modified sub from Kwiki.pm 0.18, Brian Ingerson
sub lists {
  my $text_ref = shift;
  my $cycle = 0;
  my $ul_marks = '[*+-]+';              # one-or-more of: *+-
  my $ol_marks = '\d+';                 # one-or-more digits
  my $ol_punc = '[:)>+-]';              # one of :)>+- to follow ol_marks
  
  my $list_marks = "(?:$ul_marks|$ol_marks$ol_punc?)";

  my @chunks = map {                    # detect, split, and process list blocks:
    my $level = 0;
    my @tag_stack;
    if ($cycle++ % 2) {
      my $text = '';
      my @lines = /(^$list_marks.*?\n)(?=(?:^$list_marks[ ][^\s\n]|$))/gms;
      for my $line (@lines) {
        $line =~ s/^($ul_marks|$ol_marks)$ol_punc*[ ]+//;        
        my $new_level = length($1);
        my $tag = ($1 =~ /\d/) ? 'ol' : 'ul';
        if ($new_level > $level) {                 # open a new list, or
          for (1..($new_level - $level)) {
            push @tag_stack, $tag;
            $text .= "<$tag>\n";
          }
          $level = $new_level;}
        elsif ($new_level < $level) {              # close the current list, or
          for (1..($level - $new_level)) {
            $tag = pop @tag_stack;
            $text .= "</$tag>\n";
          }
          $level = $new_level;}
        if ($close_list_item) {
          chomp($line);
          $text .= "<li>$line$close_list_item\n";  # add a list item.
        } else {
          $text .= "<li>$line";
        }
      }
      for (1..$level) {                  # close open lists
        my $tag = pop @tag_stack;
        $text .= "</$tag>\n";
      }                                  # add break tags
      $text =~ s/(?<!>)\n(?![<|\n])/$list_break\n/gm;

      $_ = $text;
    }
    $_;
  }
  split m/^((?:$list_marks[ ]+)[^\s\n].+?\n)(?=^[ ]|\n|$)/ms, "\n\n$$text_ref\n\n";

  balance($text_ref, \@chunks);
}

sub blockquotes {
  my $text_ref = shift;
  my $cycle = 0;
  my @chunks = map {
    if ($cycle++ % 2) {
      my $text = '';
      $text = join "\n$close_p_tag\n\n$open_p_tag\n", split /\n\n/, $_;
      $text =~ m/\n\n/ and $text = "$open_p_tag\n$text\n$close_p_tag";
      $text = "<blockquote>\n$text\n</blockquote>";  # best so far!
      $_ = "$text\n";
    }
    $_;
  } split m/^{=(?:[\n\s])*(.*?)(?:[\n\s])*(?<!!)=}(?: *)\n/ms, "\n\n$$text_ref\n\n";

  balance($text_ref, \@chunks);
}

sub rules {
  my $text_ref = shift;
  my $cycle = 0;
  my @chunks = map {
    #if ($cycle++ % 2) { $_ = "<hr>\n"; }
    if ($cycle++ % 2) { $_ = "<hr$close_empty_tag\n"; }
    $_;
  # (originally: m/(?<!!)^(----)\n/ms ?)
  } split m/(?<!!)^(----)$/m, "\n\n$$text_ref\n\n";

  balance($text_ref, \@chunks);
}

sub org_heads {
  my $text_ref = shift;
  my $cycle = 0;
  my @chunks = map {
    if ($cycle++ % 2) {
      /^(\*+) /;
      my $rellev = length($1);
      my $lev = $rellev + $org_base_h_level - 1;
      s#(?:\*{$rellev} )(\S.*?)$#<h$lev>$1</h$lev>\n#;
#      my $len = length($1);
#      s#(?:={$len} )(\S.*?)(?: ={1,6})?$#<h$len>$1</h$len>\n#;
    }
    $_;
  } split m/^(\*{1,6}[ ]\S.*?)\n/ms, "\n\n$$text_ref\n\n";

  balance($text_ref, \@chunks);
}

sub heads {
  my $text_ref = shift;
  my $cycle = 0;
  my @chunks = map {
    if ($cycle++ % 2) {
      /^(=+) /;
      my $len = length($1);
      s#(?:={$len} )(\S.*?)(?: ={1,6})?$#<h$len>$1</h$len>\n#;
    }
    $_;
  } split m/^(={1,6}[ ]\S.*?(?: ={1,6})?)\n/ms, "\n\n$$text_ref\n\n";

  balance($text_ref, \@chunks);
}

sub refs {
  my $text_ref = shift;
  my @text_ary = ($$text_ref =~ m/(?<!!)\[([\d]+|[a-zA-Z])\]/gm);
  foreach (@text_ary) {
    my $flag = 0;
    $$text_ref =~ s{
     (?<!!)
     ^\[
     $_[ ](https?|ftp|irc):([^\s]+?)
     ([ ][^\]]*)?
     \]
    }{
     $flag = 1;
     my $p = escape_path($2);
     my $a = escape_attr($3);
     "[$_]: <a href=\"$1:$p\"$a>$1:$p</a>";
    }emx;
    ## a little bonus: allowing plaintext refs
    if (! $flag) {
      $$text_ref =~ s{(?<!!)^\[$_([ ].+?)\]}{[$_]:$1}m;
    }
  } 
}

sub images {
  my $text_ref = shift;
  $$text_ref =~ s{
   (?<![$LWORD])
   \[img[ ]
   #(/[^\s\]]+?)
   (//?[^\s\]]+?)
   ([ ][\d]+,[\d]+)?
     ([ ][^\]]*)?
   \]
   (?!$WORD)
  }{
   my $p = escape_path($1);
   my $a = escape_attr($3);
   my $wh;
   if ($2) {
     my $str = $2;
     my ($w, $h) = ($str =~ m!(\d+),(\d+)!);
     $wh = " width=\"$w\" height=\"$h\"";
  }
   "<img src=\"$p\"$wh$a$close_empty_tag";
  }egmox;
}

sub escape_path {
  my $s = shift;
  $s =~ s:/:!/:g;
  return $s;
}

sub escape_attr {
  my $s = shift;
  $s =~ s:_:!_:g;
  return $s;
}


sub story {
  my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;

  # Blosxom expects \n line-endings (ascii 10), but macs might use 
  # \r (ascii 13), and windows might use \r\n (ascii 13,10).
  if ($$title_ref =~ s/\r\n?/\n/) {
    ($$title_ref, my $temp) = split /\n/, $$title_ref, 2;
    $$body_ref = $temp . $$body_ref;
  }

  if ($$body_ref =~ m/\r/) {
    $$body_ref =~ s/^(?:(\r\n?)+)/\n\n/;
    $$body_ref =~ s/\r\n|\r/\n/gm;
    # -- OR is this faster? --
    #$$body_ref =~ s/\r\n?/\n/gm;
  }

  # 3 chances to ignore this file:
  #  - ignore meta-markup
  $play_nice and 
      $meta::markup and 
          $meta::markup eq 'none' ? $markup_active = 0 : $meta::markup ne 'blox' and return 0;
  #  - noblox comment in entry file:
  $$body_ref !~ s/^<!--\s*noblox\s*-->$//mi or return 0;
  #  - noblox file
  $use_noblox_file and 
      $blox_skip_files{"$blosxom::datadir$path/$filename.$blosxom::file_extension"} and 
          return 0;

  #  - nobloxmarkup comment in entry file:
  $$body_ref =~ m/^<!--\s*nobloxmarkup?\s*-->$/mi and $markup_active = 0;

  # preformatted, step 1 of 2
  # pull <pre.../pre> blocks completely out of the story
  my $pre_mark = rand(7);
  while ($$body_ref =~ m/$pre_mark/) {$$pre_mark += rand(7);}
  $pre_mark = "<$pre_mark>";               # prevent being wrapped in <p>s
  my %pre_storage = ();
  $i = 0;
   while ($$body_ref =~ s/(<pre.*?>.*?<.*?\/pre>)/$pre_mark/si) {
    $i++;
    $pre_storage{$i} = $1;
  }

  my $p, $a;
  # do some block markup:
  if ($markup_active) {
    # set anchor
    $$body_ref =~ s{(?<!!)^\[#(\w+?)\]$}{\n<a class="bloxanchor" name="$1">$anchor_text</a>\n}gm;

    # right, center, left DIVs; w/escapes
    $$body_ref =~ s/(?<!!)^>>>>(\S.*)\n/<div align="right">$1<\/div>\n/gm;
    $$body_ref =~ s#^\!(?=>>>>)##gm;
    $$body_ref =~ s/(?<!!)^<<<<(\S.*)\n/<div align="left">$1<\/div>\n/gm;
    $$body_ref =~ s#^\!(?=<<<<)##gm;
    $$body_ref =~ s/(?<!!)^>><<(\S.*)\n/<div align="center">$1<\/div>\n/gm;
    $$body_ref =~ s#^\!(?=>><<)##gm;

    # org-mode heads
    org_heads($body_ref);

    # heads
#    heads($body_ref);

    # rules (original position)
    rules($body_ref);

    # blockquotes
    blockquotes($body_ref);
    # escape blockquotes
    $$body_ref =~ s/^!(?={=)//gm;
    $$body_ref =~ s/!(?==})//gm;

    # lists
    lists($body_ref);

    # escape heads and rules
    $$body_ref =~ s#^!(?=[=-])##gm;

  }

  $have_starting_blanklines = $$body_ref =~ s/^\n+//s;
  $have_ending_blanklines = $$body_ref =~ s/\n+$//s;

  $$body_ref =~ s/\n{3,}/\n\n/gm;          # eat surplus blank lines

                                           # change untagged start-of-blocks 
  $$body_ref =~ s/\n\n(?!<)/\n\n$open_p_tag\n/gm;

                                           # change untagged end-of-blocks 
  $$body_ref =~ s/(?<!>)\n\n/\n$close_p_tag\n\n/gm;

                                           # break single lines if allowed 
  $break_singles and $$body_ref =~ s/(?<!>)\n(?![<|\n])/$break\n/gm;

                                           # change first untagged start-of-block if allowed
  ($add_initial_open_tag) && ($$body_ref =~ s/^(?!<)/$open_p_tag\n/s);

                                           # change last untagged end-of-block if allowed
  ($add_final_close_tag) && ($$body_ref =~ s/(?<!>)$/\n$close_p_tag/s);

  # do some inline markup:
  if ($markup_active) {
                                           # pre-treat all links
    $$body_ref =~ s#((?:https?|ftp|irc):)(/{0,2})(\S*?)#$1$3#g;

    # escape all such sequences as: " />" 
    # to stop italic from trying to open
    $$body_ref =~ s#[ ]/># !/>#gm;

    # protect relative html links from styles
    $$body_ref =~ s{
     (<a[ ].*?>)
    }{
     $p = $1;
     $p =~ s:/:!/:g;
     $p =~ s:_:!_:g;
     $p;
    }gsie;

    # code
    $$body_ref =~ s#(?<!!)\[=(.+?)\](?![\]])#<$mono_tag>$1</$mono_close>#gs;

    # big and small
    $$body_ref =~ s#(?<![$LWORD])\+\+\+(\S.*?\S|\S)\+\+\+(?![$WORD])#<big>$1</big>#og;
    $$body_ref =~ s#(?<![$LWORD])---(\S.*?\S|\S)---(?![$WORD])#<small>$1</small>#og;

    # underline
    $$body_ref =~ s#(?<![$LWORD])_(\S.*?\S|\S)_(?![$WORD])#<$u_tag>$1</$u_close>#og;

    # images
    images($body_ref);

    # reference links
    refs($body_ref);

    # absolute named links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     ([^\] ][^\]]*?)[ ]
     (https?|ftp|irc):([^\] ]+?)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($3);
     $a = escape_attr($4);
     "<a href=\"$2:$p\"$a>$1</a>";
    }egmox;

    # absolute raw links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     (https?|ftp|irc):([^\] ]+?)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($2);
     $a = escape_attr($3);
     "<a href=\"$1:$p\"$a>$1:$p</a>";
    }egmox;

    # relative named site links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     ([^ \]][^\]]*?)[ ]
     //([^\] ]+)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($2);
     $a = escape_attr($3);
     "<a href=\"!/$p\"$a>$1</a>";
    }egmox;

    # relative raw site links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     //([^\] ]+)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($1);
     $a = escape_attr($2);
     "<a href=\"!/$p\"$a>!/$p</a>";
    }egmox;

    # relative named blog links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     ([^ \]][^\]]*?)[ ]
     ://*([^\] ]*)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($2);
     $a = escape_attr($3);
     "<a href=\"$blosxom::url!/$p\"$a>$1</a>";
    }egmox;

    # relative raw blog links
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
#     ://*([^\] ]+?)
     ://*([^\] ]*?)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     $p = escape_path($1);
     $a = escape_attr($2);
     "<a href=\"$blosxom::url!/$p\"$a>!/$p</a>";
    }egmox;
 
    # link to anchor
    $$body_ref =~ s{
     (?<![$LWORD])
     \[
     ([^=\#\]][^\]]+?)
     [ ]\#\#(\w+)
     ([ ][^\]]*)?
     \]
     (?!$WORD)
    }{
     "<a href=\"\#$2\"$3>$1</a>";
    }egmox;

                                                # pre-treat all links again
    $$body_ref =~ s#((?:https?|ftp|irc):)(/{0,2})(\S*?)#$1$3#g;

    # bold
    $$body_ref =~ s#(?<![$LWORD])\*(\S|\S.*?\S)\*(?![$WORD])#<$b_tag>$1</$b_close>#og;

    # italic
    $$body_ref =~ s#(?<![$LWORD<])/((?!/)\S|(?!/)\S.*?\S)(?<!!)/(?![$WORD])#<$i_tag>$1</$i_close>#og;

    # escape *, /, _, and list marks
    $$body_ref =~ s#!(?=[*/_])##g;              # inline first,
    $$body_ref =~ s#^!(?=!*[\d$STAR])##gm;      # then lists

    # escape [=code], [http:], [named http:], [#anchor], [+big], [-small]
    $$body_ref =~ s#!(?=\[)##g;
    $$body_ref =~ s#!(?=\+\+\+|---)##g;

    # restore "normal" links
    $$body_ref =~ s#((?:https?|ftp|irc):)([^/])#$1//$2#g;
  }
                                # restore leading/trailing blank line...
  ($have_starting_blanklines) && ($$body_ref =~ s/^/\n/);
  ($have_ending_blanklines) && ($$body_ref =~ s/$/\n/);

                                # strip lone leading and trailing next-to spaces
  $$body_ref =~ s/($open_p_tag\n) (<)/$1$2/gm;
  $$body_ref =~ s/(>) (\n$close_p_tag)/$1$2/gm;
  ## (strip _consecutive_ spaces with: s/($open_p_tag\n) +?(<)/$1$2/gm;)

  $i = 1;                       # preformatted, step 2 of 2: restore replaced blocks
  while ($$body_ref =~ s/$pre_mark/$pre_storage{$i}/) {$i++;}

}

1;

__END__

=head1 NAME

Blosxom Plug-in: blox

=head1 SYNOPSIS

* Wraps user-specified markup tags around "paragraphs" in plain 
  text entry files; optionally adds pre-selected linebreak 
  tags to single lines.

* Optional markup notation creates html tags for heads, rules, 
  blockquotes, lists, anchors, links, images, and bold, italic, 
  underline, and monospace text styles.

* Doesn't interfere with existing markup, including <PRE> tags

* Gets out of the way of other formatting plugins (via meta).

* Config file or hard-wired story comments allow blox to ignore 
  directories and files; un-ignore allows great specificity.

* Reads files from any text processor, recognizing Unix, Mac, and 
  Windows line ends.


=head1 INSTALLATION

Locate the blox plugin you downloaded; it may be in a ZIPped archive. 
Open the "blox" file and answer the questions in CONFIGURATION SECTION. 
Upload or drop the "blox" file into your blosxom plugins folder. Blog on.


=head1 CONFIGURATION

With any luck, the instructions in the "Configuration Section" 
at the top of this file are sufficient; if more information is 
needed, see the documentation at:
  http://www.enilnomi.net/dltext/blox.dl


=head1 USAGE NOTES

You're always free to use html markup in your entries; blox won't change any 
of your existing tags.  However, in cases where you have a tag at the start 
or end of a paragraph (such as "<b>" or "</a>"), you must add a single space 
before or after the tag to get blox to add its open or close block tag.

For example, the following entry text (everything between the double quotes) 
will produce a paragraph:
"
 <b>Do you see</b> the leading space on this line?

"
while this entry text won't:
"
<b>What's missing</b> is a leading space on this line.

"

(You don't need to add spaces to your text in anticipation of html tags 
that blox markup notation might add -- leading or trailing spaces are only 
needed for actual tags at the start or end of "paragraphs.")


=head2 SIMPLE MARKUP

A simple markup notation for generating html tags is available by setting 
$markup_active to 1. Notation rules are:
= Headline 1-6 
    1 to 6 "=" and a space, then head text, alone on a line. Optionally 
    put a space and matching number of "=" after head text. 

{= Blockquote =}
    Start a line with "{=" to open a blockquote; end a line with "=}" to 
    close it. Blockquotes can span paragraphs, so make sure you close them! 
    All markup except for blockquotes can be used inside a blockquote. If 
    you need to use "=}" within a blockquote, escape it as !=}.

* Unordered list item
1 Ordered list item
    Lines beginning with "list marks" and a space, followed by text, become 
    list items; the number of list marks determines the nested level of the 
    list. Consecutive list items are contained in the same list. List items 
    can be mulit-line, provided no line starts with a space. List end on a 
    blank line or a line beginning with a space.
    List marks --
      Unordered: *, +, and -
      Ordered: digits; can optionally be followed by :, ), >, +, or -

----
    four dashes alone on a line becomes <hr>

*bold words*
    stars enclose single-line words

/italic words/
    slashes enclose single-line words

_underlined words_
    underscores enclose single-line words

[=monospaced words]
    [= can be anywhere; ] can span lines

[img relative_url attributes]
    [ and ] enclose single-line "img" and a space, followed by a relative 
    (to root) url, followed by a space and optional attributes.

[link text URL attributes]
    [ and ] enclose single-line link information. Link text (and a space) 
    is optional; URL is required, and can be marked as being a complete 
    address (http://), a relative-to-root address (//), or a relative-to-
    blog address (:/); (a space and) attributes are optional. Image markup 
    can be used as link text.

[#anchor_name]
    [ and ] enclose # and singe-word same-page anchor

[link text ##anchor]
    [ and ] enclose single-line link text, ##, and singe-word same-page 
    anchor name. Image markup can be used as link text.

reference[1] links
[1 URL attributes]
    [ and ] enclose digit(s) or single letter to form a reference. 
    Then, alone on a line, [ and ] enclose the reference character(s) 
    and a space, and a complete url; (a space and) attributes are optional.

Escaping Markup
!   preceding exclamation point escapes ("ignores") markup.

The file "blox markup guide.txt" (included in the archive version of blox 
and available online at www.enilnomi.net/downloads/blox_markup_guide.txt) 
is a complete guide to blox markup notation. Set $markup_active and 
$break_singles to 1 in blox, and drop the file into your datadir to read  
complete markup documentation.


=head2 IGNORING FILES

There are three ways to tell blox to skip over (ignore) an entry file:
1) The html comment "<!--noblox-->" (no quotes) at the start of any 
   line in the story will tell blox to skip that file. (Similarly, 
   ignore markup for a file by using "<!--nobloxmarkup-->".)

2) To ignore a file via the meta plugin, use any value other than 
   "blox" for the variable $meta-markup -- $meta-markup:textile2; 
   $meta-markup:none; $meta-markup:noblox will all ignore a file. 
   ($meta-markup:blox will NOT ignore a file.)

3) Use a "noblox" file to ignore indivdual files and/or entire 
   directories: create a text file named "noblox" (no quotes) 
   in Blosxom's plugins state directory, and enter the paths 
   to files or directories that blox should ignore. 

   Valid paths in the noblox file are formatted lines:
   * all paths start from where the Blosxom datadir leaves off
   * no path begins with a slash (/)
   * all directory paths end with a slash (/)

   For example, if your $blosxom::datadir is:
     /var/www/html/example.net/blosxom
   and you want blox to ignore the story:
     www/example.net/blosxom/tech/projects/time_machine.txt
   then your "noblox" entry for the file would look like this:
     tech/projects/time_machine.txt

   To have blox skip the whole /projects folder:
     tech/projects/

   To have blox skip the whole somewhere.net/blosxom/tech folder:
     tech/

Lines in the noblox file can themeslves be ignored by adding a leading 
"#" (no quotes); i.e. making them Perl comments.


=head2 UN-IGNORING FILES

Files or directories within ignored paths can be "un-ignored" by 
preceding their paths with a "!" (no quotes) in the noblox file. 

For example, let's say that everything in the /tech directory 
could be ignored, except for the files in /tech/projects directory. 
Your noblox entries would look like this:
  tech/
  !tech/projects/
So, entry files in /tech/programming or /tech/news will be 
ignored, but the files in the /tech/projects will be handled 
by blox.

NOTE: a noblox comment within an entry file always "trumps" an 
unignore path in the noblox file.


=head2 PREFORMATTED TEXT

As of version 0.98 blox properly renders preformatted text blocks 
(text within <PRE> tags); previous versions required most users to 
make blox ignore files that contained PRE tags. Now, nearly no one 
should have to ignore such files.


=head2 LINE ENDS

The blox plugin reads line ends from Unix (ascii 10), Mac (ascii 13), and 
Windows (ascii 10/13) with equal grace; use any text processor you like to 
edit story files and noblox files.


=head1 BUGS

Address bug reports and comments to the Blosxom mailing list:
http://www.yahoogroups.com/group/blosxom


=head1 VERSION

2004-10-30 (v0.99)  - blox with markup; based on 2004-09-24 (0.97-11e)
2004-10-30 (v0.98)  - blox with no markup; based on 2004-09-24 (0.97-11e)
2004-10-24 (v0.97e) - non-release WIP for markup, bugs, cleanup (0.97-11e)
2004-09-22 (v0.97d) - named character classes dropped for perl <=5.006; 
                      several settings are config'able; cleanup
2004-08-24 (v0.97a) - normal tagged links were being mangled; fixed
2004-07-22 (v0.97)  - cleanup; add un-ignore, linebreaking, styles, graceful 
                      PREs; convert line-ends in noblox file
2003-09-14 (v0.96)  - better line-end conversion
2003-09-09 (v0.95)  - LOL! put Win line-end chars in correct order ;-)
2003-08-31 (v0.94)  - add Mac and Windows line-ending conversion
2003-08-30 (v0.93)  - wip
2003-08-04 (v0.92)  - add mechanisms to ignore specified entries
2003-07-31 (v0.9)   - half-fast workaround for <PRE> tags
2003-07-20 (v0.8)   - it's alive


=head1 LICENSE

this Blosxom Plug-in
Copyright 2003-2004, Stu MacKenzie  (S2_Mac, HyperSTUff)

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.