/usr/local/CPAN/HTML-WebMake/HTML/WebMake/UserTags.pm


# Allow the definition of user tags in WebMake files, like so:
# 
# <{mkthumb name="${from}" delim=","}>...text...</{mkthumb}>
# <{alone name="${from}" }/>

package HTML::WebMake::UserTags;

###########################################################################


use Carp;
use strict;

use HTML::WebMake::Main;

use vars	qw{
  	@ISA
};

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




###########################################################################

sub new ($$$$$) {
  my $class = shift;
  $class = ref($class) || $class;
  my ($main) = @_;

  my $self = {
    'main'		=> $main,

    'tags'		=> { },
    'tags_defined'	=> 0,
    'tag_names'		=> [ ],

    'prefmt_tags'	=> { },
    'prefmt_tags_defined' => 0,
    'prefmt_tag_names'	=> [ ],

    'wmk_tags'		=> { },
    'wmk_tags_defined'	=> 0,
    'wmk_tag_names'	=> [ ],
  };

  bless ($self, $class);

  $self;
}

sub dbg { HTML::WebMake::Main::dbg (@_); }

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

sub def_tag {
  my ($self, $is_empty, $is_wmk, $is_prefmt, $name, $fn, @reqd_attrs) = @_;

  my $tag = { };
  if ($is_empty) {
    $tag->{is_empty} = 1;
    $tag->{pattern} = qr{\<\{?${name}(?:\s([^>]*?)|)\s*\/\}?\>}is;
  } else {
    $tag->{is_empty} = 0;
    $tag->{pattern} =
	qr{\<\{?${name}(?:\s([^>]*?)|)\s*\}?\>(.*?)\<\/\{?${name}\s*\}?\>}is;
  }

  @{$tag->{reqd_attrs}} = @reqd_attrs;
  $tag->{handler_fn} = $fn;

  if ($is_wmk) {
    push (@{$self->{wmk_tag_names}}, $name);
    $self->{wmk_tags_defined}++;
    $self->{wmk_tags}->{$name} = $tag;
    dbg ("Defined new WebMake tag: <$name>");

  } elsif ($is_prefmt) {
    push (@{$self->{prefmt_tag_names}}, $name);
    $self->{prefmt_tags_defined}++;
    $self->{prefmt_tags}->{$name} = $tag;
    dbg ("Defined new preformat content tag: <$name>");

  } else {
    push (@{$self->{tag_names}}, $name);
    $self->{tags_defined}++;
    $self->{tags}->{$name} = $tag;
    dbg ("Defined new content tag: <$name>");
  }

  '';
}

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

sub subst_tags {
  my ($self, $from, $str) = @_;
  return $self->_subst_tags($from, $str, 0, 0);
}

sub subst_wmk_tags {
  my ($self, $from, $str) = @_;
  return $self->_subst_tags($from, $str, 1, 0);
}

sub subst_preformat_tags {
  my ($self, $from, $str) = @_;
  return $self->_subst_tags($from, $str, 0, 1);
}

sub _subst_tags {
  my ($self, $from, $str, $is_wmk, $is_prefmt) = @_;
  my @tags;
  my $tag;

  if ($is_wmk) {
    return unless ($self->{wmk_tags_defined});
    @tags = @{$self->{wmk_tag_names}};

  } elsif ($is_prefmt) {
    return unless ($self->{prefmt_tags_defined});
    @tags = @{$self->{prefmt_tag_names}};

  } else {
    return unless ($self->{tags_defined});
    @tags = @{$self->{tag_names}};
  }

  my $foundatag = 0;
  foreach my $tagname (@tags) {
    next unless (defined $tagname);
    if ($is_wmk) {
      $tag = $self->{wmk_tags}->{$tagname};
    } elsif ($is_prefmt) {
      $tag = $self->{prefmt_tags}->{$tagname};
    } else {
      $tag = $self->{tags}->{$tagname};
    }

    next unless ($$str =~ /\<${tagname}\b/is);

    # been deprecated for a while. take it out
    # next unless ($$str =~ /\<\{?${tagname}[\s>}]/is);
    # if ($$str =~ /\<\{${tagname}/is) {	#}
    # warn "$from: <{${tagname}}> deprecated, use <${tagname}> instead\n";
    # }

    $foundatag = 1;
    my $pat = $tag->{pattern};
    if ($tag->{is_empty}) {
      $$str =~ s/${pat}/ $self->call_tag ($tag, $from, $tagname, $1, ''); /gies;
    } else {
      $$str =~ s/${pat}/ $self->call_tag ($tag, $from, $tagname, $1, $2); /gies;
    }
  }

  return $foundatag;
}

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

sub call_tag {
  my ($self, $tag, $from, $tagname, $argtext, $text) = @_;
  local ($_) = '';

  my $util = $self->{main}->{util};
  my $attrs = $util->parse_xml_tag_attributes ($tagname,
  	defined ($argtext) ? $argtext : '',
  	$from, @{$tag->{reqd_attrs}});
  if (!defined $attrs) { return ''; }

  if ($self->{main}->{paranoid}) {
    return "\n(Paranoid mode on - perl code evaluation prohibited.)\n";
  }

  my $pl = $self->{main}->getperlinterp();

  $pl->enter_perl_call();
  my $ret = eval {
    package main;
    &{$tag->{handler_fn}} ($tagname, $attrs, $text, $pl);
  };
  $pl->exit_perl_call();

  if (!defined $ret) {
    warn "<$tagname> code failed: $@\n";
    $ret = '';
  }
  $ret;
}

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

1;