Changes to pp2latex

[email protected] (Robert Inder) 31 Jan 2003 00:36:13 +0000
Newsgroups perl.perlpoint
Message-ID <[email protected]>
I've been using perlpoint for a while now, to generate fairly complex
suites of HTML pages, and also documents that I can both print via
LaTeX and distribute via the web.

There were a few places where I could not get it to do what
I wanted, so I've hit it with a hammer until I have something
that does what I want.=20=20

   ((Anyone interested should look at http://www.interactive.co.uk=20
     and http://information.overlaid.com.  Both sites, and the case
     studies accessible from them, are Perlpoint.  And no, they
     don't say that at the moment, and yes, the probably should.  Some
     time...))

In the process, I came to the conclusion that someone has missed a
trick at the fairly low level design stage, and built a fair bit of
formatting into pp2latex itself.  Given that the whole point of latex
is to let you specify how things should be formatted, I think this was
a mistake...

I see two specific problems.

First: users are allowed to specify a "prolog" file.  If they=20
do not do this, pp2latex currently uses a latex skeleton that is
included as a "here" document within the perl code.  This means
it is effectively hidden away!

I think the correct behaviour is that if users do not specify a prolog
file of their own, pp2latex should use a standard prolog taken from
a file that is distributed with it.  This will make it easier for users to
create their own prolog by customising the standard one.  You'll
see why I think this is important below...

Second: in "handleHeadline" there is a cascaded "elsif" which
converts section depth into the corresponding "latex" section name:
0 =3D> chapter, 1 =3D> section and so forth.  However, the system counts
depths from 1, so "chapter" is forever inaccessible!  This is okay
for the default style of "article", which does not have chapters, but
it means that you can't produce a "report", with a table of contents
and the like.=20=20

I got round this by simply subtracting "1" from the
depth argument.  But that means I'll ALWAYS get chapters, so I can't
use an "article" style.  The right thing to do is to give pp2latex
an extra option which tells it whether to have "chapters", or just
start with "section".  The same option should then be used
to choose one of TWO default prologs (one based on report, one on
article).

Now, as well as pontificating about how the pp2latex could be better,
I did in fact change things to get the functionality I needed for
the job in hand.    I'm sure I've improved functionality,=20
but I'm not sure I've done it in the "right" way for pp2latex.

So, rather than just dump a changed version of the tool on the table
(which I have done, at the end of this message),=20
and say "take it or leave it", I have also described
my intention.  So that if anyone wants to do the same thing some other
way, they can...

First off, I didn't like was the way URLs were being formatted
--- small italics in square brackets, I think it was.  But I couldn't
change it because this was hard wired somewhere deep inside pp2latex.

Which to my mind is the wrong place!  The whole point of LaTeX is that
it lets you change formatting!  So I modified pp2latex so that instead
of it trying to decide how the URL should look, it simply puts it, and the
text of the anchor (body of the \L) as arguments to a latex command "\PPurl=
".

This, of course, has to be defined.  Which I do in the prolog file...
But now, hey presto, I can have URLs appear exactly the way I want....

I did the same trick for references to named labels.  pp2latex was
planting a LaTeX "ref" tag.  I changed this to plant a call to
a command that I defined, which in turn displayed the reference in the
way I like (e.g. "Page 12").  But again, anyone who doesn't like it...

Then I realised that other cross-references were not working properly.
I wanted to adopt a similar strategy, based on writing simple but
configurable wrappers around LaTeX's own reference mechanism.

So first, I modified handleHeadLine to explicitly put a LaTeX label=20
at the start of each Section, named by something based on the sections
PerlPoint page ID.  Then, it is "simply" a matter of getting the various
PerlPoint cross reference commands to plant LaTeX references to those
labels.=20=20

Then, I modified the behaviour of the XREF and SECTIONREF tags to
plant the target of the reference within calls to these wrapper
commands.  This lets me produce LOCALTOCS that look like...

  This document

    - Reviews the background material (Section 2, Page 5)
    - Summarises the current problems (Section 3, Page 10)
    - Outlines possible new solutions (Section 4, Page 12)

and so forth.  See how the section references include the section
number and page in the way I like...

I've attached a revised version here.  To use it, you HAVE to
use a LaTeX "prolog" file and specify it in your ".opt" file.

I'm afraid I'm not in a position to release a sample document!

The prolog file must be based on report or book style, and
it must define four new LaTeX commands.  The file I use follows.

I've not documented the changes in the file, or updated the change
log, or anything like that.  If anyone wants to make these changes
part of the real system, and wants some more information, let me
know...=20

Enjoy....

Robert.

P.S. I've got a comparable batch of changes for pp2html, but I'll have
to merge them in to the latest release before posting them...

--
Robert Inder         Interactive Information,     07770 30 40 52 (general)
07808 492 213        3, Lauriston Gardens,        0131 229 1052  (fax)
                     Edinburgh EH3 9HH
                     SCOTLAND UK

------------------------------------------------------------------------
My LaTeX prolog...
------------------------------------------------------------------------

\documentclass [11pt] {report}   %=20
\parindent0pt                     % no indentation of first line
\parskip1ex                       % white space between chapters
\pagestyle{headings}     %
\usepackage{epsf}
\usepackage{makeidx}

% setup for DIN A4
\oddsidemargin3cm
\evensidemargin3cm
\setlength{\hoffset}{-1in}            % compensation of
\setlength{\voffset}{-2cm}            % printer offset
\title{Interactive Information Limited: Business Plan}
\author{Robert Inder}
\def\chaptername{Section}

\textwidth15cm
\topmargin1cm
\headheight3ex
\headsep12pt
\textheight23cm
\setlength{\footskip}{1.5cm}

