From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

# -*- Mode: Perl -*-
# WAIT::Parse::Pod --
# ITIID : $ITI$ $Header $__Header$
# Author : Ulrich Pfeifer
# Created On : Sat Dec 14 17:38:29 1996
# Last Modified By: Ulrich Pfeifer
# Last Modified On: Sun Nov 22 18:44:40 1998
# Language : CPerl
# Update Count : 275
# Status : Unknown, Use with caution!
#
# Copyright (c) 1996-1997, Ulrich Pfeifer
#
use Carp;
use vars qw(@ISA %GOOD_HEADER);
# Got tired reinstalling Pod::Parser after each perl rebuild. So I renamed
# Pod::Text to Pod::PText. Thus this hack:
BEGIN {
eval {require Pod::PText;};
if ($@ ne '') {
require Pod::Text;
croak "Need Pod::Tex version > 2.0" if $Pod::Text::VERSION < 2.0;
@ISA = qw(Pod::Text Pod::Parser WAIT::Parse::Base);
} else {
@ISA = qw(Pod::PText Pod::Parser WAIT::Parse::Base);
}
}
use Text::Tabs qw(expand);
use strict;
# recognized =head1 headers
%GOOD_HEADER = (
name => 1,
synopsis => 1,
options => 1,
description => 1,
author => 1,
example => 1,
bugs => 1,
text => 1,
see => 1,
environment => 1,
);
sub default_indent () {4};
# make frequent tag sets reusable
my $CODE = {text => 1, _c => 1};
my $BOLD = {text => 1, _b => 1};
my $ITALIC = {text => 1, _i => 1};
my $PLAIN = {text => 1};
sub new {
my $this = shift;
my $class = ref($this) || $this;
my $self = $this->SUPER::new(@_);
bless $self, $class;
}
sub begin_input {
my $self = shift;
$self->indent(default_indent);
$self->{TAGS} = {};
$self->{OUT} = [];
}
sub indent {
my $self = shift;
if (@_) {
$self->{INDENT} = shift;
}
$self->{INDENT};
}
# Stolen afrom Pod::Parser by Tom Christiansen and Brad Appleton and modified
sub interpolate {
my $self = shift;
my ($text, $end_re) = @_;
$text = '' unless (defined $text);
$end_re = "\$" unless ((defined $end_re) && ($end_re ne ''));
local($_) = $text;
my @result;
my ($seq_cmd, $seq_arg, $end) = ('', '', undef);
while (($_ ne '') && /([A-Z])<|($end_re)/) {
# Only text after the match remains to be processed
$_ = $';
# Append text before the match to the result
push @result, $self->{TAGS}, $`;
# See if we matched an interior sequence or an end-expression
($seq_cmd, $end) = ($1, $2);
last if (defined $end); # Saw the end - quit loop here
# At this point we have found an interior sequence,
# we need to obtain its argument
if ($seq_cmd =~ /^([FBIC])/) {
my $tag = '_' . lc $1;
my $tags = $self->{TAGS};
my %tags = (%{$tags}, $tag => 1);
$self->{TAGS} = \%tags;
push @result, $self->interpolate($_, '>');
$self->{TAGS} = $tags;
} else {
my @seq_arg = $self->interpolate($_, '>');
my $i;
for ($i=1;$i<=@seq_arg;$i+=2) {
push @result, $seq_arg[$i-1],
$self->interior_sequence($seq_cmd, $seq_arg[$i]);
}
}
}
## Handle whatever is left if we didnt match the ending regexp
unless ((defined $end) && ($end_re ne "\$")) {
push @result, $self->{TAGS}, $_;
$_ = '';
}
## Modify the input parameter to consume the text that was
## processed so far.
$_[0] = $_;
## Return the processed-text
return @result;
}
sub textblock {
my ($self, $text) = @_;
$self->output($self->interpolate($self->wrap($text)), $PLAIN, "\n\n");
}
sub output {
my ($self) = shift;
while (@_) {
my $tags = shift;
my $text = shift;
croak "Bad tags parameter: '$tags'" unless ref($tags);
push @{$self->{OUT}}, $tags, $text;
}
}
sub verbatim {
my ($self, $text) = @_;
my $indent = $self->indent() + default_indent;
$text = expand($text);
my ($prefix) = ($text =~ /^(\s+)/);
if (length($prefix) < $indent) {
my $add = ' ' x ($indent - length($prefix));
$text =~ s/^/$add/gm;
} elsif (length($prefix) > $indent) {
my $sub = ' ' x (length($prefix) - $indent);
$text =~ s/^$sub//gm;
}
$self->output($CODE, $text);
}
sub command {
my ($self, $cmd, $arg, $sep) = @_;
if ($cmd =~ /^head(\d)/) {
my $indent = $1-1;
my $tags = $self->{TAGS};
$self->{TAGS} = $BOLD;
$self->output($self->interpolate($self->wrap($arg,
$indent*default_indent)."\n\n"));
if ($indent) {
$self->{TAGS} = $tags;
} else {
my $sarg = lc $arg;
$sarg =~ s/\s.*//g;
if ($GOOD_HEADER{$sarg}) {
$self->{TAGS} = {lc $sarg => 1}
} else {
$self->{TAGS} = {text => 1}
}
}
} elsif ($cmd =~ /^back/) {
$self->indent(default_indent);
} elsif ($cmd =~ /^over/) {
my $indent = (($arg)?$arg:default_indent) + default_indent;
$self->indent($indent);
} elsif ($cmd =~ /^item/) {
$self->output($self->interpolate($self->wrap($arg,default_indent)."\n\n"))
} else {
$self->output($self->{TAGS}, $arg);
}
}
# inspired from Text::Wrap by David Muir Sharnoff
sub wrap {
my ($self, $t, $indent) = @_;
$indent = $self->indent unless defined $indent;
my $columns = 76 - $indent;
my $ll = $columns;
my $prefix = ' ' x $indent;
my $result = $prefix;
my $length;
# E/L will probably change length
$t =~ s/([EL])<(.*?)>/$self->interior_sequence($1,$2)/eg;
$t =~ s/\s+/ /g;
while ($t =~ s/^(\S+)\s?//o) {
my $word = $1;
# inline length calculation for speed
my $dummy = $word;
$dummy =~ s/[A-Z]<(.*?)>/$1/og;
$length = length($dummy);
if ($length < $ll) {
$result .= $word . ' ';
$ll -= $length + 1;
} else {
$result =~ s/ $/\n/;
$result .= $prefix . $word . ' ';
$ll = $columns - $length - 1;
}
}
return $result;
}
sub parse_from_string {
my $self = shift;
local($_);
$self->{CUTTING} = 1; ## Keep track of when we are cutting
$self->begin_input();
my $paragraph = '';
for (split /\n\s*\n/, $_[0]) {
$self->parse_paragraph($_ . "\n\n");
}
$self->end_input();
}
sub tag {
my $self = shift;
$self->begin_input;
$self->parse_from_string(@_);
my $result = $self->{OUT};
delete $self->{OUT};
delete $self->{TAGS};
@{$result};
}