\makeindex

\newcommand{\PPurl}[2]{\ifx#1#2{\tt #1}\else{#1\protect\footnote{url: {\tt =
#2}}}\fi}

\newcommand{\PPSref}[2]{#1 (Section \ref{#2}, Page \pageref{#2})}

\newcommand{\PPXref}[2]{#1 (Section \ref{#2}, Page \pageref{#2})}

\newcommand{\PPPageref}[1]{Page \pageref{#1}}



\begin{document}
\maketitle

\tableofcontents

\begin{flushleft}



------------------------------------------------------------------------
My modified version pp2latex follows....
------------------------------------------------------------------------

#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell
#
# $Id: pp2latex,v 1.14 2001/12/19 21:04:43 lorenz Exp $
# $Revision: 1.14 $
# $Date: 2001/12/19 21:04:43 $
#
# $Author: lorenz $
#
# Revision History: See end of file
#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

# declare script package
package PerlPoint::Converter::pp2latex;

use Pod::Text;
use Getopt::ArgvFile qw(argvFile);
use Getopt::Long;
use Data::Dumper;
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20

# pragmata
use strict;
use subs "flush", "push_page", "pp_warn";

# load modules
use File::Basename;
use Carp;
use Safe;
use PerlPoint::Tags;
use PerlPoint::Tags::Basic;
use PerlPoint::Tags::HTML;
use PerlPoint::Tags::LaTeX;
use PerlPoint::Backend;
use PerlPoint::Parser 0.34;
use PerlPoint::Constants;
use PerlPoint::Converters qw(replace_keywords copy_file update_file mk_abs_=
path);

my $me =3D basename($0);

my $VERSION =3D sprintf("%d.%02d", q/$Revision: 1.14 $/ =3D~ /(\d+)\.(\d+)/=
);
my $PACK_VERSION =3D $PerlPoint::Converters::VERSION;
$main::VERSION =3D $VERSION;

my $nix =3D "";                      # for using RCS keys in Usage, ...
my $Date =3D "Date ";


#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Usage

sub Usage {
  no strict;
  $^W =3D 0;
  my $tmpfile =3D "/tmp/$me.$$_help";
  open(ME, "< $0") or die "Can't open $me: $!\n";
  open(TMP, "> $tmpfile") or die "Can't open $tmpfile: $!\n";
  while(<ME>){
    s/PROGRAM/$me/g;
    s/P_VERSION/$VERSION/g;
    print TMP $_;
  }
  close(TMP);
  pod2text( $tmpfile );
  unlink $tmpfile;
  exit;  # we're done
} # Usage

#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D Parameter Loop

my %OPT =3D (

  slide_dir       =3D> ".",
  no_index        =3D> 0,

);

argvFile( home =3D> 1, default =3D> 1);

if (defined $ARGV[0] and $ARGV[0] =3D~ /-v$/){
  @ARGV =3D("-version");  # to avoid ambiguities
}
my $verbose =3D 1;

GetOptions( \%OPT,

  "activeContents",
  "cache",
  "cacheCleanup",
  "double_lines",
  "filter=3Ds",
  "no_index",
  "nocopyright",
  "noinfo",
  "nowarn",
  "quiet",
  "safeOpcode=3Ds@",
  "set=3Ds@",
  "slide_dir=3Ds",
  "trace:i",
  "prolog=3Ds",
  "help",
  "version",

);

# propagate options as necessary
@OPT{qw(nocopyright noinfo nowarn)}=3D(1,1,1) if exists $OPT{quiet};
$OPT{trace}=3D$ENV{SCRIPTDEBUG} if not exists $OPT{trace} and exists $ENV{S=
CRIPTDEBUG};


#=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D Script Body
Usage(1) if ($OPT{help});
print STDERR "This is $me, build $VERSION from PerlPoint::Converters $PACK_=
VERSION\n" unless $OPT{quiet};
print STDERR "$Date: 2001/12/19 21:04:43 $nix\n" unless $OPT{quiet};
print STDERR "(c) Lorenz Domke <lorenz.domke\@gmx.de> 2001.\n\n" unless $OP=
T{nocopyright};
exit if $OPT{version};


$verbose =3D 0 if ($OPT{quiet} or $OPT{noinfo});

my ($li_start, $li_end);
$li_start =3D "\\item ";
$li_end =3D "\n";

# declare variables
# Data Structures
# 000000000000000
my $embedded_latex =3D 0;

my (@streamData);
my $verbatim_flag =3D 0;

my $page_ref;  # pointer to current page buffer

my @PAGES;     # Array of pointers to PAGE structures
#  $PAGES[ $m ] =3D {
#                    BODY =3D> [ ... ],
#                    LEVEL =3D> ...,
#                    HD =3D> ...,
#                    PREV =3D> ...,
#                    NEXT =3D> ...,
#                    UP =3D> ...,
#                    DOWN =3D> ...,
#                 }
my $page_cnt =3D -1;
my %ANCHOR;  # $ANCHOR{a_name} =3D $page_cnt

my %INDEX;
my $idx_cnt =3D 0;



# declare list of tag openers
# some are only needed for compatibility with pp2htm

# build parser
my ($parser)=3Dnew PerlPoint::Parser;


# build and configure a Safe object
my $safe =3D new Safe;
if (exists $OPT{safeOpcode}){
  unless (grep($_ eq 'ALL', @{$OPT{safeOpcode}})) {
     # configure compartment
     $safe->permit(@{$OPT{safeOpcode}});
  } else {
     # simply flag that we want to execute active contents
     $safe=3D1;
  }
}

# and call it
$parser->run(
             stream  =3D> \@streamData,
             files   =3D> \@ARGV,
             safe    =3D> exists $OPT{activeContents} ? $safe : undef,
             filter  =3D> exists $OPT{filter} ? $OPT{filter} : "perl|latex",
             activeBaseData =3D> {
                                targetLanguage =3D> 'SDF',
                                userSettings   =3D> {map {$_=3D>1} exists $=
OPT{set} ? @{$OPT{set}} : ()},
                               },
             vispro  =3D> 1,
             nestedTables =3D> 1,
             var2stream   =3D> 1,
             predeclaredVars =3D> {
                                 CONVERTER_NAME    =3D> basename($0),
                                 CONVERTER_VERSION =3D> $main::VERSION,
                                },
             trace   =3D> TRACE_NOTHING
                      + ((exists $OPT{trace} and $OPT{trace} &  1) ? TRACE_=
PARAGRAPHS : 0)=20
                      + ((exists $OPT{trace} and $OPT{trace} &  2) ? TRACE_=
LEXER      : 0)
                      + ((exists $OPT{trace} and $OPT{trace} &  4) ? TRACE_=
PARSER     : 0)
                      + ((exists $OPT{trace} and $OPT{trace} &  8) ? TRACE_=
SEMANTIC   : 0)
                      + ((exists $OPT{trace} and $OPT{trace} & 16) ? TRACE_=
ACTIVE     : 0),
             display =3D> DISPLAY_ALL
                      + (exists $OPT{noinfo} ? DISPLAY_NOINFO : 0)=20=20=20=
=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20=20=20
                      + (exists $OPT{nowarn} ? DISPLAY_NOWARN : 0),
             cache   =3D> (exists $OPT{cache} ? CACHE_ON : CACHE_OFF)
                      + (exists $OPT{cacheCleanup} ? CACHE_CLEANUP : 0),
            ) or exit 1;


# build a backend
my $backend=3Dnew PerlPoint::Backend(
             name    =3D> $me,=20
             trace   =3D> TRACE_NOTHING,
             display =3D> DISPLAY_ALL
                      + (exists $OPT{noinfo} ? DISPLAY_NOINFO : 0)
                      + (exists $OPT{nowarn} ? DISPLAY_NOWARN : 0),
             vispro  =3D> 1,
);
#my $backend=3Dnew PerlPoint::Backend(name=3D>$me, trace=3D>TRACE_BACKEND);

# register backend handlers
$backend->register(DIRECTIVE_BLOCK,        \&handleBlock);
$backend->register(DIRECTIVE_COMMENT,      \&handleComment);
$backend->register(DIRECTIVE_DOCUMENT,     \&handleDocument);
$backend->register(DIRECTIVE_HEADLINE,     \&handleHeadline);
$backend->register(DIRECTIVE_LIST_LSHIFT,  \&handleLShift);
$backend->register(DIRECTIVE_LIST_RSHIFT,  \&handleRShift);
$backend->register(DIRECTIVE_ULIST,        \&handleList);
$backend->register(DIRECTIVE_UPOINT,       \&handlePoint);
$backend->register(DIRECTIVE_OLIST,        \&handleList);
$backend->register(DIRECTIVE_OPOINT,       \&handlePoint);
$backend->register(DIRECTIVE_DLIST,        \&handleList);
$backend->register(DIRECTIVE_DPOINT,       \&handleDPoint);
$backend->register(DIRECTIVE_DPOINT_ITEM,  \&handleDPointItem);
$backend->register(DIRECTIVE_SIMPLE,       \&handleSimple);
$backend->register(DIRECTIVE_TAG,          \&handleTag);
$backend->register(DIRECTIVE_TEXT,         \&handleText);
$backend->register(DIRECTIVE_VERBATIM ,    \&handleVerbatim);

my @BUFFER;
my @ERRBUFFER;  # buffer for context of error=20
my $box_bg_color=3D "blue";
my $box_fg_color=3D "white";

# and run it
$backend->run(\@streamData,
);

begin_doc();

## Now do your job: output the pages ...
for (my $i =3D 0; $i <=3D $page_cnt; $i++){
  print STDERR "New Page $i: Level ",
   $PAGES[$i]->{LEVEL}, " =3D=3D=3D> ",
   $PAGES[$i]->{HD},
   , " <=3D=3D=3D\n" if $verbose;

  # print page body
  foreach my $line ( @{$PAGES[$i]->{BODY}} ){
    # Replace _INTERNAL_SECTION with correct hyperlink
    while ($line =3D~ /_INTERN_SECTION:(.*?):_END/){
      my $a_name =3D $1;
      if (! defined $ANCHOR{$a_name}) {
        warn "**** SECTIONREF with undefined anchor name '$a_name' detected=
\n";
        $line =3D~ s/_INTERN_SECTION:.*?:_END/_UNDEF_/;  # will flag an err=
or while processing with latex !
        next;
      }
      my $hd =3D $PAGES[$ANCHOR{$a_name}] -> {HD};
      my $ref =3D "PPPage$ANCHOR{$a_name}";=20=20=20=20
      $line =3D~ s/_INTERN_SECTION:.*?:_END/$hd}{$ref/;  # two arguments, t=
ext and ID
    }

    # Replace _INTERNAL_PAGE with correct hyperlink
    while ($line =3D~ /_INTERNAL_PAGE:(.*?):_END/){
      my $a_name =3D $1;

      if (! defined $ANCHOR{$a_name}) {
        warn "**** PAGE with undefined anchor name '$a_name' detected\n";
        $line =3D~ s/_INTERNAL_PAGE:.*?:_END/_UNDEF_/;  # will flag an erro=
r while processing with latex !
        next;
      }
      my $anch=3D $ANCHOR{$a_name};
      my $ref=3D"PPPage$ANCHOR{$a_name}";
      $line =3D~ s/_INTERNAL_XREF:.*?:_END/$ref/;
    }

    # Replace _INTERNAL_XREF with correct hyperlink
    while ($line =3D~ /_INTERNAL_XREF:(.*?):_END/){
      my $a_name =3D $1;

      if (! defined $ANCHOR{$a_name}) {
        warn "**** XREF with undefined anchor name '$a_name' detected\n";
        $line =3D~ s/_INTERNAL_XREF:.*?:_END/_UNDEF_/;  # will flag an erro=
r while processing with latex !
        next;
      }
      my $ref=3D"PPPage$ANCHOR{$a_name}";
      $line =3D~ s/_INTERNAL_XREF:.*?:_END/$ref/;
    }


    print $line;
  } # loop over body lines

}

gen_index() unless $OPT{no_index};
end_doc();

exit 0;

# SUBROUTINES ##############################################################

# helper function
#----------------------------------------------------------
sub begin_doc{
  print "% Created by $me, build $VERSION from PerlPoint-Converters $PACK_V=
ERSION\n";
  if (defined $OPT{prolog}) {
    # get prolog definitions from file
    my $prolog_file =3D $OPT{prolog};
    if (-e $prolog_file) {
      open(PR, "< $prolog_file") or die "Cannot open prolog file $prolog_fi=
le: $!\n";
    } else {
      die "Cannot find prolog file $prolog_file\n";
    }
    while(<PR>){
      print;
    }
    close(PR);
  } else {

  print <<'EOT';
\documentclass [11pt] {article}   %=20
\usepackage{german}               % ISO-Latin-Zeichensatz (=E4=F6=FC=DF)
\usepackage{isolatin1}            % ISO-Latin-Zeichensatz (=E4=F6=FC=DF)
\parindent0pt                     % no indentation of first line
\parskip1ex                       % white space between chapters
\pagestyle{headings}     %
\usepackage{epsf}
\usepackage{makeidx}

% setup for DIN A4
\oddsidemargin3cm
\evensidemargin3cm
\setlength{\hoffset}{-1in}            % compensation of
\setlength{\voffset}{-2cm}            % printer offset

\textwidth15cm
\topmargin1cm
\headheight3ex
\headsep12pt
\textheight23cm
\setlength{\footskip}{1.5cm}

\makeindex

\begin{document}

\begin{flushleft}

EOT
  }
} # begin_doc

# flushleft ist fix alex

#----------------------------------------------------------
sub end_doc{

# fix alex
print "\n\n\\end{flushleft}\n";

print "\n\n\\end{document}\n";
} # end_doc


#----------------------------------------------------------
sub gen_index {
# print "\n\\section{INDEX}\n\n";
# foreach my $idx (sort keys %INDEX) {
#   print "$idx \\textbf{ \\pageref{$INDEX{$idx}}}\\\\\n";
# }
  print "\n\\printindex\n\n";
} # gen_index

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


#----------------------------------------------------------
sub start_new_page {
  my ($level, @BF) =3D @_;
  $page_cnt ++;
  $PAGES[$page_cnt] =3D {
         BODY =3D> [],
         LEVEL =3D> $level,
         HD  =3D> join("", @BF),

       };
  $page_ref =3D $PAGES[$page_cnt] -> {BODY};
  my $hd =3D $PAGES[$page_cnt] -> {HD};
  $ANCHOR{$hd} =3D $page_cnt; # insert anchor for this page
 #push @{$PAGES[$page_cnt]->{BODY}}, "<a name=3D\"$hd\">";
} # start_new_page

#----------------------------------------------------------
# simple directive handlers
sub handleSimple {
  push @BUFFER, escapes($_[2]);
} # handleSimple

#----------------------------------------------------------
sub handleHeadline {
  # $_[2] contains the level number of this header
  if ($_[1]=3D=3DDIRECTIVE_START) {
    flush;
  } else {
    start_new_page($_[2], @BUFFER);
    my $section;
    $_[2]--;
    if      ($_[2] =3D=3D 0){
      $section =3D 'chapter';
    } elsif ($_[2] =3D=3D 1){
      $section =3D 'section';
    } elsif ($_[2] =3D=3D 2){
      $section =3D 'subsection';
    } elsif ($_[2] =3D=3D 3){
      $section =3D 'subsubsection';
    } elsif ($_[2] =3D=3D 4){
      $section =3D 'paragraph';
    } elsif ($_[2] =3D=3D 5){
      $section =3D 'subparagraph';
    } else {
      $section =3D '\\textbf';
    }
    push_page $page_ref, "\n\n\\$section\{";
    flush;
    push_page $page_ref, "}\n";
    push_page $page_ref, "\\label{PPPage$page_cnt}\n";
  }
} # handleHeadline

#----------------------------------------------------------
sub handleList {
  flush;
  my $LIST;
  if ($_[0]=3D=3DDIRECTIVE_ULIST){
     $LIST =3D "itemize";
  } elsif ($_[0]=3D=3DDIRECTIVE_OLIST){
     $LIST =3D "enumerate";
  } elsif ($_[0]=3D=3DDIRECTIVE_DLIST){
     $LIST =3D "itemize";
  }
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, "\n\\begin{$LIST}\n";
  } else {
    push_page $page_ref, "\\end{$LIST}\n";
    @BUFFER =3D ();
  }
=20=20
} # handleList

#----------------------------------------------------------
sub handlePoint {
  flush;
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, $li_start;
  } else {
    push_page $page_ref, $li_end;
    @BUFFER =3D ();
  }
} # handlePoint

#----------------------------------------------------------
sub handleDPoint {
  flush;
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, "\\item ";
  } else {
    push_page $page_ref, "\n\n";
    @BUFFER =3D ();
  }
} # handleDPoint

#----------------------------------------------------------
sub handleDPointItem {
  flush;
  if ($_[1]=3D=3DDIRECTIVE_START){
    # no action
  } else {
    push_page $page_ref, "\n\n";
    @BUFFER =3D ();
  }
} # handleDPointItem

#----------------------------------------------------------
sub handleText {
  flush;
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, "\n";
  } else {
    push_page $page_ref, "\n";
  }
} # handleText

#----------------------------------------------------------
sub handleBlock { # code block with TAG recognition
#TODO Es muessen alle PerlPoint tags aus dem BUFFER des
#     Blocks entfernt werden, da Latex in \begin{verbatim} ...
#     keine Ersetzungen wie \textbf etc. vornehmen kann !!
  handleVerbatim( $_[0], $_[1], $_[2]);
} # handleBlock

#----------------------------------------------------------
sub handleLShift {
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, "\n\% Shift <\n";
  }
} # handleLShift

#----------------------------------------------------------
sub handleRShift {
  if ($_[1]=3D=3DDIRECTIVE_START){
    push_page $page_ref, "\n\% Shift >\n";
  }
} # handleRShift

#----------------------------------------------------------
sub handleVerbatim { # verbatim block without TAG recognition
  flush;
  if ($_[1]=3D=3DDIRECTIVE_START){
    $verbatim_flag =3D 1;
#   push_page $page_ref, "\n\\rule{\\textwidth}{1pt}\n";
    push_page $page_ref, "\\begin{verbatim}\n";
  } else {
    push_page $page_ref, "\\end{verbatim}";
#   push_page $page_ref, "\\rule{\\textwidth}{1pt}\n";
    $verbatim_flag =3D 0;
  }
} # handleVerbatim

#----------------------------------------------------------
sub handleComment {
    @BUFFER =3D (); # skip buffer contents
} # handleComment

#----------------------------------------------------------
sub e_escapes{
  my ($flag) =3D @_;
  if ($flag eq "micro"){
    return "\$\\mu\$";
  } elsif ($flag eq "uuml"){
    return "=FC";
  } elsif ($flag eq "Uuml"){
    return "=DC";
  } elsif ($flag eq "auml"){
    return "=E4";
  } elsif ($flag eq "Auml"){
    return "=C4";
  } elsif ($flag eq "ouml"){
    return "=F6";
  } elsif ($flag eq "Ouml"){
    return "=D6";
  } elsif ($flag eq "szlig"){
    return "=DF";
  } elsif ($flag eq "nbsp"){
    return " ";
  } else {
    return "__ this was HTML escape: $flag __";  #  --> syntax error in lat=
ex
  }
} # e_escapes

#----------------------------------------------------------
sub handleTag {

  # special tags

  if ($_[2] eq "C") {                                           # special H=
TML escapes
    flush;
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      push_page $page_ref, "}";
    } else {
      push_page $page_ref, "\\texttt{";
    }
    return;
  }
  if ($_[2] eq "E") {                                           # special H=
TML escapes
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      push_page $page_ref, e_escapes( "@BUFFER");
      @BUFFER =3D ();
    } else {
      flush;
    }
    return;
  }

  # character formatting Tags: handle B I U SUP SUB
  if ($_[2] eq "B"){
    flush;
    return if $verbatim_flag;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\\textbf{";
    } else {
      push_page $page_ref, "}";
    }
    return;
  }

  if ($_[2] eq "I"){
    flush;
    return if $verbatim_flag;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\\textit{";
    } else {
      push_page $page_ref, "}";
    }
    return;
  }

  if ($_[2] eq "U"){
    flush;
    return if $verbatim_flag;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\\underline{";
    } else {
      push_page $page_ref, "}";
    }
    return;
  }

  if ($_[2] eq "SUP"){
    flush;
    return if $verbatim_flag;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\$^{";
    } else {
      push_page $page_ref, "}\$";
    }
    return;
  }

  if ($_[2] eq "SUB"){
    flush;
    return if $verbatim_flag;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\$_{";
    } else {
      push_page $page_ref, "}\$";
    }
    return;
  }

  if ($_[2] eq "PRINT_TOC"){
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\n\\tableofcontents\n\n\\newpage\n";
    }
    return;
  }

  if ($_[2] eq "MBOX"){
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START){
      push_page $page_ref, "\\mbox{";
    } else {
      push_page $page_ref, "}\$";
    }
    return;
  }

  if ($_[2] eq "LINE_BREAK" or $_[2] eq "BR") {                       # lin=
e break
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      @BUFFER =3D ();
      push_page $page_ref, "\\linebreak ";
    } else {
      flush;
    }
    return;
  }
#TODO anpassen; linie malen
  if ($_[2] eq "HR" ) {                       # horizontal line
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      @BUFFER =3D ();
      push_page $page_ref, "\n\n-------------------------------------------=
---------------\n\n";
    } else {
      flush;
    }
    return;
  }
  if ($_[2] eq "BOXCOLORS") {                                          # bo=
x color
    return
  }

  if ($_[2] eq "BOXCOLOR") {                                          # box=
 color
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      $box_bg_color =3D $BUFFER[0];
      @BUFFER =3D ();
    } else {
      flush;
    }
    return;
  }
  if ($_[2] eq "BOXTEXT") {                                          # box =
text color
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      $box_fg_color =3D $BUFFER[0];
      @BUFFER =3D ();
    } else {
      flush;
    }
    return;
  }

#TODO anpassen
  if ($_[2] eq "IMAGE") {                                          # image
    flush;
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'src'}) {
        die "*** ERROR: Image without 'src' parameter\n";
      }
      my $file =3D $_[3]->{'src'};
      my $opt =3D "";
      push_page $page_ref, "\n\n \% cool image from file $file \n\n";
      push_page $page_ref, "\n \\begin{center}\n";
      if ( defined $_[3]->{'epsfysize'}) {
        my $ysize =3D $_[3]->{'epsfysize'};
        push_page $page_ref, "\n\n \\epsfysize=3D$ysize\n";
      }
      if ( defined $_[3]->{'epsfxsize'}) {
        my $xsize =3D $_[3]->{'epsfxsize'};
        push_page $page_ref, "\n\n \\epsfxsize=3D$xsize\n";
      }
      my $ps_file =3D $file;
      $ps_file =3D~ s/\.[^.]*$/.eps/;
      print STDERR " ... image: $ps_file\n";
      if (-e $ps_file) {
        push_page $page_ref, "\n\n\\epsffile{$ps_file}\n\n";
      } else {
        push_page $page_ref, "\n\n (image from file $file) \n\n";
      }
      push_page $page_ref, "\n \\end{center}\n";
    }
    return;
  }

#TODO anpassen
  if ($_[2] eq "F" ) {                       # set color and size
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START){
      my $params =3D "";
      if ( defined $_[3]->{'color'}) {
        $params =3D "$params color=3D$_[3]->{'color'}";
      }
      if ( defined $_[3]->{'size'}) {
        $params =3D "$params size=3D$_[3]->{'size'}";
      }
      push_page $page_ref, "";
    } else {
      push_page $page_ref, "";
    }
    return;
  }

  if ($_[2] eq "A") {                                                # Anch=
or Tag
    flush;
  # print STDERR "@_\n" if $verbose;
  # print STDERR Dumper($_[3]) if $verbose;
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'name'}) {
        die "*** ERROR: Anchor without 'name' parameter\n";
      }
      my $a_name =3D $_[3]->{'name'};
      push_page $page_ref, "\\label{$a_name}";
      # Remember page number for later reference:
      if (defined $ANCHOR{$a_name}){
        warn "**** anchor name $a_name used twice !!\n";
      } else {
        $ANCHOR{$a_name} =3D $page_cnt;
      }
    }
    return;
  }
# TODO: \URL

  if ($_[2] eq "L") {                                                # gene=
ral URL
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'url'}) {
        warn "*** ERROR: Hyperlink \L without 'url' parameter\n";
      }
      my $link_text =3D join("",@BUFFER);

# fix alex!! 2001-04-17

      my $url =3D $_[3]->{'url'};
      push_page $page_ref, "\\PPurl{" . $link_text .  "}{" . escapes($url) =
. "}";
      @BUFFER=3D();

    } else {
	flush;
    }
    return;
  }
  if ($_[2] eq "PAGEREF") {                                          # page=
 reference
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'name'}) {
        warn "*** ERROR: PAGEREF without 'name' parameter\n";
      }
      my $a_name =3D $_[3]->{'name'};
      push_page $page_ref, "\\PPPageref{_INTERNAL_PAGE:$a_name:_END}"; # to=
 be replaced later ...
    } else {
      flush;
    }
    return;
  }
  if ($_[2] eq "SECTIONREF") {                                       # sect=
ion header reference
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'name'}) {
        warn "*** ERROR: PAGEREF without 'name' parameter\n";
      }
      my $a_name =3D $_[3]->{'name'};
      push_page $page_ref, "\\PPSref{_INTERN_SECTION:$a_name:_END}"; # to b=
e replaced later ...
    } else {
      flush;
    }
    return;
  }
  if ($_[2] eq "XREF") {                                       # internal c=
ross reference
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      if ( !defined $_[3]->{'name'}) {
        warn "*** ERROR: XREF without 'name' parameter\n";
      }
      my $ref_text =3D join("",@BUFFER);
      my $a_name =3D $_[3]->{'name'};
      push_page $page_ref, "\\PPXref{$ref_text}{_INTERNAL_XREF:$a_name:_END=
}";
      @BUFFER =3D ();
    } else {
      flush;
    }
    return;
  }

  if ($_[2] eq "X") {                                          # index entry
    if ($_[1]=3D=3DDIRECTIVE_COMPLETE) {
      my $idx =3D join("",@BUFFER);
      $idx_cnt ++;
      my $index_anchor =3D "index:$page_cnt" . ":$idx_cnt";
      $INDEX{$idx} =3D $index_anchor;
      push_page $page_ref, "\\label{$index_anchor}";

      push_page $page_ref, "\\index{$idx}";

      if ( defined $_[3]->{'mode'} and $_[3]->{'mode'} eq "index_only"){
        @BUFFER =3D ();
      }
    } else {
      flush;
    }
    return;
  }

  if ($_[2] eq "TABLE") {                                       # TABLE
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START) {
      my $cols =3D "|c|c|c|c|";
      if ( defined $_[3]->{'columns'}) {
         $cols =3D $_[3]->{'columns'};
      }
      push_page $page_ref, "\n\n\\vspace{1ex}\n\\begin{tabular}{$cols}\n";
      push_page $page_ref, "\\hline\n" unless $OPT{double_lines};
    } else {
      push_page $page_ref, "\n\n\\end{tabular}\n\n";
    }
    return;
  }

  if ($_[2] eq "TABLE_HL") {                                       # TABLE
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START) {
      push_page $page_ref, "\\bf ";
    } else {
      push_page $page_ref, " & "; # &
    }
    return;
  }

  if ($_[2] eq "TABLE_ROW") {                                       # TABLE
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START) {
      push_page $page_ref, "\\hline\n" if $OPT{double_lines};
    } else {
      pop (@$page_ref); # to remove extra '&'
      push_page $page_ref, "\\\\\\hline\n";
    }
    return;
  }

  if ($_[2] eq "TABLE_COL") {                                       # TABLE
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START) {
      push_page $page_ref, "";
    } else {
      push_page $page_ref, " & "; # &
    }
    return;
  }


  if ($_[2] eq "EMBED") {                                       # embeded L=
aTeX
    flush;
    if ($_[1]=3D=3DDIRECTIVE_START) {
      if ( !defined $_[3]->{'lang'}) {
        pp_warn "ERROR: EMBED without 'lang' parameter\n";
      }
      elsif ($_[3]->{'lang'} =3D~ /latex/i){
        $embedded_latex =3D 1;
      }
    } else {
      $embedded_latex =3D 0;
    }
    @BUFFER=3D();
    return;
  }

  if ($_[2] eq 'LOCALTOC') { # ste, ldo
     # act mode dependend - we only need to handle this once, there is no t=
ag body
     if ($_[1]=3D=3DDIRECTIVE_START)
       {
        # get local toc
        my $toc=3D$backend->toc(
                              $backend->currentChapterNr,
                              exists $_[3]->{depth} ? $_[3]->{depth} : 0,
                             );

        # anything found?
        if (@$toc)
          {
           # make it into a list
           push_page $page_ref,  "\n\n\\begin{itemize}\n";
           push_page $page_ref,  '  \\item ', ' ', $_->[1], "\n" for @$toc;
           push_page $page_ref,  "\n\\end{itemize}\n\n";
          }
       }

     # ok, well done
     return;
  }

  warn "**** $me: unkown or not yet implemented tag: $_[2]\n";
} # handleTag

#----------------------------------------------------------
sub handleDocument {
  if ($_[1]=3D=3DDIRECTIVE_START) {
    warn "\n[Info] Document start ($_[2]).\n" if $verbose;

  }
  else {

    warn "\n[Info] Document end ($_[2]).\n" if $verbose;
  }
} # handleDocument

#----------------------------------------------------------
sub flush {
  push_page $page_ref, @BUFFER;
  push @ERRBUFFER, @BUFFER;
  @BUFFER =3D ();
  # trim ERRBUFFER:
  @ERRBUFFER =3D grep (!/^\s*$/ ,@ERRBUFFER);
  for (my $k=3D1;$k<scalar(@ERRBUFFER)-6;$k++){
    shift @ERRBUFFER;
  }
}

#----------------------------------------------------------
sub push_page {
  # push $text to current page buffer
  my ($page_ref, @text) =3D @_;
  push @$page_ref, @text;
} # push_page

#---------------------------------------------------------------
sub save {
    my $it =3D $_[0];
    $it =3D~ y/\000-\177/\200-\377/;
    return $it;
} # save
#----------------------------------------------------------
sub escapes {
  my $line =3D shift;
  return $line if $embedded_latex;
  return $line if $verbatim_flag;
  $line =3D~ s!\334!save('"U')!ge; #"
  $line =3D~ s!\374!save('"u')!ge; #"
  $line =3D~ s!\326!save('"O')!ge; #"
  $line =3D~ s!\366!save('"o')!ge; #"
  $line =3D~ s!\304!save('"A')!ge; #"
  $line =3D~ s!\344!save('"a')!ge; #"
  $line =3D~ s!\337!save('"s')!ge; #"
    $line =3D~ s!\$!save("\\\$")!ge;
    $line =3D~ s!\\!\$\\backslash\$!g;
    $line =3D~ s!&!\\&!g;
    $line =3D~ s!#!\\#!g;
    $line =3D~ s!%!\\%!g;
    $line =3D~ s!~!\\char126!g;
    $line =3D~ s!_!\\_!g;
    $line =3D~ s!\^!\\char94!g;
    $line =3D~ s!{!\\{!g;
    $line =3D~ s!}!\\}!g;
    $line =3D~ s!>!{\\tt>}!g;
    $line =3D~ s!<!{\\tt<}!g;
    $line =3D~ s!"!{\\char34}!g; #'
    $line =3D~ y/\200-\377/\000-\177/;

    return $line;
} #" escapes

#----------------------------------------------------------
sub insert_template {
  my ($f, $page_no, $what) =3D @_;
} # insert_template
#----------------------------------------------------------

#----------------------------------------------------------
sub pp_warn {
  my ($message) =3D @_;
  print STDERR "*** $me: $message\n";
  print STDERR "context: ------\n@ERRBUFFER\n---------------\n";
} # pp_warn


__END__



# =3D POD SECTION =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

=3Dhead1 NAME

B<pp2latex> - PerlPoint to LaTeX converter

=3Dhead1 VERSION

This man page describes $Revision: 1.14 $
from PerlPoint::Converters Package 1.01


=3Dhead1 SYNOPSIS

  pp2latex --help
  pp2latex [@options_file] [options] slide_text=20

=3Dhead1 DESCRIPTION

C<pp2latex> creates a LaTeX file from a PerlPoint input file.


=3Dhead1 SYNTAX of PerlPoint Files

For a detailed description of the PerlPoint language please refer to the
excellent POD documentation of the B<PerlPoint::Parser> Module by Jochen St=
enzel.
There you will find everything you ever wanted to know about PerlPoint ;-)


=3Dhead1 OPTIONS

=3Dover 4

=3Ditem --filter=3Dregexp

This specifies a regular expression C<regexp> which should match
all allowed languages for EMBEDed code. The expression is evaluated
caseinsensitively.

Example: --filter=3D"perl|latex"

=3Ditem --prolog=3Dfilename

Specifies a file which must contain the LaTeX Declarations for the document.
C<\documentclass> and C<\begin{document}> must be defined there.

=3Ditem --activeContents

PerlPoint sources can embed Perl code which is evaluated while the source i=
s parsed. For
reasons of security this feature is deactivated by default. Set this option=
 to active
it. You can use I<--safeOpcode> to fine tune which operations shall be perm=
itted.

=3Ditem --double_lines

This option has the effect that all horizontal Lines in Tables are
doubled.

=3Ditem --cache

parsing of one and the same document several times can be accelerated by ac=
tivating the
PerlPoint parser cache by this option. The performance boost depends on you=
r document
structure.

Cache files are written besides the source and named ".<source file>.ppcach=
e".

It can be useful to (temporarily) deactivate the cache to get correct line =
numbers in
parser error messages (currently numbers cannot always reported correctly w=
ith activated
cache because of a special perl behaviour).

=3Ditem --cacheCleanup

PerlPoint parser cache files grow (with every modified version of a source =
parsed)
because they store expressions for every parsed variant of a paragraph. Thi=
s is usually
uncritical but you may wish to clean up the cache occasionally. Use this op=
tion to
perform the task (or remove the cache file manually).


=3Ditem -nocopyright

suppresses the copyright message;

=3Ditem -noinfo

supresses runtime informations;

=3Ditem --nowarn

supresses warnings;

=3Ditem --quiet

a shortcut for "--nocopyright --noinfo --nowarn": all non critical runtime =
messages are suppressed;

=3Ditem --safeOpcode <opcode>

If active contents is enabled (I<--activeContents>), Perl code embedded int=
o the translated PerlPoint sources will be
evaluated. To keep security this is done via an object of class B<Safe> whi=
ch restricts code
to permitted operations. By this option you can declare which opcode (or op=
code tag) is
permitted. Please see the B<Safe> and B<Opcode> manual pages for further de=
tails. (These modules
come with perl.)

This option can be used multiply.

You may want to store these options in default option files, see below for =
details.


For the examples used in I<ppdoc.pp> you should use

 --safeOpcode=3D:filesys_open --safeOpcode=3D:still_to_be_decided --safeOpc=
ode=3D:browse


=3Ditem --set <flag>

This option allows you to pass certain settings - of your choice - to activ=
e contents
(like conditions) where it can be accessed via the $PerlPoint hash referenc=
e. For
example, your PerlPoint code could contain a condition like

  ? $PerlPoint->{userSettings}{special}

  Special part.

  ? 1

. The special part enclosed by the two conditions would then be processed I=
<only> if you
call C<pp2html> with

  --set special

- and if active contents was enabled by I<-active>, of course.

This option can be used multiply.

=3Ditem --trace [<level>]

activates traces of the specified level. You may use the environment variab=
le SCRIPTDEBUG
alternatively (but an option overwrites environment settings). The followin=
g levels are
defined  (use the I<numeric> values) - if a description sounds cryptic to y=
ou, just ignore
the setting:

=3Ditem --help

Output of usage.

=3Ditem --version

Output of version information.

=3Dback

=3Dhead1 FILES

Configuration file $HOME/.pp2latex

=3Dhead1 ENVIRONMENT

The following environment variables have influence on the program:

=3Dover 4

=3Ditem SCRIPTDEBUG

may be set to a numeric value to activate certain trace levels. You can use=
 option I<-trace>
alternatively (note that a used option overwrites an environment setting). =
The several levels
are described with this option.

=3Dback


=3Dhead1 SEE ALSO

C<pp2html>

=3Dhead1 AUTHOR

Lorenz Domke ([email protected]), 2001. All rights reserved.

=3Dcut


# =3D HISTORY SECTION =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

# --------------------------------------------------------------------------
# version | date   | author | changes
# --------------------------------------------------------------------------
# 0.02    |12.10.99| ste    | added a simple backend;
# 0.01    |09.10.99| ste    | derived from the PP::Parser draft.
# --------------------------------------------------------------------------

$Log: pp2latex,v $
Revision 1.14  2001/12/19 21:04:43  lorenz
Final commit for Version 1.001

Revision 1.13  2001/12/18 22:51:07  lorenz
Checkin for version 1.01

Revision 1.12  2001/12/06 21:38:06  lorenz
more tests

Revision 1.11  2001/11/30 00:46:22  lorenz
new cvs version

Revision 1.10  2001/10/02 08:47:56  lorenz
LOCALTOC

Revision 1.12  2001/08/16 04:06:46  lorenz
checkin for/after 0.11.01

Revision 1.11  2001/06/15 15:56:02  lorenz
ci for Release 0.10 (final)

Revision 1.10  2001/06/14 12:00:56  lorenz
checkin for version 0.10_05

Revision 1.9  2001/03/11 11:55:11  lorenz
checkin for version 0.009

Revision 1.8  2001/03/06 21:21:28  lorenz
checkin for 0.009

Revision 1.7  2001/01/17 22:24:16  lorenz
checkin for version 0.008

Revision 1.6  2000/12/10 22:48:37  lorenz
check in for firest CPAN version

Revision 1.5  2000/11/02 19:37:48  lorenz
checkin for 0.006

Revision 1.4  2000/10/25 20:02:39  lorenz
support eps

Revision 1.3  2000/08/04 19:56:52  lorenz
check

Revision 1.2  2000/08/04 17:29:42  lorenz
sub save

Revision 1.1  2000/07/11 20:02:59  lorenz
Initial revision

Revision 1.1  2000/04/27 21:28:36  lorenz
Initial revision