summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/perltex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/perltex
Initial commit
Diffstat (limited to 'macros/latex/contrib/perltex')
-rw-r--r--macros/latex/contrib/perltex/README55
-rw-r--r--macros/latex/contrib/perltex/perltex.1280
-rw-r--r--macros/latex/contrib/perltex/perltex.dtx3207
-rw-r--r--macros/latex/contrib/perltex/perltex.ins68
-rw-r--r--macros/latex/contrib/perltex/perltex.pdfbin0 -> 333786 bytes
5 files changed, 3610 insertions, 0 deletions
diff --git a/macros/latex/contrib/perltex/README b/macros/latex/contrib/perltex/README
new file mode 100644
index 0000000000..cf6fcdcb5e
--- /dev/null
+++ b/macros/latex/contrib/perltex/README
@@ -0,0 +1,55 @@
+ +------------------------------------+
+ | PERLTEX |
+ | By Scott Pakin, scott+pt@pakin.org |
+ +------------------------------------+
+
+
+Description
+-----------
+
+PerlTeX is a combination Perl script (perltex.pl) and LaTeX2e style
+file (perltex.sty) that, together, give the user the ability to define
+LaTeX macros in terms of Perl code. Once defined, a Perl macro becomes
+indistinguishable from any other LaTeX macro. PerlTeX thereby combines
+LaTeX's typesetting power with Perl's programmability.
+
+
+Installation
+------------
+
+In case it's not obvious, you'll need a Perl installation. Perl is
+freely available and runs on dozens of platforms. See the list of Perl
+binary distributions on CPAN (http://www.cpan.org/ports/index.html).
+
+Execute "latex perltex.ins" to generate perltex.sty and perltex.pl.
+Install perltex.sty in an appropriate directory (e.g.,
+/usr/local/share/texmf/tex/latex/misc or C:\localtexmf\tex\latex\misc).
+perltex.pl is a Perl script. On Unix, you may want to rename it to
+just "perltex" and set execute permissions ("chmod +x perltex"). On
+Windows, you may want to create a batch-file wrapper for it ("pl2bat
+perltex.pl"). In either case, perltex should be installed somewhere in
+your executable path (e.g., /usr/local/bin).
+
+It's not necessary to produce the documentation as PerlTeX comes with
+prebuilt documentation in PDF format (perltex.pdf). However, if you
+want to build the documentation yourself (e.g., to use A4 paper instead
+of U.S. Letter), run "latex perltex.dtx" twice, then "makeindex -s
+gind.ist perltex.idx" and "makeindex -s gglo.ist perltex.glo -o
+perltex.gls", then "latex perltex.dtx" again, then "dvips perltex.dvi
+-o perltex.ps" if you want to produce PostScript.
+
+
+License
+-------
+
+Copyright (C) 2010 Scott Pakin
+
+These files may be distributed and/or modified under the conditions of
+the LaTeX Project Public License, either version 1.3c of this license or
+(at your option) any later version. The latest version of this license
+is in:
+
+ http://www.latex-project.org/lppl.txt
+
+and version 1.3c or later is part of all distributions of LaTeX version
+2006/05/20 or later.
diff --git a/macros/latex/contrib/perltex/perltex.1 b/macros/latex/contrib/perltex/perltex.1
new file mode 100644
index 0000000000..28c0508e68
--- /dev/null
+++ b/macros/latex/contrib/perltex/perltex.1
@@ -0,0 +1,280 @@
+.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.05)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.el \{\
+. de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "PERLTEX 1"
+.TH PERLTEX 1 "2010-07-10" "v2.1" " "
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+perltex \- enable LaTeX macros to be defined in terms of Perl code
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+perltex
+[\fB\-\-help\fR]
+[\fB\-\-latex\fR=\fIprogram\fR]
+[\fB\-\-\fR[\fBno\fR]\fBsafe\fR]
+[\fB\-\-permit\fR=\fIfeature\fR]
+[\fB\-\-makesty\fR]
+[\fIlatex options\fR]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+LaTeX \*(-- through the underlying TeX typesetting system \*(-- produces
+beautifully typeset documents but has a macro language that is
+difficult to program. In particular, support for complex string
+manipulation is largely lacking. Perl is a popular general-purpose
+programming language whose forte is string manipulation. However, it
+has no typesetting capabilities whatsoever.
+.PP
+Clearly, Perl's programmability could complement LaTeX's typesetting
+strengths. \fBperltex\fR is the tool that enables a symbiosis between
+the two systems. All a user needs to do is compile a LaTeX document
+using \fBperltex\fR instead of \fBlatex\fR. (\fBperltex\fR is actually a
+wrapper for \fBlatex\fR, so no \fBlatex\fR functionality is lost.) If the
+document includes a \f(CW\*(C`\eusepackage{perltex}\*(C'\fR in its preamble, then
+\&\f(CW\*(C`\eperlnewcommand\*(C'\fR and \f(CW\*(C`\eperlrenewcommand\*(C'\fR macros will be made
+available. These behave just like LaTeX's \f(CW\*(C`\enewcommand\*(C'\fR and
+\&\f(CW\*(C`\erenewcommand\*(C'\fR except that the macro body contains Perl code instead
+of LaTeX code.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+\&\fBperltex\fR accepts the following command-line options:
+.IP "\fB\-\-help\fR" 4
+.IX Item "--help"
+Display basic usage information.
+.IP "\fB\-\-latex\fR=\fIprogram\fR" 4
+.IX Item "--latex=program"
+Specify a program to use instead of \fBlatex\fR. For example,
+\&\f(CW\*(C`\-\-latex=pdflatex\*(C'\fR would typeset the given document using
+\&\fBpdflatex\fR instead of ordinary \fBlatex\fR.
+.IP "\fB\-\-\fR[\fBno\fR]\fBsafe\fR" 4
+.IX Item "--[no]safe"
+Enable or disable sandboxing. With the default of \fB\-\-safe\fR,
+\&\fBperltex\fR executes the code from a \f(CW\*(C`\eperlnewcommand\*(C'\fR or
+\&\f(CW\*(C`\eperlrenewcommand\*(C'\fR macro within a protected environment that
+prohibits ``unsafe'' operations such as accessing files or executing
+external programs. Specifying \fB\-\-nosafe\fR gives the LaTeX document
+\&\fIcarte blanche\fR to execute any arbitrary Perl code, including that
+which can harm the user's files. See Safe for more information.
+.IP "\fB\-\-permit\fR=\fIfeature\fR" 4
+.IX Item "--permit=feature"
+Permit particular Perl operations to be performed. The \fB\-\-permit\fR
+option, which can be specified more than once on the command line,
+enables finer-grained control over the \fBperltex\fR sandbox. See
+Opcode for more information.
+.IP "\fB\-\-makesty\fR" 4
+.IX Item "--makesty"
+Generate a LaTeX style file called \fInoperltex.sty\fR. Replacing the
+document's \f(CW\*(C`\eusepackage{perltex}\*(C'\fR line with \f(CW\*(C`\eusepackage{noperltex}\*(C'\fR
+produces the same output but does not require PerlTeX, making the
+document suitable for distribution to people who do not have PerlTeX
+installed. The disadvantage is that \fInoperltex.sty\fR is specific to
+the document that produced it. Any changes to the document's PerlTeX
+macro definitions or macro invocations necessitates rerunning
+\&\fBperltex\fR with the \fB\-\-makesty\fR option.
+.PP
+These options are then followed by whatever options are normally
+passed to \fBlatex\fR (or whatever program was specified with
+\&\f(CW\*(C`\-\-latex\*(C'\fR), including, for instance, the name of the \fI.tex\fR file to
+compile.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+In its simplest form, \fBperltex\fR is run just like \fBlatex\fR:
+.PP
+.Vb 1
+\& perltex myfile.tex
+.Ve
+.PP
+To use \fBpdflatex\fR instead of regular \fBlatex\fR, use the \fB\-\-latex\fR
+option:
+.PP
+.Vb 1
+\& perltex \-\-latex=pdflatex myfile.tex
+.Ve
+.PP
+If LaTeX gives a ``\f(CW\*(C`trapped by operation mask\*(C'\fR'' error and you trust
+the \fI.tex\fR file you're trying to compile not to execute malicious
+Perl code (e.g., because you wrote it yourself), you can disable
+\&\fBperltex\fR's safety mechansisms with \fB\-\-nosafe\fR:
+.PP
+.Vb 1
+\& perltex \-\-nosafe myfile.tex
+.Ve
+.PP
+The following command gives documents only \fBperltex\fR's default
+permissions (\f(CW\*(C`:browse\*(C'\fR) plus the ability to open files and invoke the
+\&\f(CW\*(C`time\*(C'\fR command:
+.PP
+.Vb 2
+\& perltex \-\-permit=:browse \-\-permit=:filesys_open
+\& \-\-permit=time myfile.tex
+.Ve
+.SH "ENVIRONMENT"
+.IX Header "ENVIRONMENT"
+\&\fBperltex\fR honors the following environment variables:
+.IP "\s-1PERLTEX\s0" 4
+.IX Item "PERLTEX"
+Specify the filename of the LaTeX compiler. The LaTeX compiler
+defaults to ``\f(CW\*(C`latex\*(C'\fR''. The \f(CW\*(C`PERLTEX\*(C'\fR environment variable
+overrides this default, and the \fB\-\-latex\fR command-line option (see
+\&\*(L"\s-1OPTIONS\s0\*(R") overrides that.
+.SH "FILES"
+.IX Header "FILES"
+While compiling \fIjobname.tex\fR, \fBperltex\fR makes use of the following
+files:
+.IP "\fIjobname.lgpl\fR" 4
+.IX Item "jobname.lgpl"
+log file written by Perl; helpful for debugging Perl macros
+.IP "\fIjobname.topl\fR" 4
+.IX Item "jobname.topl"
+information sent from LaTeX to Perl
+.IP "\fIjobname.frpl\fR" 4
+.IX Item "jobname.frpl"
+information sent from Perl to LaTeX
+.IP "\fIjobname.tfpl\fR" 4
+.IX Item "jobname.tfpl"
+``flag'' file whose existence indicates that \fIjobname.topl\fR contains
+valid data
+.IP "\fIjobname.ffpl\fR" 4
+.IX Item "jobname.ffpl"
+``flag'' file whose existence indicates that \fIjobname.frpl\fR contains
+valid data
+.IP "\fIjobname.dfpl\fR" 4
+.IX Item "jobname.dfpl"
+``flag'' file whose existence indicates that \fIjobname.ffpl\fR has been
+deleted
+.IP "\fInoperltex\-#.tex\fR" 4
+.IX Item "noperltex-#.tex"
+file generated by \fInoperltex.sty\fR for each PerlTeX macro invocation
+.SH "NOTES"
+.IX Header "NOTES"
+\&\fBperltex\fR's sandbox defaults to what Opcode calls ``\f(CW\*(C`:browse\*(C'\fR''.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fIlatex\fR\|(1), \fIpdflatex\fR\|(1), \fIperl\fR\|(1), \fISafe\fR\|(3pm), \fIOpcode\fR\|(3pm)
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Scott Pakin, \fIscott+pt@pakin.org\fR
diff --git a/macros/latex/contrib/perltex/perltex.dtx b/macros/latex/contrib/perltex/perltex.dtx
new file mode 100644
index 0000000000..3f61570dda
--- /dev/null
+++ b/macros/latex/contrib/perltex/perltex.dtx
@@ -0,0 +1,3207 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2010 Scott Pakin <scott+pt@pakin.org>
+% ---------------------------------------------------
+%
+% This file may be distributed and/or modified under the conditions of
+% the LaTeX Project Public License, either version 1.3c of this license
+% or (at your option) any later version. The latest version of this
+% license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3c or later is part of all distributions of LaTeX
+% version 2006/05/20 or later.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{perltex.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+%<package>\ProvidesPackage{perltex}
+%<*package>
+ [2010/07/10 v2.1 LaTeX macros for use with PerlTeX]
+%</package>
+%
+%<*driver>
+\documentclass{ltxdoc}
+\makeatletter
+ \def\plmac@tag{FakingBeingRunFromPerlTeX}
+ \def\plmac@tofile{\jobname.topl}
+ \def\plmac@fromfile{\jobname.frpl}
+ \def\plmac@toflag{\jobname.tfpl}
+ \def\plmac@fromflag{\jobname.ffpl}
+ \def\plmac@doneflag{\jobname.dfpl}
+ \def\plmac@pipe{\jobname.pipe}
+\makeatother
+\usepackage{perltex}
+\usepackage{varioref}
+\usepackage{flafter}
+\usepackage{textcomp}
+\usepackage{graphicx}
+\IfFileExists{hyperref.sty}{%
+ \usepackage{hyperref}
+ \hypersetup{%
+ hyperindex=false,
+ bookmarksopen,
+ pdftitle={PerlTeX: Defining LaTeX macros in terms of Perl code},
+ pdfauthor={Scott Pakin, scott+pt@pakin.org},
+ pdfsubject={Using Perl to define LaTeX macros},
+ pdfkeywords={programming, LaTeX, macros, Perl}
+ }
+}{}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\setcounter{IndexColumns}{2}
+\begin{document}
+ \DocInput{perltex.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \CheckSum{602}
+%
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+%
+%
+% \changes{v1.0}{2003/07/13}{Initial version}
+% \changes{v1.2}{2004/10/07}{Renamed \texttt{perlmacros.sty} to
+% \texttt{perltex.sty} for consistency.}
+%
+% \GetFileInfo{perltex.sty}
+%
+% \DoNotIndex{\$, \', \(, \), \., \\, \{, \}, \^, \", \@}
+% \DoNotIndex{\@empty, \@ifnextchar, \@ifundefined, \@makeother, \@ne}
+% \DoNotIndex{\@permittedops}
+% \DoNotIndex{\A, \active, \advance}
+% \DoNotIndex{\b, \begin, \begingroup, \bgroup, \btrapped}
+% \DoNotIndex{\catcode, \csname}
+% \DoNotIndex{\d, \def, \documentclass}
+% \DoNotIndex{\E, \edef, \egroup, \else, \end, \endcsname, \endgroup}
+% \DoNotIndex{\expandafter}
+% \DoNotIndex{\fi}
+% \DoNotIndex{\gdef, \global}
+% \DoNotIndex{\ifeof, \ifnum, \ifx, \immediate}
+% \DoNotIndex{\let, \loop}
+% \DoNotIndex{\makeatletter, \makeatother, \MessageBreak}
+% \DoNotIndex{\n, \newcommand, \newcount, \newenvironment, \newif}
+% \DoNotIndex{\newread, \newtoks, \newwrite}
+% \DoNotIndex{\noexpand, \number}
+% \DoNotIndex{\obeyspaces}
+% \DoNotIndex{\ProcessOptions, \protect}
+% \DoNotIndex{\Q}
+% \DoNotIndex{\r, \relax, \repeat}
+% \DoNotIndex{\s, \space, \string}
+% \DoNotIndex{\TeX, \the}
+% \DoNotIndex{\W}
+%
+% \newcommand{\indexpkg}[1]{^^A ^^A Index a package name
+% \index{#1=\textsf{#1} (package)}^^A
+% \index{packages>#1=\textsf{#1}}^^A
+% }
+% \newcommand{\pkgname}[1]{^^A ^^A Name of an arbitrary package
+% \textsf{#1}^^A
+% \indexpkg{#1}^^A
+% }
+% \newcommand{\PerlTeX}{Perl\TeX{}} ^^A Name of the complete system
+% \newcommand{\perltex}{\texttt{perltex.pl}} ^^A Name of the Perl script
+% \newcommand{\perlmac}{^^A ^^A Name of the LaTeX package
+% \texttt{perltex.sty}^^A
+% \indexpkg{perltex}^^A
+% }
+% \newcommand{\noperlmac}{\texttt{noperltex.sty}} ^^A Name of the alternate LaTeX package
+% \newcommand{\XeTeX}{^^A ^^A Name of the typesetting system
+% X\lower0.5ex\hbox{\kern-0.15em\reflectbox{E}}\kern-0.1667em\TeX^^A
+% }
+% \newcommand{\signal}[1]{^^A ^^A Signal handler
+% \lowercase{\textsc{sig#1}}^^A
+% \index{SIG#1=\lowercase{\textsc{sig#1}}}^^A
+% }
+%
+% ^^A Typeset package options.
+% \newcommand{\DescribeOption}[1]{^^A
+% \marginpar{\raggedleft\PrintDescribeEnv{#1}}}
+% \newcommand{\pkgoption}[1]{^^A
+% \texttt{#1}^^A
+% \index{#1=\texttt{#1} (package option)}^^A
+% \index{package options>#1=\texttt{#1}}^^A
+% }
+%
+%
+% ^^A Define an environment just like macro but for Perl subroutines
+% \makeatletter
+% \newenvironment{perlsub}{^^A
+% \begingroup
+% \catcode`\_=11
+% \def\PrintMacroName##1{\strut\MacroFont\string##1\ }^^A
+% \def\SpecialIndex@##1##2{^^A
+% \@bsphack
+% \special@index{\string##1\actualchar
+% \string\verb\quotechar*\verbatimchar##1\verbatimchar##2}^^A
+% \@esphack
+% }^^A
+% \begin{macro}^^A
+% }{^^A
+% \end{macro}^^A
+% \endgroup
+% }
+% \makeatother
+%
+% ^^A Define an environment just like macro but for Perl scalars or lists.
+% \makeatletter
+% \newenvironment{perlvar}{^^A
+% \begingroup
+% \catcode`\_=11
+% \def\PrintMacroName##1{\strut\MacroFont\string##1\ }^^A
+% \def\SpecialIndex@##1##2{^^A
+% \@bsphack
+% \special@index{\expandafter\@gobble\string##1\actualchar
+% \string\verb\quotechar*\verbatimchar\string##1\verbatimchar##2}^^A
+% \@esphack
+% }^^A
+% \begin{macro}^^A
+% }{^^A
+% \end{macro}^^A
+% \endgroup
+% }
+% \makeatother
+%
+% \title{\PerlTeX: \\ Defining \LaTeX{} macros in terms of Perl code^^A
+% \thanks{This document corresponds to \PerlTeX~\fileversion, dated
+% \filedate.}}
+% \author{Scott Pakin \\ \texttt{scott+pt@pakin.org}}
+%
+% \maketitle
+% \sloppy
+%
+% \begin{abstract}
+% \PerlTeX{} is a combination Perl script (\perltex) and \LaTeXe{}
+% style file (\perlmac) that, together, give the user the ability to
+% define \LaTeX{} macros in terms of Perl code. Once defined, a Perl
+% macro becomes indistinguishable from any other \LaTeX{} macro.
+% \PerlTeX{} thereby combines \LaTeX's typesetting power with Perl's
+% programmability.
+% \end{abstract}
+%
+% \section{Introduction}
+%
+% \TeX{} is a professional-quality typesetting system. However, its
+% programming language is rather hard to use for anything but the most
+% simple forms of text substitution. Even \LaTeX, the most popular
+% macro package for \TeX, does little to simplify \TeX{} programming.
+%
+% Perl is a general-purpose programming language whose forte is in text
+% manipulation. However, it has no support whatsoever for typesetting.
+%
+% \PerlTeX's goal is to bridge these two worlds. It enables the
+% construction of documents that are primarily \LaTeX-based but contain
+% a modicum of Perl. \PerlTeX{} seamlessly integrates Perl code into a
+% \LaTeX{} document, enabling the user to define macros whose bodies
+% consist of Perl code instead of \TeX{} and \LaTeX{} code.
+%
+% As an example, suppose you need to define a macro that reverses a set
+% of words. Although it sounds like it should be simple, few \LaTeX{}
+% authors are sufficiently versed in the \TeX{} language to be able to
+% express such a macro. However, a word-reversal function is easy to
+% express in Perl: one need only |split| a string into a list of words,
+% |reverse| the list, and |join| it back together. The following is how
+% a |\reversewords| macro could be defined using \PerlTeX:
+%
+% \begin{verbatim}
+% \perlnewcommand{\reversewords}[1]{join " ", reverse split " ", $_[0]}
+% \end{verbatim}
+%
+% \noindent
+% Then, executing ``\texttt{\string\reversewords\string{Try doing this
+% without Perl!\string}}'' in a document would produce the text ``Perl!
+% without this doing Try''. Simple, isn't it?
+%
+% As another example, think about how you'd write a macro in \LaTeX{} to
+% extract a substring of a given string when provided with a starting
+% position and a length. Perl has an built-in |substr| function and
+% \PerlTeX{} makes it easy to export this to \LaTeX:
+%
+% \begin{verbatim}
+% \perlnewcommand{\substr}[3]{substr $_[0], $_[1], $_[2]}
+% \end{verbatim}
+%
+% |\substr| can then be used just like any other \LaTeX{} macro---and as
+% simply as Perl's |substr| function:
+%
+% \bigskip
+%
+% \noindent| |^^A
+% \begin{tabular}{@{}l@{}}
+% |\newcommand{\str}{superlative}| \\
+% |A sample substring of ``\str'' is ``\substr{\str}{2}{4}''.| \\[1ex]
+% \multicolumn{1}{@{}c@{}}{\Huge$\Downarrow$} \\[2ex]
+% \multicolumn{1}{@{}c@{}}{A sample substring of ``superlative'' is ``perl''.}
+% \end{tabular}
+%
+% \bigskip
+%
+% To present a somewhat more complex example, observe how much
+% easier it is to generate a repetitive matrix using Perl code than
+% ordinary \LaTeX{} commands:
+%
+% \begin{verbatim}
+% \perlnewcommand{\hilbertmatrix}[1]{
+% my $result = '
+% \[
+% \renewcommand{\arraystretch}{1.3}
+% ';
+% $result .= '\begin{array}{' . 'c' x $_[0] . "}\n";
+% foreach $j (0 .. $_[0]-1) {
+% my @row;
+% foreach $i (0 .. $_[0]-1) {
+% push @row, ($i+$j) ? (sprintf '\frac{1}{%d}', $i+$j+1) : '1';
+% }
+% $result .= join (' & ', @row) . " \\\\\n";
+% }
+% $result .= '\end{array}
+% \]';
+% return $result;
+% }
+%
+% \hilbertmatrix{20}
+% \end{verbatim}
+%
+% \begin{center}
+% {\Huge$\Downarrow$}
+% \end{center}
+%
+% \[
+% \renewcommand{\arraystretch}{1.3}
+% \begin{array}{ccccccccccccccc}
+% 1 & \frac{1}{2} & \frac{1}{3} & \frac{1}{4} & \frac{1}{5} & \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} \\
+% \frac{1}{2} & \frac{1}{3} & \frac{1}{4} & \frac{1}{5} & \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} \\
+% \frac{1}{3} & \frac{1}{4} & \frac{1}{5} & \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} \\
+% \frac{1}{4} & \frac{1}{5} & \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} \\
+% \frac{1}{5} & \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} \\
+% \frac{1}{6} & \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} \\
+% \frac{1}{7} & \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} \\
+% \frac{1}{8} & \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} \\
+% \frac{1}{9} & \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} \\
+% \frac{1}{10} & \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} \\
+% \frac{1}{11} & \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} & \frac{1}{25} \\
+% \frac{1}{12} & \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} & \frac{1}{25} & \frac{1}{26} \\
+% \frac{1}{13} & \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} & \frac{1}{25} & \frac{1}{26} & \frac{1}{27} \\
+% \frac{1}{14} & \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} & \frac{1}{25} & \frac{1}{26} & \frac{1}{27} & \frac{1}{28} \\
+% \frac{1}{15} & \frac{1}{16} & \frac{1}{17} & \frac{1}{18} & \frac{1}{19} & \frac{1}{20} & \frac{1}{21} & \frac{1}{22} & \frac{1}{23} & \frac{1}{24} & \frac{1}{25} & \frac{1}{26} & \frac{1}{27} & \frac{1}{28} & \frac{1}{29} \\
+% \end{array}
+% \]
+%
+% \bigskip
+%
+% In addition to |\perlnewcommand| and |\perlrenewcommand|, \PerlTeX{}
+% supports |\perlnewenvironment| and |\perlrenewenvironment| macros.
+% These enable environments to be defined using Perl code. The
+% following example, a |spreadsheet| environment, generates a |tabular|
+% environment plus a predefined header row. This example would have
+% been much more difficult to implement without \PerlTeX:
+%
+% \begin{verbatim}
+% \newcounter{ssrow}
+% \perlnewenvironment{spreadsheet}[1]{
+% my $cols = $_[0];
+% my $header = "A";
+% my $tabular = "\\setcounter{ssrow}{1}\n";
+% $tabular .= '\newcommand*{\rownum}{\thessrow\addtocounter{ssrow}{1}}' . "\n";
+% $tabular .= '\begin{tabular}{@{}r|*{' . $cols . '}{r}@{}}' . "\n";
+% $tabular .= '\\multicolumn{1}{@{}c}{} &' . "\n";
+% foreach (1 .. $cols) {
+% $tabular .= "\\multicolumn{1}{c";
+% $tabular .= '@{}' if $_ == $cols;
+% $tabular .= "}{" . $header++ . "}";
+% if ($_ == $cols) {
+% $tabular .= " \\\\ \\cline{2-" . ($cols+1) . "}"
+% }
+% else {
+% $tabular .= " &";
+% }
+% $tabular .= "\n";
+% }
+% return $tabular;
+% }{
+% return "\\end{tabular}\n";
+% }
+%
+% \begin{center}
+% \begin{spreadsheet}{4}
+% \rownum & 1 & 8 & 10 & 15 \\
+% \rownum & 12 & 13 & 3 & 6 \\
+% \rownum & 7 & 2 & 16 & 9 \\
+% \rownum & 14 & 11 & 5 & 4
+% \end{spreadsheet}
+% \end{center}
+% \end{verbatim}
+%
+% \begin{center}
+% {\Huge$\Downarrow$}
+% \end{center}
+%
+% \DeleteShortVerb{\|}
+% \begin{center}
+% \begin{tabular}{@{}r|*{4}{r}@{}}
+% \multicolumn{1}{@{}c}{} &
+% \multicolumn{1}{c}{A} &
+% \multicolumn{1}{c}{B} &
+% \multicolumn{1}{c}{C} &
+% \multicolumn{1}{c@{}}{D} \\ \cline{2-5}
+% 1 & 1 & 8 & 10 & 15 \\
+% 2 & 12 & 13 & 3 & 6 \\
+% 3 & 7 & 2 & 16 & 9 \\
+% 4 & 14 & 11 & 5 & 4
+% \end{tabular}
+% \end{center}
+% \MakeShortVerb{\|}
+%
+%
+% \section{Usage}
+%
+% There are two components to using \PerlTeX\@. First, documents must
+% include a ``|\usepackage{perltex}|'' line in their preamble in
+% order to define |\perlnewcommand|, |\perlrenewcommand|,
+% |\perlnewenvironment|, and |\perlrenewenvironment|. Second, \LaTeX{}
+% documents must be compiled using the \perltex{} wrapper script.
+%
+% \subsection{Defining and redefining Perl macros}
+%
+% \DescribeMacro{\perlnewcommand}
+% \DescribeMacro{\perlrenewcommand}
+% \DescribeMacro{\perlnewenvironment}
+% \DescribeMacro{\perlrenewenvironment}
+% \DescribeMacro{\perldo}
+% \perlmac{} defines five macros: |\perlnewcommand|,
+% |\perlrenewcommand|, |\perlnewenvironment|, |\perlrenewenvironment|,
+% and |\perldo|. The first four of these behave exactly like their
+% \LaTeXe{} counterparts---|\newcommand|, |\renewcommand|,
+% |\newenvironment|, and |\renewenvironment|---except that the macro
+% body consists of Perl code that dynamically generates \LaTeX{} code.
+% \perlmac{} even includes support for optional arguments and the
+% starred forms of its commands (i.e.~|\perlnewcommand*|,
+% |\perlrenewcommand*|, |\perlnewenvironment*|, and
+% |\perlrenewenvironment*|). |\perldo| immediately executes a block of
+% Perl code without (re)defining any macros or environments.
+%
+% A \PerlTeX-defined macro or environments is converted to a Perl
+% subroutine named after the macro/environment but beginning with
+% ``|latex_|''. For example, a \PerlTeX-defined \LaTeX{} macro called
+% |\myMacro| internally produces a Perl subroutine called
+% |latex_myMacro|. Macro arguments are converted to subroutine
+% arguments. A \LaTeX{} macro's |#1| argument is referred to as |$_[0]|
+% in Perl; |#2| is referred to as |$_[1]|; and so forth.
+%
+% Any valid Perl code can be used in the body of a macro. However,
+% \PerlTeX{} executes the Perl code within a secure sandbox. This means
+% that potentially harmful Perl operations, such as |unlink|, |rmdir|,
+% and |system| will result in a run-time error. (It is possible to
+% disable the safety checks, however, as is explained in
+% Section~\ref{sec:perltex-man}.) Having a secure sandbox implies that
+% it is safe to build \PerlTeX{} documents written by other people
+% without worrying about what they may do to your computer system.
+%
+% A single sandbox is used for the entire |latex| run. This means that
+% multiple macros defined by |\perlnewcommand| can invoke each other.
+% It also means that global variables persist across macro calls:
+%
+% \bigskip
+%
+% \noindent| |^^A
+% \begin{tabular}{@{}l@{}}
+% |\perlnewcommand{\setX}[1]{$x = $_[0]; return ""}| \\
+% |\perlnewcommand{\getX}{'$x$ was set to ' . $x . '.'}| \\
+% |\setX{123}| \\
+% |\getX| \\
+% |\setX{456}| \\
+% |\getX| \\
+% |\perldo{$x = 789}| \\
+% |\getX| \\[1ex]
+% \multicolumn{1}{@{}c@{}}{\Huge$\Downarrow$} \\[2ex]
+% \multicolumn{1}{@{}c@{}}{^^A
+% $x$ was set to 123. $x$ was set to 456. $x$ was set to 789.^^A
+% } \\
+% \end{tabular}
+%
+% \bigskip
+%
+% Macro arguments are expanded by \LaTeX{} before being passed to Perl.
+% Consider the following macro definition, which wraps its argument
+% within |\begin{verbatim*}|\dots\linebreak[0]|\end{verbatim*}|:
+%
+% \begin{verbatim}
+% \perlnewcommand{\verbit}[1]{
+% "\\begin{verbatim*}\n$_[0]\n\\end{verbatim*}\n"
+% }
+% \end{verbatim}
+%
+% \noindent
+% An invocation of
+% ``|\verbit{\TeX}|'' would therefore typeset the \emph{expansion} of
+% ``|\TeX|'', namely ``|T\kern| |-.1667em\lower| |.5ex\hbox| |{E}\kern|
+% |-.125emX\spacefactor| |\@m|'', which might be a bit unexpected. The
+% solution is to use |\noexpand|:
+% |\verbit{\noexpand\TeX}|~$\Rightarrow$ |\TeX|\@. ``Robust'' macros as
+% well as |\begin| and |\end| are implicitly preceded by |\noexpand|.
+%
+%
+% \subsection{Making \perltex\ optional}
+% \label{sec:perltex-opt}
+%
+% Normally, \perlmac\ issues a \texttt{Document must be compiled using
+% perltex} error if a document specifies |\usepackage{perltex}| but is
+% not compiled using \perltex. However, sometimes \PerlTeX\ may be
+% needed merely to enhance a document's formatting without being
+% mandatory for compiling the document. For such cases, the
+% \DescribeOption{optional}
+% \pkgoption{optional} package option instructs \perlmac\ only to note
+% that \texttt{Document was compiled without using the perltex script}
+% without aborting the compilation.
+% \DescribeMacro{\ifperl}
+% The author can then use the |\ifperl| macro to test if \perltex\ is
+% being used and, if not, provide alternative definitions for macros and
+% environments defined with |\perlnewcommand| and |\perlnewenvironment|.
+%
+% See Section~\ref{sec:complete-example} for a large \PerlTeX\ example
+% that uses \pkgoption{optional} and |\ifperl| to define an environment
+% one way if \perltex\ is detected and another way if not. The text
+% preceding the example also shows how to enable a document to compile
+% even if \perlmac\ is not even installed.
+%
+%
+% \subsection{Invoking \perltex}
+% \label{sec:perltex-man}
+%
+% The following pages reproduce the \perltex{} program documentation.
+% Key parts of the documentation are excerpted when \perltex{} is
+% invoked with the |--help| option. The various Perl
+% |pod2|\meta{something} tools can be used to generate the complete
+% program documentation in a variety of formats such as \LaTeX, HTML,
+% plain text, or Unix man-page format. For example, the following
+% command is the recommended way to produce a Unix man page from
+% \perltex:
+%
+% \enlargethispage{4ex}
+% \begin{verbatim}
+% pod2man --center=" " --release=" " perltex.pl > perltex.1
+% \end{verbatim}
+%
+% \clearpage
+% \begingroup
+% \def\index#1{}
+% \def\section#1{}
+% \let\subsection=\subsubsection
+%
+% ^^A ***************************************************************
+% ^^A * The following was generated using pod2latex and touched up *
+% ^^A * slightly to make it better match the rest of this document. *
+% ^^A ***************************************************************
+%
+% \def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}}
+% \def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}}
+% \setlength{\parindent}{0pt}
+%
+% \section{PERLTEX.PL}%
+% \index{PERLTEX.PL}
+%
+% \subsection*{NAME}
+% perltex --- enable \LaTeX{} macros to be defined in terms of Perl code
+%
+% \subsection*{SYNOPSIS}
+% perltex
+% [\textbf{--help}]
+% [\textbf{--latex}=\textit{program}]
+% [\textbf{--}[\textbf{no}]\textbf{safe}]
+% [\textbf{--permit}=\textit{feature}]
+% [\textbf{--makesty}]
+% [\textit{latex options}]
+%
+% \subsection*{DESCRIPTION}
+% \LaTeX---through the underlying \TeX{} typesetting system---produces
+% beautifully typeset documents but has a macro language that is
+% difficult to program. In particular, support for complex string
+% manipulation is largely lacking. Perl is a popular general-purpose
+% programming language whose forte is string manipulation. However, it
+% has no typesetting capabilities whatsoever.
+%
+% \bigskip
+%
+% Clearly, Perl's programmability could complement \LaTeX's typesetting
+% strengths. \textbf{perltex} is the tool that enables a symbiosis
+% between the two systems. All a user needs to do is compile a \LaTeX\
+% document using \textbf{perltex} instead of \textbf{latex}.
+% (\textbf{perltex} is actually a wrapper for \textbf{latex}, so no
+% \textbf{latex} functionality is lost.) If the document includes a
+% \texttt{\string\usepackage\{perltex\}} in its preamble, then
+% \texttt{\string\perlnewcommand} and \texttt{\string\perlrenewcommand}
+% macros will be made available. These behave just like \LaTeX's
+% \texttt{\string\newcommand} and \texttt{\string\renewcommand} except
+% that the macro body contains Perl code instead of \LaTeX\ code.
+%
+% \subsection*{OPTIONS}%
+% \index{OPTIONS}
+%
+% {\bf perltex} accepts the following command-line options:
+%
+% \begin{description}
+%
+%
+% \item[{\textbf{-{}-help}}] \mbox{}
+%
+% Display basic usage information.
+%
+%
+% \item[{\textbf{-{}-latex}=\textit{program}}] \mbox{}
+%
+% Specify a program to use instead of \textbf{latex}. For example,
+% \texttt{--latex=pdflatex} would typeset the given document using
+% \textbf{pdflatex} instead of ordinary \textbf{latex}.
+%
+%
+% \item[{\textbf{-{}-}[\textbf{no}]\textbf{safe}}] \mbox{}
+%
+% Enable or disable sandboxing. With the default of \textbf{-{}-safe},
+% \textbf{perltex} executes the code from a
+% \texttt{\string\perlnewcommand} or \texttt{\string\perlrenewcommand}
+% macro within a protected environment that prohibits ``unsafe''
+% operations such as accessing files or executing external programs.
+% Specifying \textbf{-{}-nosafe} gives the \LaTeX\ document \textit{carte
+% blanche} to execute any arbitrary Perl code, including that which can
+% harm the user's files. See \emph{Safe} for more information.
+%
+% \item[{\textbf{-{}-permit}=\textit{feature}}] \mbox{}
+%
+% Permit particular Perl operations to be performed. The
+% \textbf{-{}-permit} option, which can be specified more than once on
+% the command line, enables finer-grained control over the
+% \textbf{perltex} sandbox. See \emph{Opcode} for more information.
+%
+%
+% \item[{\textbf{-{}-makesty}}] \mbox{}
+%
+% Generate a \LaTeX\ style file called \emph{noperltex.sty}. Replacing
+% the document's \texttt{\string\usepackage\{perltex\}} line with
+% \texttt{\string\usepackage\{noperltex\}} produces the same output
+% but does not require \PerlTeX, making the document suitable for
+% distribution to people who do not have \PerlTeX\ installed. The
+% disadvantage is that \emph{noperltex.sty} is specific to the document
+% that produced it. Any changes to the document's \PerlTeX\ macro
+% definitions or macro invocations necessitates rerunning
+% \textbf{perltex} with the \textbf{-{}-makesty} option.
+%
+% \end{description}
+%
+% These options are then followed by whatever options are normally
+% passed to \textbf{latex} (or whatever program was specified with
+% \texttt{--latex}), including, for instance, the name of the
+% \emph{.tex} file to compile.
+%
+% \subsection*{EXAMPLES}
+%
+% In its simplest form, \textbf{perltex} is run just like \textbf{latex}:
+%
+% \begin{verbatim}
+% perltex myfile.tex
+% \end{verbatim}
+%
+%
+% To use \textbf{pdflatex} instead of regular \textbf{latex}, use the
+% \textbf{-{}-latex} option:
+%
+% \begin{verbatim}
+% perltex --latex=pdflatex myfile.tex
+% \end{verbatim}
+%
+%
+% If \LaTeX\ gives a ``\texttt{trapped by operation mask}'' error and
+% you trust the \emph{.tex} file you're trying to compile not to execute
+% malicious Perl code (e.g., because you wrote it yourself), you can
+% disable \textbf{perltex}'s safety mechansisms with
+% \textbf{-{}-nosafe}:
+%
+% \begin{verbatim}
+% perltex --nosafe myfile.tex
+% \end{verbatim}
+%
+%
+% The following command gives documents only \textbf{perltex}'s default
+% permissions (\texttt{:browse}) plus the ability to open files and invoke the
+% \texttt{time} command:
+%
+% \begin{verbatim}
+% perltex --permit=:browse --permit=:filesys_open
+% --permit=time myfile.tex
+% \end{verbatim}
+%
+%
+% \subsection*{ENVIRONMENT}
+%
+% \textbf{perltex} honors the following environment variables:
+%
+% \begin{description}
+%
+% \item[{PERLTEX}] \mbox{}
+%
+% Specify the filename of the \LaTeX\ compiler. The \LaTeX\ compiler
+% defaults to ``\texttt{latex}''. The \texttt{PERLTEX} environment
+% variable overrides this default, and the \textbf{-{}-latex}
+% command-line option (see \textsf{OPTIONS}) overrides that.
+%
+% \end{description}
+%
+%
+% \subsection*{FILES}
+%
+% While compiling \emph{jobname.tex}, \textbf{perltex} makes use of the
+% following files:
+%
+% \begin{description}
+%
+% \item[{\emph{jobname.lgpl}}] \mbox{}
+%
+% log file written by Perl; helpful for debugging Perl macros
+%
+%
+% \item[{\emph{jobname.topl}}] \mbox{}
+%
+% information sent from \LaTeX\ to Perl
+%
+%
+% \item[{\emph{jobname.frpl}}] \mbox{}
+%
+% information sent from Perl to \LaTeX\
+%
+%
+% \item[{\emph{jobname.tfpl}}] \mbox{}
+%
+% ``flag'' file whose existence indicates that \emph{jobname.topl} contains
+% valid data
+%
+%
+% \item[{\emph{jobname.ffpl}}] \mbox{}
+%
+% ``flag'' file whose existence indicates that \emph{jobname.frpl} contains
+% valid data
+%
+%
+% \item[{\emph{jobname.dfpl}}] \mbox{}
+%
+% ``flag'' file whose existence indicates that \emph{jobname.ffpl} has been
+% deleted
+%
+%
+% \item[{\emph{noperltex-\#.tex}}] \mbox{}
+%
+% file generated by \emph{noperltex.sty} for each \PerlTeX\ macro invocation
+%
+% \end{description}
+%
+%
+% \subsection*{NOTES}
+%
+% \textbf{perltex}'s sandbox defaults to what \emph{Opcode} calls
+% ``\texttt{:browse}''.
+%
+%
+% \subsection*{SEE ALSO}
+%
+% latex(1), pdflatex(1), perl(1), Safe(3pm), Opcode(3pm)
+%
+%
+% \subsection*{AUTHOR}
+%
+% Scott Pakin, \textit{scott+pt@pakin.org}
+%
+%
+% ^^A ***********************************
+% ^^A * End of generated pod2latex text *
+% ^^A ***********************************
+% \endgroup
+% \clearpage
+%
+%
+% \subsection{A large, complete example}
+% \label{sec:complete-example}
+%
+% Suppose we want to define a |linkwords| environment that exhibits the
+% following characteristics:
+%
+% \begin{enumerate}
+% \item All words that appear within the environment's body are
+% automatically hyperlinked to a given URL that incorporates the
+% lowercase version of the word somewhere within that URL\@.
+%
+% \item The environment accepts an optional list of stop~words that
+% should not be hyperlinked.
+%
+% \item Paragraph breaks, nested environments, and other
+% \LaTeX\ markup are allowed within the environment's body.
+% \end{enumerate}
+%
+% Because of the reliance on text manipulation (parsing the
+% environment's body into words, comparing each word against the list of
+% stop~words, distinguishing between text and \LaTeX\ markup, etc.),
+% these requirements would be difficult to meet without \PerlTeX\@.
+%
+% We use three packages to help define the |linkwords| environment:
+% \pkgname{perltex} for text manipulation, \pkgname{hyperref} for
+% creating hyperlinks, and \pkgname{environ} for gathering up the body
+% of an environment and passing it as an argument to a macro. Most of
+% the work is performed by the \PerlTeX\ macro |\dolinkwords|, which
+% takes three arguments: a URL template that contains ``|\%s|'' as a
+% placeholder for a word from the text, a mandatory but possibly empty
+% space-separated list of lowercase stop~words, and the input text to
+% process. |\dolinkwords| first replaces all sequences of the form
+% |\|\meta{letters}, |\begin{|\meta{letters}|}|, or
+% |\end{|\meta{letters}|}| with dummy alphanumerics but remembers which
+% dummy sequence corresponds with each original \LaTeX\ sequence. The
+% macro then iterates over each word in the input text, formatting each
+% non-stop-word using the URL template. Contractions (words containing
+% apostrophes) are ignored. Finally, |\dolinkwords| replaces the dummy
+% sequences with the corresponding \LaTeX\ text and returns the result.
+%
+% The |linkwords| environment itself is defined using the |\NewEnviron|
+% macro from the \pkgname{environ} package. With |\NewEnviron|'s help,
+% |linkwords| accumulates its body into a |\BODY| macro and passes that
+% plus the URL template and the optional list of stop~words to
+% |\dolinkwords|.
+%
+% As an added bonus,
+% |\ifperl|\dots\linebreak[0]|\else|\dots\linebreak[0]|\fi| is used to
+% surround the definition of the |\dolinkwords| macro and |linkwords|
+% environment. If the document is not run through \perltex, |linkwords|
+% is defined as a do-nothing environment that simply typesets its body
+% as~is. Note that \perlmac\ is loaded with the \pkgoption{optional}
+% option to indicate that the document can compile without \perltex.
+% However, the user still needs \perlmac\ to avoid getting a
+% \texttt{File `perltex.sty' not found} error from \LaTeX\@. To produce
+% a document that can compile even without \perlmac\ installed, replace
+% the |\usepackage[optional]{perltex}| line with the following
+% \LaTeX\ code:
+%
+% \begin{samepage}
+% \begin{verbatim}
+% \IfFileExists{perltex.sty}
+% {\usepackage[optional]{perltex}}
+% {\newif\ifperl}
+% \end{verbatim}
+% \end{samepage}
+%
+% A complete \LaTeX\ document is presented below. This document, which
+% includes the definition and a use of the |linkwords| environment, can be
+% extracted from the \PerlTeX\ source code into a file called
+% |example.tex| by running
+%
+% \begin{verbatim}
+% tex perltex.ins
+% \end{verbatim}
+%
+% In the following listing, line numbers are suffixed with ``X'' to
+% distinguish them from line numbers associated with \PerlTeX's source
+% code.
+%
+% \bigskip
+%
+% ^^A We want the doc package to number and index the lines in our
+% ^^A code listing, but we want to keep line numbers and index entries
+% ^^A distinct from those of the PerlTeX package code. The following
+% ^^A machinations temporarily append an "X" to line numbers in the
+% ^^A code listing and in the index.
+% \makeatletter
+% \let\theOldCodelineNo=\theCodelineNo
+% \def\theCodelineNo{\reset@font\scriptsize \arabic{CodelineNo}X}
+% \def\appendX#1{#1X}
+% \def\codeline@wrindex@ex#1{\if@filesw
+% \immediate\write\@indexfile
+% {\string\indexentry{#1\encapchar appendX}^^A
+% {\number\c@CodelineNo}}\fi}
+% \ifcodeline@index
+% \let\special@index=\codeline@wrindex@ex
+% \fi
+% \makeatother
+% \iffalse
+%<*example>
+% \fi
+%
+% \begin{macrocode}
+\documentclass{article}
+\usepackage[optional]{perltex}
+\usepackage{environ}
+\usepackage{hyperref}
+
+\ifperl
+
+ \perlnewcommand{\dolinkwords}[3]{
+ # Preprocess our arguments.
+ $url = $_[0];
+ $url =~ s/\\\%s/\%s/g;
+ %stopwords = map {lc $_ => 1} split " ", $_[1];
+ $stopwords{""} = 1;
+ $text = $_[2];
+
+ # Replace LaTeX code in the text with placeholders.
+ $placeholder = "ABCxyz123";
+ %substs = ();
+ $replace = sub {$substs{$placeholder} = $_[0]; $placeholder++};
+ $text =~ s/\\(begin|end)\s+\{[a-z]+\}/$replace->($&)/gse;
+ $text =~ s/\\[a-z]+/$replace->($&)/gse;
+
+ # Hyperlink each word that's not in the stop list.
+ $newtext = "";
+ foreach $word (split /((?<=[-\A\s])[\'a-z]+\b)/i, $text) {
+ $lcword = lc $word;
+ if (defined $stopwords{$lcword} || $lcword =~ /[^a-z]/) {
+ $newtext .= $word;
+ }
+ else {
+ $newtext .= sprintf "\\href{$url}{%s}", $lcword, $word;
+ }
+ }
+
+ # Restore original text from placeholders and return the new text.
+ while (($tag, $orig) = each %substs) {
+ $newtext =~ s/\Q$tag\E/$orig/gs;
+ }
+ return $newtext;
+ }
+
+ \NewEnviron{linkwords}[2][]{\dolinkwords{#2}{#1}{\BODY}}{}
+
+\else
+
+ \newenvironment{linkwords}[2][]{}{}
+
+\fi
+
+\begin{document}
+
+\newcommand{\stopwords}{a an the of in am and or but i we me you us them}
+
+\begin{linkwords}[\stopwords]{http://www.google.com/search?q=define:\%s}
+\begin{verse}
+ I'm very good at integral and differential calculus; \\
+ I know the scientific names of beings animalculous: \\
+ In short, in matters vegetable, animal, and mineral, \\
+ I am the very model of a modern Major-General.
+\end{verse}
+\end{linkwords}
+
+\end{document}
+% \end{macrocode}
+%
+% \iffalse
+%</example>
+% \fi
+% \makeatletter
+% \ifcodeline@index
+% \let\special@index=\codeline@wrindex
+% \fi
+% \let\theCodelineNo=\theOldCodelineNo
+% \makeatother
+%
+%
+% \StopEventually{^^A
+% \section{License agreement}
+% \label{sec:license}
+%
+% Copyright \textcopyright{} 2010 Scott Pakin \texttt{<scott+pt@pakin.org>}
+%
+% \providecommand{\url}[1]{\texttt{##1}}
+%
+% \bigskip
+% \noindent
+% These files may be distributed and/or modified under the conditions of
+% the \LaTeX{} Project Public License, either version~1.3c of this
+% license or (at your option) any later version. The latest version of
+% this license is in \url{http://www.latex-project.org/lppl.txt} and
+% version~1.3c or later is part of all distributions of \LaTeX{} version
+% 2006/05/20 or later.
+%
+%
+% \section*{Acknowledgments}
+% \label{sec:acknowledgments}
+%
+% Thanks to Andrew Mertz for writing the first draft of the code that
+% produces the \PerlTeX-free \noperlmac\ style file and for testing the
+% final draft; to Andrei Alexandrescu for providing a few bug fixes; to
+% Nick Andrewes for identifying and helping diagnose a problem running
+% \PerlTeX\ with \XeTeX\ and to Jonathan Kew for suggesting a
+% workaround; and to Linus K\"allberg for reporting and helping diagnose
+% some problems with running \PerlTeX\ on Windows. Also, thanks to the
+% many people who have sent me fan mail or submitted bug reports,
+% documentation corrections, or feature requests. (The
+% \texttt{\string\perldo} macro and the \texttt{--makesty} option were
+% particularly popular requests.)
+%
+% \PrintChanges
+% \PrintIndex
+% }
+%
+% \section{Implementation}
+% \label{sec:implementation}
+%
+% Users interested only in \emph{using} \PerlTeX{} can skip
+% Section~\ref{sec:implementation}, which presents the complete
+% \PerlTeX{} source code. This section should be of interest primarily
+% to those who wish to extend \PerlTeX{} or modify it to use a language
+% other than Perl.
+%
+% Section~\ref{sec:implementation} is split into two main parts.
+% Section~\ref{sec:perlmacros} presents the source code for \perlmac,
+% the \LaTeX{} side of \PerlTeX, and Section~\ref{sec:perltex} presents
+% the source code for \perltex, the Perl side of \PerlTeX\@.
+% \makeatletter
+% \@ifundefined{perlmaclines}{}{^^A
+% \newcount\perltex@lines
+% \perltex@lines=\perltexlines
+% \advance\perltex@lines by -\perlmaclines
+% In toto, \PerlTeX{} consists of a relatively small amount of code.
+% \perlmac{} is only \perlmaclines{} lines of \LaTeX{} and \perltex{}
+% is only \the\perltex@lines{} lines of Perl.
+% }
+% \makeatother
+% \perltex{} is fairly straightforward Perl code and shouldn't be too
+% difficult to understand by anyone comfortable with Perl programming.
+% \perlmac, in contrast, contains a bit of \LaTeX{} trickery and is
+% probably impenetrable to anyone who hasn't already tried his hand at
+% \LaTeX{} programming. Fortunately for the reader, the code is
+% profusely commented so the aspiring \LaTeX{} guru may yet learn
+% something from it.
+%
+% After documenting the \perlmac{} and \perltex{} source code, a few
+% suggestions are provided for porting \PerlTeX{} to use a backend
+% language other than Perl (Section~\ref{sec:porting}).
+%
+% \subsection{\perlmac}
+% \label{sec:perlmacros}
+%
+% \iffalse
+%<*package>
+% \fi
+%
+% Although I've written a number of \LaTeX{} packages, \perlmac{} was
+% the most challenging to date. The key things I needed to learn how to
+% do include the following:
+%
+% \begin{enumerate}
+% \item storing brace-matched---but otherwise not valid \LaTeX---code
+% for later use
+%
+% \item iterating over a macro's arguments
+% \end{enumerate}
+%
+% Storing non-\LaTeX{} code in a variable involves beginning a group in
+% an argumentless macro, fiddling with category codes, using
+% |\afterassignment| to specify a continuation function, and storing the
+% subsequent brace-delimited tokens in the input stream into a token
+% register. The continuation function, which also takes no arguments,
+% ends the group begun in the first function and proceeds using the
+% correctly |\catcode|d token register. This technique appears in
+% |\plmac@haveargs| and |\plmac@havecode| and in a simpler form
+% (i.e.,~without the need for storing the argument) in
+% |\plmac@write@perl| and |\plmac@write@perl@i|.
+%
+% Iterating over a macro's arguments is hindered by \TeX's requirement
+% that ``|#|'' be followed by a number or another ``|#|''. The
+% technique I discovered (which is used by the Texinfo source code) is
+% first to |\let| a variable be |\relax|, thereby making it
+% unexpandable, then to define a macro that uses that variable followed
+% by a loop variable, and finally to expand the loop variable and |\let|
+% the |\relax|ed variable be ``|#|'' right before invoking the macro.
+% This technique appears in |\plmac@havecode|.
+%
+% I hope you find reading the \perlmac{} source code instructive.
+% Writing it certainly was.
+%
+%
+% \subsubsection{Package initialization}
+% \label{sec:package-init}
+%
+% \begin{macro}{\ifplmac@required}
+% \begin{macro}{\plmac@requiredtrue}
+% \begin{macro}{\plmac@requiredfalse}
+% The |optional| package option lets an author specify that the document
+% can be built successfully even without \PerlTeX\@. Typically, this
+% means that the document uses |\ifperl| to help define
+% reduced-functionality equivalents of any document-defined
+% \PerlTeX\ macros and environments. When |optional| is not specified,
+% \perlmac\ issues an error message if the document is compiled without
+% using \perltex. When |optional| is specified, \perlmac\ suppresses
+% the error message.
+% \changes{v1.8}{2009/03/26}{Introduced an \texttt{optional} package
+% option to suppress the ``must be compiled using perltex'' error
+% message}
+% \begin{macrocode}
+\newif\ifplmac@required \plmac@requiredtrue
+\DeclareOption{optional}{\plmac@requiredfalse} \ProcessOptions\relax
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \PerlTeX{} defines six macros that are used for communication between
+% Perl and \LaTeX\@. |\plmac@tag| is a string of characters that should
+% never occur within one of the user's macro names, macro arguments, or
+% macro bodies. \perltex{} therefore defines |\plmac@tag| as a long
+% string of random uppercase letters. |\plmac@tofile| is the name of a
+% file used for communication from \LaTeX{} to Perl. |\plmac@fromfile|
+% is the name of a file used for communication from Perl to \LaTeX.
+% |\plmac@toflag| signals that |\plmac@tofile| can be read safely.
+% |\plmac@fromflag| signals that |\plmac@fromfile| can be read safely.
+% |\plmac@doneflag| signals that |\plmac@fromflag| has been deleted.
+% Table~\ref{tbl:variables} lists all of these variables along with the
+% value assigned to each by \perltex.
+%
+% \begin{table}[htbp]
+% \centering
+% \caption{Variables used for communication between Perl and \LaTeX}
+% \label{tbl:variables}
+% \begin{tabular}{@{}lll@{}}
+% \hline
+% Variable & Purpose & \perltex{} assignment \\
+% \hline
+%
+% |\plmac@tag| & |\plmac@tofile| field separator &
+% (20 random letters) \\
+%
+% |\plmac@tofile| & \LaTeX{} $\rightarrow$ Perl communication &
+% |\jobname.topl| \\
+%
+% |\plmac@fromfile| & Perl $\rightarrow$ \LaTeX{} communication &
+% |\jobname.frpl| \\
+%
+% |\plmac@toflag| & |\plmac@tofile| synchronization &
+% |\jobname.tfpl| \\
+%
+% |\plmac@fromflag| & |\plmac@fromfile| synchronization &
+% |\jobname.ffpl| \\
+%
+% |\plmac@doneflag| & |\plmac@fromflag| synchronization &
+% |\jobname.dfpl| \\
+%
+% \hline
+% \end{tabular}
+% \end{table}
+%
+% \begin{macro}{\ifperl}
+% \begin{macro}{\perltrue}
+% \begin{macro}{\perlfalse}
+% The following block of code checks the existence of each of the
+% variables listed in Table~\ref{tbl:variables} plus |\plmac@pipe|, a
+% Unix named pipe used for to improve performance. If any variable is
+% not defined, \perlmac{} gives an error message and---as we shall see
+% on page~\pageref{page:define-dummies}---defines dummy versions of
+% |\perl|[|re|]|newcommand| and |\perl|[|re|]|newenvironment|.
+% \begin{macrocode}
+\newif\ifperl
+\perltrue
+\@ifundefined{plmac@tag}{\perlfalse}{}
+\@ifundefined{plmac@tofile}{\perlfalse}{}
+\@ifundefined{plmac@fromfile}{\perlfalse}{}
+\@ifundefined{plmac@toflag}{\perlfalse}{}
+\@ifundefined{plmac@fromflag}{\perlfalse}{}
+\@ifundefined{plmac@doneflag}{\perlfalse}{}
+\@ifundefined{plmac@pipe}{\perlfalse}{}
+\ifperl
+\else
+ \ifplmac@required
+ \PackageError{perltex}{Document must be compiled using perltex}
+ {Instead of compiling your document directly with latex, you need
+ to\MessageBreak use the perltex script. \space perltex sets up
+ a variety of macros needed by\MessageBreak the perltex
+ package as well as a listener process needed for\MessageBreak
+ communication between LaTeX and Perl.}
+ \else
+ \bgroup
+ \obeyspaces
+ \typeout{perltex: Document was compiled without using the perltex script;}
+ \typeout{ it may not print as desired.}
+ \egroup
+ \fi
+\fi
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Defining Perl macros}
+% \label{sec:perl-mac}
+%
+% \PerlTeX{} defines five macros intended to be called by the author.
+% Section~\ref{sec:perl-mac} details the implementation of two of them:
+% |\perlnewcommand| and |\perlrenewcommand|.
+% (Section~\ref{sec:perl-env} details the implementation of the next
+% two, |\perlnewenvironment| and |\perlrenewenvironment|; and,
+% Section~\ref{sec:perl-run} details the implementation of the final
+% macro, |\perldo|.) The goal is for these two macros to behave
+% \emph{exactly} like |\newcommand| and |\renewcommand|, respectively,
+% except that the author macros they in turn define have Perl bodies
+% instead of \LaTeX{} bodies.
+%
+% The sequence of the operations defined in this section is as follows:
+%
+% \begin{enumerate}
+% \item The user invokes |\perl|[|re|]|newcommand|, which stores
+% |\|[|re|]|newcommand| in |\plmac@command|. The
+% |\perl|[|re|]|newcommand| macro then invokes |\plmac@newcommand@i|
+% with a first argument of ``|*|'' for |\perl|[|re|]|newcommand*| or
+% ``|!|'' for ordinary |\perl|[|re|]|newcommand|.
+%
+% \item |\plmac@newcommand@i| defines |\plmac@starchar| as ``|*|'' if
+% it was passed a ``|*|'' or \meta{empty} if it was passed a ``|!|''.
+% It then stores the name of the user's macro in |\plmac@macname|, a
+% |\write|able version of the name in |\plmac@cleaned@macname|, and
+% the macro's previous definition (needed by |\perlrenewcommand|) in
+% |\plmac@oldbody|. Finally, |\plmac@newcommand@i| invokes
+% |\plmac@newcommand@ii|.
+%
+% \item |\plmac@newcommand@ii| stores the number of arguments to the
+% user's macro (which may be zero) in |\plmac@numargs|. It then
+% invokes |\plmac@newcommand@iii@opt| if the first argument is
+% supposed to be optional or |\plmac@newcommand@iii@no@opt| if all
+% arguments are supposed to be required.
+%
+% \item |\plmac@newcommand@iii@opt| defines |\plmac@defarg| as the
+% default value of the optional argument.
+% |\plmac@newcommand@iii@no@opt| defines it as \meta{empty}. Both
+% functions then call |\plmac@haveargs|.
+%
+% \item |\plmac@haveargs| stores the user's macro body (written in
+% Perl) verbatim in |\plmac@perlcode|. |\plmac@haveargs| then invokes
+% |\plmac@havecode|.
+%
+% \item By the time |\plmac@havecode| is invoked all of the
+% information needed to define the user's macro is available. Before
+% defining a \LaTeX{} macro, however, |\plmac@havecode| invokes
+% |\plmac@write@perl| to tell \perltex{} to define a Perl subroutine
+% with a name based on |\plmac@cleaned@macname| and the code contained
+% in |\plmac@perlcode|. Figure~\ref{fig:tofile-define} illustrates
+% the data that |\plmac@write@perl| passes to \perltex.
+%
+% \begin{figure}[htbp]
+% \centering
+% \DeleteShortVerb\|
+% \begin{tabular}{|l|}
+% \hline
+% \verb|DEF| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|\plmac@cleaned@macname| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|\plmac@perlcode| \\ \hline
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{Data written to \texttt{\string\plmac@tofile} to define a
+% Perl subroutine}
+% \label{fig:tofile-define}
+% \end{figure}
+%
+% \item |\plmac@havecode| invokes |\newcommand| or |\renewcommand|, as
+% appropriate, defining the user's macro as a call to
+% |\plmac@write@perl|. An invocation of the user's \LaTeX{} macro
+% causes |\plmac@write@perl| to pass the information shown in
+% Figure~\ref{fig:tofile-use} to \perltex.
+%
+% \begin{figure}[htbp]
+% \centering
+% \DeleteShortVerb\|
+% \begin{tabular}{|l|}
+% \hline
+% \verb|USE| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|\plmac@cleaned@macname| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|#1| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|#2| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|#3| \\ \hline
+% \multicolumn{1}{c}{$\vdots$} \\ \hline
+% \verb|#|\meta{last} \\ \hline
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{Data written to \texttt{\string\plmac@tofile} to invoke a
+% Perl subroutine}
+% \label{fig:tofile-use}
+% \end{figure}
+%
+% \item Whenever |\plmac@write@perl| is invoked it writes its argument
+% verbatim to |\plmac@tofile|; \perltex{} evaluates the code and
+% writes |\plmac@fromfile|; finally, |\plmac@write@perl| |\input|s
+% |\plmac@fromfile|.
+% \end{enumerate}
+%
+% An example might help distinguish the myriad macros used internally by
+% \perlmac. Consider the following call made by the user's
+% document:\label{text:example-cmd}
+%
+% \begin{center}
+% |\perlnewcommand*{\example}[3][frobozz]{join("---", @_)}|
+% \end{center}
+%
+% \noindent
+% Table~\ref{tbl:example-cmd} shows how \perlmac{} parses that command
+% into its constituent components and which components are bound to
+% which \perlmac{} macros.
+%
+% \begin{table}[htbp]
+% \centering
+% \caption{Macro assignments corresponding to an sample
+% \texttt{\string\perlnewcommand*}}
+% \label{tbl:example-cmd}
+% \begin{tabular}{@{}lll@{}}
+% \hline
+% Macro & \multicolumn{2}{l@{}}{Sample definition} \\
+% \hline
+% |\plmac@command| & |\newcommand| \\
+% |\plmac@starchar| & |*| \\
+% |\plmac@macname| & |\example| \\
+% |\plmac@cleaned@macname| & |\example| & (catcode~11) \\
+% |\plmac@oldbody| & |\relax| & (presumably) \\
+% |\plmac@numargs| & |3| \\
+% |\plmac@defarg| & |frobozz| \\
+% |\plmac@perlcode| & |join("---", @_)| & (catcode~11) \\
+% \hline
+% \end{tabular}
+% \end{table}
+%
+% \bigskip
+%
+% \begin{macro}{\perlnewcommand}
+% \begin{macro}{\perlrenewcommand}
+% \begin{macro}{\plmac@command}
+% \begin{macro}{\plmac@next}
+% |\perlnewcommand| and |\perlrenewcommand| are the first two commands
+% exported to the user by \perlmac. |\perlnewcommand| is analogous to
+% |\newcommand| except that the macro body consists of Perl code instead
+% of \LaTeX{} code. Likewise, |\perlrenewcommand| is analogous to
+% |\renewcommand| except that the macro body consists of Perl code
+% instead of \LaTeX{} code. |\perlnewcommand| and |\perlrenewcommand|
+% merely define |\plmac@command| and |\plmac@next| and invoke
+% |\plmac@newcommand@i|.
+% \begin{macrocode}
+\def\perlnewcommand{%
+ \let\plmac@command=\newcommand
+ \let\plmac@next=\relax
+ \@ifnextchar*{\plmac@newcommand@i}{\plmac@newcommand@i!}%
+}
+% \end{macrocode}
+% \begin{macrocode}
+\def\perlrenewcommand{%
+ \let\plmac@next=\relax
+ \let\plmac@command=\renewcommand
+ \@ifnextchar*{\plmac@newcommand@i}{\plmac@newcommand@i!}%
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@newcommand@i}
+% \begin{macro}{\plmac@starchar}
+% \begin{macro}{\plmac@macname}
+% \begin{macro}{\plmac@oldbody}
+% \begin{macro}{\plmac@cleaned@macname}
+% If\label{page:newcommand-i} the user invoked
+% |\perl|[|re|]|newcommand*| then |\plmac@newcommand@i| is passed a
+% ``|*|'' and, in turn, defines |\plmac@starchar| as ``|*|''. If the
+% user invoked |\perl|[|re|]|newcommand| (no ``|*|'') then
+% |\plmac@newcommand@i| is passed a ``|!|'' and, in turn, defines
+% |\plmac@starchar| as \meta{empty}. In either case,
+% |\plmac@newcommand@i| defines |\plmac@macname| as the name of the
+% user's macro, |\plmac@cleaned@macname| as a |\write|able
+% (i.e.,~category code~11) version of |\plmac@macname|, and
+% |\plmac@oldbody| and the previous definition of the user's macro.
+% (|\plmac@oldbody| is needed by |\perlrenewcommand|.) It then invokes
+% |\plmac@newcommand@ii|.
+% \begin{macrocode}
+\def\plmac@newcommand@i#1#2{%
+ \ifx#1*%
+ \def\plmac@starchar{*}%
+ \else
+ \def\plmac@starchar{}%
+ \fi
+ \def\plmac@macname{#2}%
+ \let\plmac@oldbody=#2\relax
+ \expandafter\def\expandafter\plmac@cleaned@macname\expandafter{%
+ \expandafter\string\plmac@macname}%
+ \@ifnextchar[{\plmac@newcommand@ii}{\plmac@newcommand@ii[0]}%]
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@newcommand@ii}
+% \begin{macro}{\plmac@numargs}
+% |\plmac@newcommand@i| invokes |\plmac@newcommand@ii| with the number
+% of arguments to the user's macro in brackets. |\plmac@newcommand@ii|
+% stores that number in |\plmac@numargs| and invokes
+% |\plmac@newcommand@iii@opt| if the first argument is to be optional or
+% |\plmac@newcommand@iii@no@opt| if all arguments are to be mandatory.
+% \begin{macrocode}
+\def\plmac@newcommand@ii[#1]{%
+ \def\plmac@numargs{#1}%
+ \@ifnextchar[{\plmac@newcommand@iii@opt}
+ {\plmac@newcommand@iii@no@opt}%]
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@newcommand@iii@opt}
+% \begin{macro}{\plmac@newcommand@iii@no@opt}
+% \begin{macro}{\plmac@defarg}
+% Only one of these two macros is executed per invocation of
+% |\perl|[|re|]|newcommand|, depending on whether or not the first
+% argument of the user's macro is an optional argument.
+% |\plmac@newcommand@iii@opt| is invoked if the argument is optional.
+% It defines |\plmac@defarg| to the default value of the optional
+% argument. |\plmac@newcommand@iii@no@opt| is invoked if all arguments
+% are mandatory. It defines |\plmac@defarg| as |\relax|. Both
+% |\plmac@newcommand@iii@opt| and |\plmac@newcommand@iii@no@opt| then
+% invoke |\plmac@haveargs|.
+% \begin{macrocode}
+\def\plmac@newcommand@iii@opt[#1]{%
+ \def\plmac@defarg{#1}%
+ \plmac@haveargs
+}
+% \end{macrocode}
+% \begin{macrocode}
+\def\plmac@newcommand@iii@no@opt{%
+ \let\plmac@defarg=\relax
+ \plmac@haveargs
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@perlcode}
+% \begin{macro}{\plmac@haveargs}
+% Now things start to get tricky. We have all of the arguments we need
+% to define the user's command so all that's left is to grab the macro
+% body. But there's a catch: Valid Perl code is unlikely to be valid
+% \LaTeX{} code. We therefore have to read the macro body in a
+% |\verb|-like mode. Furthermore, we actually need to \emph{store} the
+% macro body in a variable, as we don't need it right away.
+%
+% The approach we take in |\plmac@haveargs| is as follows. First, we
+% give all ``special'' characters category code~12 (``other''). We then
+% indicate that the carriage return character (control-M) marks the end
+% of a line and that curly braces retain their normal meaning. With the
+% aforementioned category-code definitions, we now have to store the
+% next curly-brace-delimited fragment of text, end the current group to
+% reset all category codes to their previous value, and continue
+% processing the user's macro definition. How do we do that? The
+% answer is to assign the upcoming text fragment to a token register
+% (|\plmac@perlcode|) while an |\afterassignment| is in effect. The
+% |\afterassignment| causes control to transfer to |\plmac@havecode|
+% right after |\plmac@perlcode| receives the macro body with all of the
+% ``special'' characters made impotent.
+% \begin{macrocode}
+\newtoks\plmac@perlcode
+% \end{macrocode}
+% \begin{macrocode}
+\def\plmac@haveargs{%
+ \begingroup
+ \let\do\@makeother\dospecials
+ \catcode`\^^M=\active
+ \newlinechar`\^^M
+ \endlinechar=`\^^M
+ \catcode`\{=1
+ \catcode`\}=2
+ \afterassignment\plmac@havecode
+ \global\plmac@perlcode
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% Control is transfered to |\plmac@havecode| from |\plmac@haveargs|
+% right after the user's macro body is assigned to |\plmac@perlcode|.
+% We now have everything we need to define the user's macro. The goal
+% is to define it as ``|\plmac@write@perl{|\meta{contents of
+% Figure~\ref{fig:tofile-use}}|}|''. This is easier said than done
+% because the number of arguments in the user's macro is not known
+% statically, yet we need to iterate over however many arguments there
+% are. Because of this complexity, we will explain |\plmac@perlcode|
+% piece-by-piece.
+%
+% \begin{macro}{\plmac@sep}
+% Define a character to separate each of the items presented in
+% Figures~\ref{fig:tofile-define} and~\ref{fig:tofile-use}. Perl will
+% need to strip this off each argument. For convenience in porting to
+% languages with less powerful string manipulation than Perl's, we
+% define |\plmac@sep| as a carriage-return character of category code~11
+% (``letter'').
+% \begin{macrocode}
+{\catcode`\^^M=11\gdef\plmac@sep{^^M}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@argnum}
+% Define a loop variable that will iterate from |1| to the number of
+% arguments in the user's function, i.e.,~|\plmac@numargs|.
+% \begin{macrocode}
+\newcount\plmac@argnum
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@havecode}
+% Now comes the final piece of what started as a call to
+% |\perl|[|re|]|newcommand|. First, to reset all category codes back to
+% normal, |\plmac@havecode| ends the group that was begun in
+% |\plmac@haveargs|.
+% \changes{v1.1}{2004/02/24}{Added a \texttt{\string\string\string\plmac@next}
+% hook to support \PerlTeX's new environment-defining macros}
+% \begin{macrocode}
+\def\plmac@havecode{%
+ \endgroup
+% \end{macrocode}
+%
+% \begin{macro}{\plmac@define@sub}
+% We invoke |\plmac@write@perl| to define a Perl subroutine named after
+% |\plmac@cleaned@macname|. |\plmac@define@sub| sends Perl the
+% information shown in Figure~\vref{fig:tofile-define}.
+% \begin{macrocode}
+ \edef\plmac@define@sub{%
+ \noexpand\plmac@write@perl{DEF\plmac@sep
+ \plmac@tag\plmac@sep
+ \plmac@cleaned@macname\plmac@sep
+ \plmac@tag\plmac@sep
+ \the\plmac@perlcode
+ }%
+ }%
+ \plmac@define@sub
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@body}
+% The rest of |\plmac@havecode| is preparation for defining the user's
+% macro. (\LaTeXe's |\newcommand| or |\renewcommand| will do the actual
+% work, though.) |\plmac@body| will eventually contain the complete
+% (\LaTeX) body of the user's macro. Here, we initialize it to the
+% first three items listed in Figure~\vref{fig:tofile-use} (with
+% intervening |\plmac@sep|s).
+% \begin{macrocode}
+ \edef\plmac@body{%
+ USE\plmac@sep
+ \plmac@tag\plmac@sep
+ \plmac@cleaned@macname
+ }%
+% \end{macrocode}
+%
+% \begin{macro}{\plmac@hash}
+% Now, for each argument |#1|, |#2|,~\dots, |#\plmac@numargs| we append
+% a |\plmac@tag| plus the argument to |\plmac@body| (as always, with a
+% |\plmac@sep| after each item). This requires more trickery, as \TeX{}
+% requires a macro-parameter character (``|#|'') to be followed by a
+% literal number, not a variable. The approach we take, which I first
+% discovered in the Texinfo source code (although it's used by \LaTeX{}
+% and probably other \TeX-based systems as well), is to |\let|-bind
+% |\plmac@hash| to |\relax|. This makes |\plmac@hash| unexpandable, and
+% because it's not a ``|#|'', \TeX{} doesn't complain. After
+% |\plmac@body| has been extended to include |\plmac@hash1|,
+% |\plmac@hash2|,~\dots, |\plmac@hash\plmac@numargs|, we then
+% |\let|-bind |\plmac@hash| to |##|, which \TeX{} lets us do because
+% we're within a macro definition (|\plmac@havecode|). |\plmac@body|
+% will then contain |#1|, |#2|,~\dots, |#\plmac@numargs|, as desired.
+% \begin{macrocode}
+ \let\plmac@hash=\relax
+ \plmac@argnum=\@ne
+ \loop
+ \ifnum\plmac@numargs<\plmac@argnum
+ \else
+ \edef\plmac@body{%
+ \plmac@body\plmac@sep\plmac@tag\plmac@sep
+ \plmac@hash\plmac@hash\number\plmac@argnum}%
+ \advance\plmac@argnum by \@ne
+ \repeat
+ \let\plmac@hash=##%
+% \end{macrocode}
+%
+% \begin{macro}{\plmac@define@command}
+% We're ready to execute a |\|[|re|]|newcommand|. Because we need to
+% expand many of our variables, we |\edef| |\plmac@define@command| to
+% the appropriate |\|[|re|]|newcommand| call, which we will soon
+% execute. The user's macro must first be |\let|-bound to |\relax| to
+% prevent it from expanding. Then, we handle two cases: either all
+% arguments are mandatory (and |\plmac@defarg| is |\relax|) or the
+% user's macro has an optional argument (with default value
+% |\plmac@defarg|).
+% \begin{macrocode}
+ \expandafter\let\plmac@macname=\relax
+ \ifx\plmac@defarg\relax
+ \edef\plmac@define@command{%
+ \noexpand\plmac@command\plmac@starchar{\plmac@macname}%
+ [\plmac@numargs]{%
+ \noexpand\plmac@write@perl{\plmac@body}%
+ }%
+ }%
+ \else
+ \edef\plmac@define@command{%
+ \noexpand\plmac@command\plmac@starchar{\plmac@macname}%
+ [\plmac@numargs][\plmac@defarg]{%
+ \noexpand\plmac@write@perl{\plmac@body}%
+ }%
+ }%
+ \fi
+% \end{macrocode}
+%
+% The final steps are to restore the previous definition of the user's
+% macro---we had set it to |\relax| above to make the name
+% unexpandable---then redefine it by invoking |\plmac@define@command|.
+% Why do we need to restore the previous definition if we're just going
+% to redefine it? Because |\newcommand| needs to produce an error if
+% the macro was previously defined and |\renewcommand| needs to produce
+% an error if the macro was \emph{not} previously defined.
+%
+% |\plmac@havecode| concludes by invoking |\plmac@next|, which is a
+% no-op for |\perlnewcommand| and |\perlrenewcommand| but processes the
+% end-environment code for |\perlnewenvironment| and
+% |\perlrenewenvironment|.
+% \begin{macrocode}
+ \expandafter\let\plmac@macname=\plmac@oldbody
+ \plmac@define@command
+ \plmac@next
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Defining Perl environments}
+% \label{sec:perl-env}
+%
+% \changes{v1.1}{2004/02/24}{Added new
+% \texttt{\string\string\string\perlnewenvironment} and
+% \texttt{\string\string\string\perlrenewenvironment} macros}
+%
+% Section~\ref{sec:perl-mac} detailed the implementation of
+% |\perlnewcommand| and |\perlrenewcommand|. Section~\ref{sec:perl-env}
+% does likewise for |\perlnewenvironment| and |\perlrenewenvironment|,
+% which are the Perl-bodied analogues of |\newenvironment| and
+% |\renewenvironment|. This section is significantly shorter than the
+% previous because |\perlnewenvironment| and |\perlrenewenvironment| are
+% largely built atop the macros already defined in
+% Section~\ref{sec:perl-mac}.
+%
+% \begin{macro}{\perlnewenvironment}
+% \begin{macro}{\perlrenewenvironment}
+% \begin{macro}{\plmac@command}
+% \begin{macro}{\plmac@next}
+% |\perlnewenvironment| and |\perlrenewenvironment| are the remaining
+% two commands exported to the user by \perlmac. |\perlnewenvironment|
+% is analogous to |\newenvironment| except that the macro body consists
+% of Perl code instead of \LaTeX{} code. Likewise,
+% |\perlrenewenvironment| is analogous to |\renewenvironment| except
+% that the macro body consists of Perl code instead of \LaTeX{} code.
+% |\perlnewenvironment| and |\perlrenewenvironment| merely define
+% |\plmac@command| and |\plmac@next| and invoke
+% |\plmac@newenvironment@i|.
+%
+% The significance of |\plmac@next| (which was let-bound to |\relax| for
+% |\perl|[|re|]|newcommand| but is let-bound to |\plmac@end@environment|
+% here) is that a \LaTeX{} environment definition is really two macro
+% definitions: |\|\meta{name} and |\end|\meta{name}. Because we want to
+% reuse as much code as possible the idea is to define the ``begin''
+% code as one macro, then inject---by way of |plmac@next|---a call to
+% |\plmac@end@environment|, which defines the ``end'' code as a second
+% macro.
+% \begin{macrocode}
+\def\perlnewenvironment{%
+ \let\plmac@command=\newcommand
+ \let\plmac@next=\plmac@end@environment
+ \@ifnextchar*{\plmac@newenvironment@i}{\plmac@newenvironment@i!}%
+}
+% \end{macrocode}
+% \begin{macrocode}
+\def\perlrenewenvironment{%
+ \let\plmac@command=\renewcommand
+ \let\plmac@next=\plmac@end@environment
+ \@ifnextchar*{\plmac@newenvironment@i}{\plmac@newenvironment@i!}%
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@newenvironment@i}
+% \begin{macro}{\plmac@starchar}
+% \begin{macro}{\plmac@envname}
+% \begin{macro}{\plmac@macname}
+% \begin{macro}{\plmac@oldbody}
+% \begin{macro}{\plmac@cleaned@macname}
+% The |\plmac@newenvironment@i| macro is analogous to
+% |\plmac@newcommand@i|; see the description of
+% |\plmac@newcommand@i|~\vpageref{page:newcommand-i} to understand the
+% basic structure. The primary difference is that the environment name
+% (|#2|) is just text, not a control sequence. We store this text in
+% |\plmac@envname| to facilitate generating the names of the two macros
+% that constitute an environment definition. Note that there is no
+% |\plmac@newenvironment@ii|; control passes instead to
+% |\plmac@newcommand@ii|.
+% \begin{macrocode}
+\def\plmac@newenvironment@i#1#2{%
+ \ifx#1*%
+ \def\plmac@starchar{*}%
+ \else
+ \def\plmac@starchar{}%
+ \fi
+ \def\plmac@envname{#2}%
+ \expandafter\def\expandafter\plmac@macname\expandafter{\csname#2\endcsname}%
+ \expandafter\let\expandafter\plmac@oldbody\plmac@macname\relax
+ \expandafter\def\expandafter\plmac@cleaned@macname\expandafter{%
+ \expandafter\string\plmac@macname}%
+ \@ifnextchar[{\plmac@newcommand@ii}{\plmac@newcommand@ii[0]}%]
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@end@environment}
+% \begin{macro}{\plmac@next}
+% \begin{macro}{\plmac@macname}
+% \begin{macro}{\plmac@oldbody}
+% \begin{macro}{\plmac@cleaned@macname}
+% Recall that an environment definition is a shortcut for two macro
+% definitions: |\|\meta{name} and |\end|\meta{name} (where \meta{name}
+% was stored in |\plmac@envname| by |\plmac@newenvironment@i|). After
+% defining |\|\meta{name}, |\plmac@havecode| transfers control to
+% |\plmac@end@environment| because |\plmac@next| was let-bound to
+% |\plmac@end@environment| in |\perl|[|re|]|newenvironment|.
+%
+% |\plmac@end@environment|'s purpose is to define |\end|\meta{name}.
+% This is a little tricky, however, because \LaTeX's
+% |\|[|re|]|newcommand| refuses to (re)define a macro whose name begins
+% with ``|end|''. The solution that |\plmac@end@environment| takes is
+% first to define a |\plmac@end@macro| macro then (in |plmac@next|)
+% let-bind |\end|\meta{name} to it. Other than that,
+% |\plmac@end@environment| is a combined and simplified version of
+% |\perlnewenvironment|, |\perlrenewenvironment|, and
+% |\plmac@newenvironment@i|.
+% \begin{macrocode}
+\def\plmac@end@environment{%
+ \expandafter\def\expandafter\plmac@next\expandafter{\expandafter
+ \let\csname end\plmac@envname\endcsname=\plmac@end@macro
+ \let\plmac@next=\relax
+ }%
+ \def\plmac@macname{\plmac@end@macro}%
+ \expandafter\let\expandafter\plmac@oldbody\csname end\plmac@envname\endcsname
+ \expandafter\def\expandafter\plmac@cleaned@macname\expandafter{%
+ \expandafter\string\plmac@macname}%
+ \@ifnextchar[{\plmac@newcommand@ii}{\plmac@newcommand@ii[0]}%]
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Executing top-level Perl code}
+% \label{sec:perl-run}
+%
+% The macros defined in Sections~\ref{sec:perl-mac}
+% and~\ref{sec:perl-env} enable an author to inject subroutines into the
+% Perl sandbox. The final \PerlTeX\ macro, |\perldo|, instructs the
+% Perl sandbox to execute a block of code outside of all subroutines.
+% |\perldo|'s implementation is much simpler than that of the other
+% author macros because |\perldo| does not have to process subroutine
+% arguments. Figure~\ref{fig:tofile-run} illustrates the data that gets
+% written to |plmac@tofile| (indirectly) by |\perldo|.
+%
+% \begin{figure}[htbp]
+% \centering
+% \DeleteShortVerb\|
+% \begin{tabular}{|l|}
+% \hline
+% \verb|RUN| \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \textit{Ignored} \\ \hline
+% \verb|\plmac@tag| \\ \hline
+% \verb|\plmac@perlcode| \\ \hline
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{Data written to \texttt{\string\plmac@tofile} to execute
+% Perl code}
+% \label{fig:tofile-run}
+% \end{figure}
+%
+%
+% \begin{macro}{\perldo}
+% Execute a block of Perl code and pass the result to \LaTeX\ for
+% further processing. This code is nearly identical to that of
+% Section~\ref{sec:perl-mac}'s |\plmac@haveargs| but ends by invoking
+% |\plmac@have@run@code| instead of |\plmac@havecode|.
+% \changes{v1.3}{2006/06/23}{Introduced \texttt{\string\string\string\perldo}
+% to support code execution outside of all subroutines.}
+% \begin{macrocode}
+\def\perldo{%
+ \begingroup
+ \let\do\@makeother\dospecials
+ \catcode`\^^M=\active
+ \newlinechar`\^^M
+ \endlinechar=`\^^M
+ \catcode`\{=1
+ \catcode`\}=2
+ \afterassignment\plmac@have@run@code
+ \global\plmac@perlcode
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@have@run@code}
+% \begin{macro}{\plmac@run@code}
+% Pass a block of code to Perl to execute. |\plmac@have@run@code| is
+% identical to |\plmac@havecode| but specifies the |RUN| tag instead of
+% the |DEF| tag.
+% \changes{v1.3}{2006/06/23}{Added to assist
+% \texttt{\string\string\string\perldo}}
+% \begin{macrocode}
+\def\plmac@have@run@code{%
+ \endgroup
+ \edef\plmac@run@code{%
+ \noexpand\plmac@write@perl{RUN\plmac@sep
+ \plmac@tag\plmac@sep
+ N/A\plmac@sep
+ \plmac@tag\plmac@sep
+ \the\plmac@perlcode
+ }%
+ }%
+ \plmac@run@code
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Communication between \LaTeX{} and Perl}
+%
+% As shown in the previous section, when a document invokes
+% |\perl|[|re|]|newcommand| to define a macro, \perlmac{} defines the
+% macro in terms of a call to |\plmac@write@perl|. In this section, we
+% learn how |\plmac@write@perl| operates.
+%
+% At the highest level, \LaTeX-to-Perl communication is performed via
+% the filesystem. In essence, \LaTeX{} writes a file (|\plmac@tofile|)
+% corresponding to the information in either
+% Figure~\ref{fig:tofile-define} or Figure~\ref{fig:tofile-use}; Perl
+% reads the file, executes the code within it, and writes a |.tex| file
+% (|\plmac@fromfile|); and, finally, \LaTeX{} reads and executes the new
+% |.tex| file. However, the actual communication protocol is a bit more
+% involved than that. The problem is that Perl needs to know when
+% \LaTeX{} has finished writing Perl code and \LaTeX{} needs to know
+% when Perl has finished writing \LaTeX{} code. The solution involves
+% introducing three extra files---|\plmac@toflag|, |\plmac@fromflag|,
+% and |\plmac@doneflag|---which are used exclusively for \LaTeX-to-Perl
+% synchronization.
+%
+% There's a catch: Although Perl can create and delete files, \LaTeX{}
+% can only create them. Even worse, \LaTeX{} (more specifically,
+% te\TeX, which is the \TeX{} distribution under which I developed
+% \PerlTeX) cannot reliably poll for a file's \emph{non}existence; if a
+% file is deleted in the middle of an |\immediate\openin|, |latex|
+% aborts with an error message. These restrictions led to the
+% regrettably convoluted protocol illustrated in
+% Figure~\ref{fig:comm-protocol}. In the figure, ``Touch'' means
+% ``create a zero-length file''; ``Await'' means ``wait until the file
+% exists''; and, ``Read'', ``Write'', and ``Delete'' are defined as
+% expected. Assuming the filesystem performs these operations in a
+% sequentially consistent order (not necessarily guaranteed on all
+% filesystems, unfortunately), \PerlTeX{} should behave as expected.
+%
+% \begin{figure}[htbp]
+% \centering
+% \makeatletter\setlength{\unitlength}{\baselineskip}\makeatother
+% \DeleteShortVerb\|
+% \def\topl{\texttt{\string\plmac@tofile}}
+% \def\frpl{\texttt{\string\plmac@fromfile}}
+% \def\tfpl{\texttt{\string\plmac@toflag}}
+% \def\ffpl{\texttt{\string\plmac@fromflag}}
+% \def\dfpl{\texttt{\string\plmac@doneflag}}
+% \begin{tabular}{@{}c@{\hspace*{1cm}}|l@{~}l|c|l@{~}l|@{}}
+% \multicolumn{1}{@{}c@{\hspace*{1cm}}}{Time} &
+% \multicolumn{2}{c}{\LaTeX} &
+% \multicolumn{1}{c}{} &
+% \multicolumn{2}{c@{}}{Perl} \\
+%
+% \cline{2-3}\cline{5-6}
+% \smash{\vector(0,-1){11}}
+% & Write & \topl & & & \\
+% & Touch & \tfpl & $\rightarrow$ & Await & \tfpl \\
+% & & & & Read & \topl \\
+% & & & & Write & \frpl \\
+% & & & & Delete & \tfpl \\
+% & & & & Delete & \topl \\
+% & & & & Delete & \dfpl \\
+% & Await & \ffpl & $\leftarrow$ & Touch & \ffpl \\
+% & Touch & \topl & $\rightarrow$ & Await & \topl \\
+% & & & & Delete & \ffpl \\
+% & Await & \dfpl & $\leftarrow$ & Touch & \dfpl \\
+% & Read & \frpl & & & \\
+% \cline{2-3}\cline{5-6}
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{\LaTeX-to-Perl communication protocol}
+% \label{fig:comm-protocol}
+% \end{figure}
+%
+% Although Figure~\ref{fig:comm-protocol} shows the read of
+% |\plmac@fromfile| as the final step of the protocol, the file's
+% contents are in fact valid as soon as \LaTeX{} detects that
+% |\plmac@fromflag| exists. Deferring the read to the end, however,
+% enables \PerlTeX{} to support recursive macro invocations.
+%
+% \begin{macro}{\plmac@await@existence}
+% \changes{v1.9}{2009/09/13}{Put the
+% \texttt{\string\string\string\input\string\string\string\plmac@pipe}
+% within an \texttt{lrbox} environment to prevent a partial read from
+% introducing spurious text into the document}
+% \begin{macro}{\ifplmac@file@exists}
+% \begin{macro}{\plmac@file@existstrue}
+% \begin{macro}{\plmac@file@existsfalse}
+% The purpose of the |\plmac@await@existence| macro is to repeatedly
+% check the existence of a given file until the file actually exists.
+% For convenience, we use \LaTeXe's |\IfFileExists| macro to check the
+% file and invoke |\plmac@file@existstrue| or |\plmac@file@existsfalse|,
+% as appropriate.
+%
+% As a performance optimization we |\input| a named pipe. This causes
+% the |latex| process to relinquish the CPU until the |perltex| process
+% writes data (always just a comment plus ``|\endinput|'') into the
+% named pipe. On systems that don't support persistent named pipes
+% (e.g.,~Microsoft Windows), |\plmac@pipe| is an ordinary file
+% containing only a comment plus ``|\endinput|''. While reading that
+% file is not guaranteed to relinquish the CPU, it should not hurt the
+% performance or correctness of the communication protocol between
+% \LaTeX\ and Perl.
+% \changes{v1.5}{2007/10/13}{Modified to read from a named pipe before
+% checking file existence}
+% \begin{macrocode}
+\newif\ifplmac@file@exists
+% \end{macrocode}
+% \begin{macrocode}
+\newcommand{\plmac@await@existence}[1]{%
+ \begin{lrbox}{\@tempboxa}%
+ \input\plmac@pipe
+ \end{lrbox}%
+ \loop
+ \IfFileExists{#1}%
+ {\plmac@file@existstrue}%
+ {\plmac@file@existsfalse}%
+ \ifplmac@file@exists
+ \else
+ \repeat
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\plmac@outfile}
+% We define a file handle for |\plmac@write@perl@i| to use to create and
+% write |\plmac@tofile| and |\plmac@toflag|.
+% \begin{macrocode}
+\newwrite\plmac@outfile
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@write@perl}
+% |\plmac@write@perl| begins the \LaTeX-to-Perl data exchange, following
+% the protocol illustrated in Figure~\ref{fig:comm-protocol}.
+% |\plmac@write@perl| prepares for the next piece of text in the input
+% stream to be read with ``special'' characters marked as category
+% code~12 (``other''). This prevents \LaTeX{} from complaining if the
+% Perl code contains invalid \LaTeX{} (which it usually will).
+% |\plmac@write@perl| ends by passing control to |\plmac@write@perl@i|,
+% which performs the bulk of the work.
+% \begin{macrocode}
+\newcommand{\plmac@write@perl}{%
+ \begingroup
+ \let\do\@makeother\dospecials
+ \catcode`\^^M=\active
+ \newlinechar`\^^M
+ \endlinechar=`\^^M
+ \catcode`\{=1
+ \catcode`\}=2
+ \plmac@write@perl@i
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@write@perl@i}
+% When |\plmac@write@perl@i| begins executing, the category codes are
+% set up so that the macro's argument will be evaluated ``verbatim''
+% except for the part consisting of the \LaTeX\ code passed in by the
+% author, which is partially expanded. Thus, everything is in place for
+% |\plmac@write@perl@i| to send its argument to Perl and read back the
+% (\LaTeX) result.
+%
+% Because\label{page:define-dummies} all of \perlmac's protocol
+% processing is encapsulated within |\plmac@write@perl@i|, this is the
+% only macro that strictly requires \perltex. Consequently, we wrap the
+% entire macro definition within a check for \perltex.
+% \changes{v1.8}{2009/03/25}{Renamed
+% \texttt{\string\string\string\ifplmac@have@perltex} to
+% \texttt{\char`\\ ifperl} to help authors write
+% mixed \string\LaTeX\string\slash\space \string\PerlTeX\ documents}
+% \begin{macrocode}
+\ifperl
+ \newcommand{\plmac@write@perl@i}[1]{%
+% \end{macrocode}
+% The first step is to write argument |#1| to |\plmac@tofile|:
+% \changes{v1.1}{2004/02/19}{Made argument-handling more rational by
+% making \texttt{\string\string\string\protect},
+% \texttt{\string\string\string\begin}, and
+% \texttt{\string\string\string\end} non-expandable}
+% \begin{macrocode}
+ \immediate\openout\plmac@outfile=\plmac@tofile\relax
+ \let\protect=\noexpand
+ \def\begin{\noexpand\begin}%
+ \def\end{\noexpand\end}%
+ \immediate\write\plmac@outfile{#1}%
+ \immediate\closeout\plmac@outfile
+% \end{macrocode}
+% \noindent
+% (In the future, it might be worth redefining |\def|, |\edef|, |\gdef|,
+% |\xdef|, |\let|, and maybe some other control sequences as
+% ``|\noexpand|\meta{control sequence}|\noexpand|'' so that |\write|
+% doesn't try to expand an undefined control sequence.)
+%
+% We're now finished using |#1| so we can end the group begun by
+% |\plmac@write@perl|, thereby resetting each character's category code
+% back to its previous value.
+% \begin{macrocode}
+ \endgroup
+% \end{macrocode}
+%
+% Continuing the protocol illustrated in Figure~\ref{fig:comm-protocol},
+% we create a zero-byte |\plmac@toflag| in order to notify \perltex{}
+% that it's now safe to read |\plmac@tofile|.
+% \begin{macrocode}
+ \immediate\openout\plmac@outfile=\plmac@toflag\relax
+ \immediate\closeout\plmac@outfile
+% \end{macrocode}
+%
+% To avoid reading |\plmac@fromfile| before \perltex{} has finished
+% writing it we must wait until \perltex{} creates |\plmac@fromflag|,
+% which it does only after it has written |\plmac@fromfile|.
+% \begin{macrocode}
+ \plmac@await@existence\plmac@fromflag
+% \end{macrocode}
+%
+% At this point, |\plmac@fromfile| should contain valid \LaTeX{} code.
+% However, we defer inputting it until we the very end. Doing so
+% enables recursive and mutually recursive invocations of \PerlTeX{}
+% macros.
+% \changes{v1.2}{2004/10/07}{Moved the
+% \texttt{\string\string\string\input} of the generated Perl code to
+% the end of the routine in order to support recursive \PerlTeX{}
+% macro invocations.}
+%
+% Because \TeX{} can't delete files we require an additional
+% \LaTeX-to-Perl synchronization step. For convenience, we recycle
+% |\plmac@tofile| as a synchronization file rather than introduce yet
+% another flag file to complement |\plmac@toflag|, |\plmac@fromflag|,
+% and |\plmac@doneflag|.
+% \begin{macrocode}
+ \immediate\openout\plmac@outfile=\plmac@tofile\relax
+ \immediate\closeout\plmac@outfile
+ \plmac@await@existence\plmac@doneflag
+% \end{macrocode}
+%
+% The only thing left to do is to |\input| and evaluate
+% |\plmac@fromfile|, which contains the \LaTeX{} output from the Perl
+% subroutine.
+% \begin{macrocode}
+ \input\plmac@fromfile\relax
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\plmac@write@perl@i}
+% \changes{v1.1}{2004/02/24}{Added a dummy version of the macro to use
+% if \texttt{latex} was launched directly, without \perltex}
+% The foregoing code represents the ``real'' definition of
+% |\plmac@write@perl@i|. For the user's convenience, we define a dummy
+% version of |\plmac@write@perl@i| so that a document which utilizes
+% \perlmac{} can still compile even if not built using \perltex. All
+% calls to macros defined with |\perl|[|re|]|newcommand| and all
+% invocations of environments defined with |\perl|[|re|]|newenvironment|
+% are replaced with ``\fbox{Perl\TeX}''. A minor complication is that
+% text can't be inserted before the |\begin{document}|. Hence, we
+% initially define |\plmac@write@perl@i| as a do-nothing macro and
+% redefine it as ``|\fbox{Perl\TeX}|'' at the |\begin{document}|.
+% \begin{macrocode}
+\else
+ \newcommand{\plmac@write@perl@i}[1]{\endgroup}
+% \end{macrocode}
+% \begin{macro}{\plmac@show@placeholder}
+% There's really no point in outputting a framed ``Perl\TeX'' when a
+% macro is defined \emph{and} when it's used. |\plmac@show@placeholder|
+% checks the first character of the protocol header. If it's
+% ``D''~(|DEF|), nothing is output. Otherwise, it'll be ``U''~(|USE|)
+% and ``Perl\TeX'' will be output.
+% \begin{macrocode}
+ \gdef\plmac@show@placeholder#1#2\@empty{%
+ \ifx#1D\relax
+ \endgroup
+ \else
+ \endgroup
+ \fbox{Perl\TeX}%
+ \fi
+ }%
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+ \AtBeginDocument{%
+ \renewcommand{\plmac@write@perl@i}[1]{%
+ \plmac@show@placeholder#1\@empty
+ }%
+ }
+\fi
+% \end{macrocode}
+% \end{macro}
+%
+% \iffalse
+%</package>
+% \fi
+%
+% ^^A Keep track of the number of lines of code in perltex.
+% \makeatletter
+% \immediate\write\@auxout{^^A
+% \noexpand\gdef\noexpand\perlmaclines{\the\c@CodelineNo}}
+% \makeatother
+%
+%
+% \subsection{\perltex}
+% \label{sec:perltex}
+%
+% \perltex{} is a wrapper script for |latex| (or any other \LaTeX{}
+% compiler). It sets up client-server communication between \LaTeX{}
+% and Perl, with \LaTeX{} as the client and Perl as the server. When a
+% \LaTeX{} document sends a piece of Perl code to \perltex{} (with the
+% help of \perlmac, as detailed in Section~\ref{sec:perlmacros}),
+% \perltex{} executes it within a secure sandbox and transmits the
+% resulting \LaTeX{} code back to the document.
+% \changes{v1.0a}{2003/08/21}{Made all \texttt{unlink} calls wait for the
+% file to actually disappear}
+%
+% \iffalse
+%<*perltex>
+% \fi
+%
+% \subsubsection{Header comments}
+%
+% Because \perltex{} is generated without a \textsf{DocStrip}
+% preamble or postamble we have to manually include the desired
+% text as Perl comments.
+%
+% \begin{macrocode}
+#! /usr/bin/env perl
+
+###########################################################
+# Prepare a LaTeX run for two-way communication with Perl #
+# By Scott Pakin <scott+pt@pakin.org> #
+###########################################################
+
+#-------------------------------------------------------------------
+# This is file `perltex.pl',
+# generated with the docstrip utility.
+#
+# The original source files were:
+#
+# perltex.dtx (with options: `perltex')
+#
+# This is a generated file.
+#
+# Copyright (C) 2010 Scott Pakin <scott+pt@pakin.org>
+#
+# This file may be distributed and/or modified under the conditions
+# of the LaTeX Project Public License, either version 1.3c of this
+# license or (at your option) any later version. The latest
+# version of this license is in:
+#
+# http://www.latex-project.org/lppl.txt
+#
+# and version 1.3c or later is part of all distributions of LaTeX
+# version 2006/05/20 or later.
+#-------------------------------------------------------------------
+
+% \end{macrocode}
+%
+% \subsubsection{Top-level code evaluation}
+%
+% In previous versions of \perltex, the |--nosafe| option created and
+% ran code within a sandbox in which all operations are allowed (via
+% |Opcode::full_opset()|). Unfortunately, certain operations still fail
+% to work within such a sandbox. We therefore define a top-level
+% ``non-sandbox'', |top_level_eval()|, in which to execute code.
+% |top_level_eval()| merely calls |eval()| on its argument. However, it
+% needs to be declared top-level and before anything else because
+% |eval()| runs in the lexical scope of its caller.
+% \changes{v1.3}{2006/06/24}{Modified \perltex\ to eschew the sandbox
+% altogether when \texttt{--nosafe} is specified}
+%
+% \begin{macrocode}
+sub top_level_eval ($)
+{
+ return eval $_[0];
+}
+% \end{macrocode}
+%
+% \subsubsection{Perl modules and pragmas}
+%
+% We use |Safe| and |Opcode| to implement the secure sandbox,
+% |Getopt::Long| and |Pod::Usage| to parse the command line, and
+% various other modules and pragmas for miscellaneous things.
+% \begin{macrocode}
+use Safe;
+use Opcode;
+use Getopt::Long;
+use Pod::Usage;
+use File::Basename;
+use Fcntl;
+use POSIX;
+use File::Spec;
+use IO::Handle;
+use warnings;
+use strict;
+% \end{macrocode}
+%
+% \subsubsection{Variable declarations}
+%
+% With |use strict| in effect, we need to declare all of our variables.
+% For clarity, we separate our global-variable declarations into
+% variables corresponding to command-line options and other global
+% variables.
+%
+% \paragraph{Variables corresponding to command-line arguments}
+% \begin{perlvar}{$latexprog}
+% \begin{perlvar}{$runsafely}
+% \begin{perlvar}{@permittedops}
+% \begin{perlvar}{$usepipe}
+% |$latexprog| is the name of the \LaTeX{} executable
+% (e.g.,~``|latex|''). If |$runsafely| is~|1| (the default), then the
+% user's Perl code runs in a secure sandbox; if it's~|0|, then arbitrary
+% Perl code is allowed to run. |@permittedops| is a list of features
+% made available to the user's Perl code. Valid values are described in
+% Perl's |Opcode| manual page. \perltex's default is a list containing
+% only |:browse|. |$usepipe| is~|1| if \perltex\ should attempt to use
+% a named pipe for communicating with |latex| or~|0| if an ordinary file
+% should be used instead.
+% \begin{macrocode}
+my $latexprog;
+my $runsafely = 1;
+my @permittedops;
+my $usepipe = 1;
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+%
+% \paragraph{Filename variables}
+% \begin{perlvar}{$progname}
+% \begin{perlvar}{$jobname}
+% \begin{perlvar}{$toperl}
+% \begin{perlvar}{$fromperl}
+% \begin{perlvar}{$toflag}
+% \begin{perlvar}{$fromflag}
+% \begin{perlvar}{$doneflag}
+% \begin{perlvar}{$logfile}
+% \begin{perlvar}{$pipe}
+% |$progname| is the run-time name of the \perltex{} program.
+% |$jobname| is the base name of the user's |.tex| file, which defaults
+% to the \TeX{} default of |texput|. |$toperl| defines the filename
+% used for \LaTeX-to-Perl communication. |$fromperl| defines the
+% filename used for Perl-to-\LaTeX{} communication. |$toflag| is the
+% name of a file that will exist only after \LaTeX{} creates |$tofile|.
+% |$fromflag| is the name of a file that will exist only after Perl
+% creates |$fromfile|. |$doneflag| is the name of a file that will
+% exist only after Perl deletes |$fromflag|. |$logfile| is the name of
+% a log file to which \perltex{} writes verbose execution information.
+% |$pipe| is the name of a Unix named pipe (or ordinary file on
+% operating systems that lack support for persistent named pipes or in
+% the case that |$usepipe| is set to~|0|) used to convince the |latex|
+% process to yield control of the CPU\@.
+% \begin{macrocode}
+my $progname = basename $0;
+my $jobname = "texput";
+my $toperl;
+my $fromperl;
+my $toflag;
+my $fromflag;
+my $doneflag;
+my $logfile;
+my $pipe;
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+%
+% \paragraph{Other global variables}
+% \begin{perlvar}{@latexcmdline}
+% \begin{perlvar}{$styfile}
+% \begin{perlvar}{@macroexpansions}
+% \begin{perlvar}{$sandbox}
+% \begin{perlvar}{$sandbox_eval}
+% \begin{perlvar}{$latexpid}
+% |@latexcmdline| is the command line to pass to the \LaTeX{}
+% executable. |$styfile| is the string \noperlmac{} if \perltex{} is run
+% with \texttt{--makesty}, otherwise undefined. |@macroexpansions| is a
+% list of \PerlTeX{} macro expansions in the order they were encountered.
+% It is used for creating a \noperlmac{} file when \texttt{--makesty} is
+% specified. |$sandbox| is a secure sandbox in which to run code that
+% appeared in the \LaTeX{} document. |$sandbox_eval| is a subroutine
+% that evalutes a string within |$sandbox| (normally) or outside of all
+% sandboxes (if |--nosafe| is specified). |$latexpid| is the process~ID
+% of the |latex| process.
+% \begin{macrocode}
+my @latexcmdline;
+my $styfile;
+my @macroexpansions;
+my $sandbox = new Safe;
+my $sandbox_eval;
+my $latexpid;
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+%
+% \begin{perlvar}{$pipestring}
+% |$pipestring| is a constant string to write to the |$pipe| named pipe
+% (or file) at each \LaTeX{} synchronization point. Its particular
+% definition is really a bug workaround for \XeTeX\@. The current
+% version of \XeTeX{} reads the first few bytes of a file to determine
+% the character encoding (\mbox{UTF-8} or \mbox{UTF-16}, big-endian or
+% little-endian) then attempts to rewind the file pointer. Because
+% pipes can't be rewound, the effect is that the first two bytes of
+% |$pipe| are discarded and the rest are input. Hence, the
+% ``|\endinput|'' used in prior versions of \PerlTeX{} inserted a
+% spurious ``|ndinput|'' into the author's document. We therefore
+% define |$pipestring| such that it will not interfere with the document
+% even if the first few bytes are discarded.
+% \changes{v1.7}{2007/12/09}{Introduced this variable as a workaround for
+% \protect\XeTeX's attempt to rewind \texttt{\$pipe}}
+% \begin{macrocode}
+my $pipestring = "\%\%\%\%\% Generated by $progname\n\\endinput\n";
+% \end{macrocode}
+% \end{perlvar}
+%
+% \subsubsection{Command-line conversion}
+%
+% In this section, \perltex{} parses its own command line and prepares a
+% command line to pass to |latex|.
+%
+% \paragraph{Parsing \perltex's command line}
+% We first set |$latexprog| to be the contents of the environment
+% variable |PERLTEX| or the value ``|latex|'' if |PERLTEX| is not
+% specified. We then use |Getopt::Long| to parse the command line,
+% leaving any parameters we don't recognize in the argument vector
+% (|@ARGV|) because these are presumably |latex| options.
+% \changes{v1.6}{2007/12/07}{Added an (undocumented) \texttt{--nopipe}
+% option to \protect\perltex\ to help it work with \protect\XeTeX}
+% \changes{v1.7}{2007/12/09}{Added an (undocumented) \texttt{--synctext}
+% option to alter the text written to \texttt{\$pipe}}
+% \begin{macrocode}
+$latexprog = $ENV{"PERLTEX"} || "latex";
+Getopt::Long::Configure("require_order", "pass_through");
+GetOptions("help" => sub {pod2usage(-verbose => 1)},
+ "latex=s" => \$latexprog,
+ "safe!" => \$runsafely,
+% \end{macrocode}
+% The following two options are undocumented because the defaults should
+% always suffice. We're not yet removing these options, however, in
+% case they turn out to be useful for diagnostic purposes.
+% \begin{macrocode}
+ "pipe!" => \$usepipe,
+ "synctext=s" => \$pipestring,
+% \end{macrocode}
+% \begin{macrocode}
+ "makesty" => sub {$styfile = "noperltex.sty"},
+ "permit=s" => \@permittedops) || pod2usage(2);
+% \end{macrocode}
+%
+% \paragraph{Preparing a \LaTeX{} command line}
+% \begin{perlvar}{$firstcmd}
+% \begin{perlvar}{$option}
+% We start by searching |@ARGV| for the first string that does not start
+% with ``|-|'' or ``|\|''. This string, which represents a filename, is
+% used to set |$jobname|.
+% \begin{macrocode}
+@latexcmdline = @ARGV;
+my $firstcmd = 0;
+for ($firstcmd=0; $firstcmd<=$#latexcmdline; $firstcmd++) {
+ my $option = $latexcmdline[$firstcmd];
+ next if substr($option, 0, 1) eq "-";
+ if (substr ($option, 0, 1) ne "\\") {
+ $jobname = basename $option, ".tex" ;
+ $latexcmdline[$firstcmd] = "\\input $option";
+ }
+ last;
+}
+push @latexcmdline, "" if $#latexcmdline==-1;
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+%
+% \begin{perlvar}{$separator}
+% To avoid conflicts with the code and parameters passed to Perl from
+% \LaTeX{} (see Figure~\vref{fig:tofile-define} and
+% Figure~\vref{fig:tofile-use}) we define a separator string,
+% |$separator|, containing 20 random uppercase letters.
+% \begin{macrocode}
+my $separator = "";
+foreach (1 .. 20) {
+ $separator .= chr(ord("A") + rand(26));
+}
+% \end{macrocode}
+% \end{perlvar}
+%
+% Now that we have the name of the \LaTeX{} job (|$jobname|) we can
+% assign |$toperl|, |$fromperl|, |$toflag|, |$fromflag|, |$doneflag|,
+% |$logfile|, and |$pipe| in terms of |$jobname| plus a suitable
+% extension.
+% \begin{macrocode}
+$toperl = $jobname . ".topl";
+$fromperl = $jobname . ".frpl";
+$toflag = $jobname . ".tfpl";
+$fromflag = $jobname . ".ffpl";
+$doneflag = $jobname . ".dfpl";
+$logfile = $jobname . ".lgpl";
+$pipe = $jobname . ".pipe";
+% \end{macrocode}
+%
+% We now replace the filename of the |.tex| file passed to \perltex{}
+% with a |\def|inition of the separator character, |\def|initions of the
+% various files, and the original file with |\input| prepended if
+% necessary.
+% \begin{macrocode}
+$latexcmdline[$firstcmd] =
+ sprintf '\makeatletter' . '\def%s{%s}' x 7 . '\makeatother%s',
+ '\plmac@tag', $separator,
+ '\plmac@tofile', $toperl,
+ '\plmac@fromfile', $fromperl,
+ '\plmac@toflag', $toflag,
+ '\plmac@fromflag', $fromflag,
+ '\plmac@doneflag', $doneflag,
+ '\plmac@pipe', $pipe,
+ $latexcmdline[$firstcmd];
+% \end{macrocode}
+%
+% \subsubsection{Increasing \PerlTeX's robustness}
+%
+% \changes{v2.0}{2009/11/24}{Refer to each communication file using
+% its absolute path. This makes \perltex\ robust to user code
+% that changes the current directory}
+% \changes{v2.1}{2010/07/10}{Replaced \texttt{abs\_path()} with
+% \texttt{File::Spec-\char"3Erel2abs()} because the latter seems
+% to be more robust to nonexistent files}
+% \begin{macrocode}
+$toperl = File::Spec->rel2abs($toperl);
+$fromperl = File::Spec->rel2abs($fromperl);
+$toflag = File::Spec->rel2abs($toflag);
+$fromflag = File::Spec->rel2abs($fromflag);
+$doneflag = File::Spec->rel2abs($doneflag);
+$logfile = File::Spec->rel2abs($logfile);
+$pipe = File::Spec->rel2abs($pipe);
+% \end{macrocode}
+%
+% \changes{v1.9}{2009/09/13}{Introduced handlers for \textsc{sigalrm}
+% and \textsc{sigpipe} to make \perltex\ more robust to \texttt{latex}
+% exiting at an inopportune time}
+%
+% \perltex\ may hang if |latex| exits right before the final pipe
+% communication. We therefore define a simple \signal{ALRM} handler
+% that lets \perltex\ exit after a given length of time has
+% elapsed.\label{code:sigalrm}
+% \begin{macrocode}
+$SIG{"ALRM"} = sub {
+ undef $latexpid;
+ exit 0;
+};
+% \end{macrocode}
+%
+% To prevent Perl from aborting with a ``\texttt{Broken pipe}'' error
+% message if |latex| exits during the final pipe communication we tell
+% Perl to ignore \signal{PIPE} errors. |latex|'s exiting will be
+% caught via other means (the preceding \signal{ALRM} handler or the
+% following call to |waitpid|).
+% \begin{macrocode}
+$SIG{"PIPE"} = "IGNORE";
+% \end{macrocode}
+%
+% \begin{perlsub}{delete_files}
+% On some operating systems and some filesystems, deleting a file may
+% not cause the file to disappear immediately. Because
+% \PerlTeX\ synchronizes Perl and \LaTeX\ via the filesystem it is
+% critical that file deletions be performed when requested. We
+% therefore define a |delete_files| subroutine that waits until each
+% file named in the argument list is truly deleted.
+% \changes{v1.9}{2009/09/13}{Replaced all
+% \texttt{unlink}\dots\texttt{while~-e} statements with calls to a new
+% \texttt{delete\_files} subroutine}
+% \begin{macrocode}
+sub delete_files (@)
+{
+ foreach my $filename (@_) {
+ unlink $filename;
+ while (-e $filename) {
+ unlink $filename;
+ sleep 0;
+ }
+ }
+}
+% \end{macrocode}
+% \end{perlsub}
+%
+% \begin{perlsub}{awaitexists}
+% We define an |awaitexists| subroutine that waits for a given file to
+% exist. If |latex| exits while |awaitexists| is waiting, then
+% \perltex{} cleans up and exits, too.
+% \changes{v1.0a}{2003/08/06}{Bug fix: Added ``\texttt{undef
+% \$latexpid}'' to make the \texttt{END} block correctly return a
+% status code of~0 on success}
+% \changes{v1.9}{2009/09/13}{Hoisted \texttt{\$awaitexists} from the
+% main loop and made it a top-level subroutine}
+% \begin{macrocode}
+sub awaitexists ($)
+{
+ while (!-e $_[0]) {
+ sleep 0;
+ if (waitpid($latexpid, &WNOHANG)==-1) {
+ delete_files($toperl, $fromperl, $toflag,
+ $fromflag, $doneflag, $pipe);
+ undef $latexpid;
+ exit 0;
+ }
+ }
+}
+% \end{macrocode}
+% \end{perlsub}
+%
+% \subsubsection{Launching \LaTeX}
+%
+% We start by deleting the |$toperl|, |$fromperl|, |$toflag|,
+% |$fromflag|, |$doneflag|, and |$pipe| files, in case any of these were
+% left over from a previous (aborted) run. We also create a log file
+% (|$logfile|), a named pipe (|$pipe|)---or a file containing only
+% |\endinput| if we can't create a named pipe---and, if |$styfile| is
+% defined, a \LaTeXe\ style file. As |@latexcmdline| contains the
+% complete command line to pass to |latex| we need only |fork| a new
+% process and have the child process overlay itself with |latex|.
+% \perltex{} continues running as the parent.
+% \begin{macrocode}
+delete_files($toperl, $fromperl, $toflag, $fromflag, $doneflag, $pipe);
+open (LOGFILE, ">$logfile") || die "open(\"$logfile\"): $!\n";
+autoflush LOGFILE 1;
+if (defined $styfile) {
+ open (STYFILE, ">$styfile") || die "open(\"$styfile\"): $!\n";
+}
+% \end{macrocode}
+% \begin{macrocode}
+if (!$usepipe || !eval {mkfifo($pipe, 0600)}) {
+ sysopen PIPE, $pipe, O_WRONLY|O_CREAT, 0755;
+ autoflush PIPE 1;
+ print PIPE $pipestring;
+ close PIPE;
+ $usepipe = 0;
+}
+% \end{macrocode}
+% \begin{macrocode}
+defined ($latexpid = fork) || die "fork: $!\n";
+unshift @latexcmdline, $latexprog;
+if (!$latexpid) {
+ exec {$latexcmdline[0]} @latexcmdline;
+ die "exec('@latexcmdline'): $!\n";
+}
+% \end{macrocode}
+%
+% \subsubsection{Preparing a sandbox}
+%
+% \perltex{} uses Perl's |Safe| and |Opcode| modules to declare a secure
+% sandbox (|$sandbox|) in which to run Perl code passed to it from
+% \LaTeX{}\@. When the sandbox compiles and executes Perl code, it
+% permits only operations that are deemed safe. For example, the Perl
+% code is allowed by default to assign variables, call functions, and
+% execute loops. However, it is not normally allowed to delete files,
+% kill processes, or invoke other programs. If \perltex\ is run with
+% the |--nosafe| option we bypass the sandbox entirely and execute Perl
+% code using an ordinary |eval()| statement.
+% \begin{macrocode}
+if ($runsafely) {
+ @permittedops=(":browse") if $#permittedops==-1;
+ $sandbox->permit_only (@permittedops);
+ $sandbox_eval = sub {$sandbox->reval($_[0])};
+}
+else {
+ $sandbox_eval = \&top_level_eval;
+}
+% \end{macrocode}
+%
+% \subsubsection{Communicating with \LaTeX{}}
+%
+% The following code constitutes \perltex's main loop. Until |latex|
+% exits, the loop repeatedly reads Perl code from \LaTeX{}, evaluates
+% it, and returns the result as per the protocol described in
+% Figure~\vref{fig:comm-protocol}.
+% \changes{v1.0a}{2003/08/21}{Undefined \texttt{\string\string\string$/}
+% only locally}
+%
+% \begin{macrocode}
+while (1) {
+% \end{macrocode}
+%
+% \begin{perlvar}{$entirefile}
+% Wait for |$toflag| to exist. When it does, this implies that
+% |$toperl| must exist as well. We read the entire contents of
+% |$toperl| into the |$entirefile| variable and process it.
+% Figures~\ref{fig:tofile-define} and~\ref{fig:tofile-use} illustrate
+% the contents of |$toperl|.
+% \begin{macrocode}
+ awaitexists($toflag);
+ my $entirefile;
+ {
+ local $/ = undef;
+ open (TOPERL, "<$toperl") || die "open($toperl): $!\n";
+ $entirefile = <TOPERL>;
+ close TOPERL;
+ }
+% \end{macrocode}
+% \end{perlvar}
+%
+% \begin{perlvar}{$optag}
+% \begin{perlvar}{$macroname}
+% \begin{perlvar}{@otherstuff}
+% We split the contents of |$entirefile| into an operation tag (either
+% |DEF|, |USE|, or |RUN|), the macro name, and everything else
+% (|@otherstuff|). If |$optag| is |DEF| then |@otherstuff| will contain
+% the Perl code to define. If |$optag| is |USE| then |@otherstuff| will
+% be a list of subroutine arguments. If |$optag| is |RUN| then
+% |@otherstuff| will be a block of Perl code to run.
+% \changes{v2.1}{2010/07/10}{Normalized line endings across
+% Unix\slash Windows\slash Macintosh}
+% \begin{macrocode}
+ $entirefile =~ s/\r//g;
+ my ($optag, $macroname, @otherstuff) =
+ map {chomp; $_} split "$separator\n", $entirefile;
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+% \end{perlvar}
+%
+% We clean up the macro name by deleting all leading non-letters,
+% replacing all subsequent non-alphanumerics with ``|_|'', and
+% prepending ``|latex_|'' to the macro name.
+% \begin{macrocode}
+ $macroname =~ s/^[^A-Za-z]+//;
+ $macroname =~ s/\W/_/g;
+ $macroname = "latex_" . $macroname;
+% \end{macrocode}
+%
+% If we're calling a subroutine, then we make the arguments more
+% palatable to Perl by single-quoting them and replacing every
+% occurrence of ``|\|'' with ``|\\|'' and every occurrence of ``|'|''
+% with ``|\'|''.
+% \begin{macrocode}
+ if ($optag eq "USE") {
+ foreach (@otherstuff) {
+ s/\\/\\\\/g;
+ s/\'/\\\'/g;
+ $_ = "'$_'";
+ }
+ }
+% \end{macrocode}
+%
+% \begin{perlvar}{$perlcode}
+% There are three possible values that can be assigned to |$perlcode|.
+% If |$optag| is |DEF|, then |$perlcode| is made to contain a definition
+% of the user's subroutine, named |$macroname|. If |$optag| is |USE|,
+% then |$perlcode| becomes an invocation of |$macroname| which gets
+% passed all of the macro arguments. Finally, if |$optag| is |RUN|,
+% then |$perlcode| is the unmodified Perl code passed to us from
+% \perlmac. Figure~\ref{fig:latex-perl-define} presents an example
+% of how the following code converts a \PerlTeX{} macro definition into
+% a Perl subroutine definition and Figure~\ref{fig:latex-perl-use}
+% presents an example of how the following code converts a \PerlTeX{}
+% macro invocation into a Perl subroutine invocation.
+%
+% \begin{figure}[tbp]
+% \centering
+% \DeleteShortVerb\|
+% \begin{tabular}{l|l|}
+% \cline{2-2}
+% \LaTeX: & \verb|\perlnewcommand{\mymacro}[2]{%| \\
+% & \verb| sprintf "Isn't $_[0] %s $_[1]?\n",| \\
+% & \verb| $_[0]>=$_[1] ? ">=" : "<"| \\
+% & \verb|}| \\
+% \cline{2-2}
+% \multicolumn{2}{c}{} \\
+% \multicolumn{1}{c}{} & \multicolumn{1}{c}{\Huge$\Downarrow$} \\
+% \multicolumn{2}{c}{} \\
+% \cline{2-2}
+% Perl: & \verb|sub latex_mymacro {| \\
+% & \verb| sprintf "Isn't $_[0] %s $_[1]?\n",| \\
+% & \verb| $_[0]>=$_[1] ? ">=" : "<"| \\
+% & \verb|}| \\
+% \cline{2-2}
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{Conversion from \LaTeX{} to Perl (subroutine definition)}
+% \label{fig:latex-perl-define}
+% \end{figure}
+%
+% \begin{figure}[tbp]
+% \centering
+% \DeleteShortVerb\|
+% \begin{tabular}{l|l|}
+% \cline{2-2}
+% \LaTeX: & \verb|\mymacro{12}{34}| \\
+% \cline{2-2}
+% \multicolumn{2}{c}{} \\
+% \multicolumn{1}{c}{} & \multicolumn{1}{c}{\Huge$\Downarrow$} \\
+% \multicolumn{2}{c}{} \\
+% \cline{2-2}
+% Perl: & \verb|latex_mymacro ('12', '34');| \\
+% \cline{2-2}
+% \end{tabular}
+% \MakeShortVerb\|
+% \caption{Conversion from \LaTeX{} to Perl (subroutine invocation)}
+% \label{fig:latex-perl-use}
+% \end{figure}
+%
+% \begin{macrocode}
+ my $perlcode;
+ if ($optag eq "DEF") {
+ $perlcode =
+ sprintf "sub %s {%s}\n",
+ $macroname, $otherstuff[0];
+ }
+ elsif ($optag eq "USE") {
+ $perlcode = sprintf "%s (%s);\n", $macroname, join(", ", @otherstuff);
+ }
+ elsif ($optag eq "RUN") {
+ $perlcode = $otherstuff[0];
+ }
+ else {
+ die "${progname}: Internal error -- unexpected operation tag \"$optag\"\n";
+ }
+% \end{macrocode}
+% \end{perlvar}
+%
+% Log what we're about to evaluate.
+% \begin{macrocode}
+ print LOGFILE "#" x 31, " PERL CODE ", "#" x 32, "\n";
+ print LOGFILE $perlcode, "\n";
+% \end{macrocode}
+%
+% \begin{perlvar}{$result}
+% \begin{perlvar}{$msg}
+% We're now ready to execute the user's code using the |$sandbox_eval|
+% function. If a warning occurs we write it as a Perl comment to the
+% log file. If an error occurs (i.e.,~|$@| is defined) we replace the
+% result (|$result|) with a call to \LaTeXe's |\PackageError| macro to
+% return a suitable error message. We produce one error message for
+% sandbox policy violations (detected by the error message, |$@|,
+% containing the string ``\texttt{trapped by}'') and a different error
+% message for all other errors caused by executing the user's code. For
+% clarity of reading both warning and error messages, we elide the
+% string ``\texttt{at (eval} \meta{number}\texttt{) line}
+% \meta{number}''. Once |$result| is defined---as either the resulting
+% \LaTeX\ code or as a |\PackageError|---we store it in
+% |@macroexpansions| in preparation for writing it to \noperlmac\
+% (when \perltex\ is run with \texttt{--makesty}).
+% \changes{v2.0}{2009/11/21}{Substituted
+% \texttt{\string\string\string\MessageBreak} for newline when
+% reporting error messages produced by user code}
+% \begin{macrocode}
+ undef $_;
+ my $result;
+ {
+ my $warningmsg;
+ local $SIG{__WARN__} =
+ sub {chomp ($warningmsg=$_[0]); return 0};
+ $result = $sandbox_eval->($perlcode);
+ if (defined $warningmsg) {
+ $warningmsg =~ s/at \(eval \d+\) line \d+\W+//;
+ print LOGFILE "# ===> $warningmsg\n\n";
+ }
+ }
+ $result = "" if !$result || $optag eq "RUN";
+ if ($@) {
+ my $msg = $@;
+ $msg =~ s/at \(eval \d+\) line \d+\W+//;
+ $msg =~ s/\n/\\MessageBreak\n/g;
+ $msg =~ s/\s+/ /;
+ $result = "\\PackageError{perltex}{$msg}";
+ my @helpstring;
+ if ($msg =~ /\btrapped by\b/) {
+ @helpstring =
+ ("The preceding error message comes from Perl. Apparently,",
+ "the Perl code you tried to execute attempted to perform an",
+ "`unsafe' operation. If you trust the Perl code (e.g., if",
+ "you wrote it) then you can invoke perltex with the --nosafe",
+ "option to allow arbitrary Perl code to execute.",
+ "Alternatively, you can selectively enable Perl features",
+ "using perltex's --permit option. Don't do this if you don't",
+ "trust the Perl code, however; malicious Perl code can do a",
+ "world of harm to your computer system.");
+ }
+ else {
+ @helpstring =
+ ("The preceding error message comes from Perl. Apparently,",
+ "there's a bug in your Perl code. You'll need to sort that",
+ "out in your document and re-run perltex.");
+ }
+ my $helpstring = join ("\\MessageBreak\n", @helpstring);
+ $helpstring =~ s/\. /.\\space\\space /g;
+ $result .= "{$helpstring}";
+ }
+ push @macroexpansions, $result if defined $styfile && $optag eq "USE";
+% \end{macrocode}
+% \end{perlvar}
+% \end{perlvar}
+%
+% Log the resulting \LaTeX{} code.
+% \begin{macrocode}
+ print LOGFILE "%" x 30, " LATEX RESULT ", "%" x 30, "\n";
+ print LOGFILE $result, "\n\n";
+% \end{macrocode}
+%
+% We add |\endinput| to the generated \LaTeX{} code to suppress an
+% extraneous end-of-line character that \TeX{} would otherwise insert.
+% \begin{macrocode}
+ $result .= '\endinput';
+% \end{macrocode}
+%
+% Continuing the protocol described in Figure~\vref{fig:comm-protocol}
+% we now write |$result| (which contains either the result of executing
+% the user's or a |\PackageError|) to the |$fromperl| file, delete
+% |$toflag|, |$toperl|, and |$doneflag|, and notify \LaTeX{} by touching
+% the |$fromflag| file. As a performance optimization, we also write
+% |\endinput| into |$pipe| to wake up the |latex| process.
+% \begin{macrocode}
+ open (FROMPERL, ">$fromperl") || die "open($fromperl): $!\n";
+ syswrite FROMPERL, $result;
+ close FROMPERL;
+% \end{macrocode}
+% \begin{macrocode}
+ delete_files($toflag, $toperl, $doneflag);
+% \end{macrocode}
+% \begin{macrocode}
+ open (FROMFLAG, ">$fromflag") || die "open($fromflag): $!\n";
+ close FROMFLAG;
+% \end{macrocode}
+% \begin{macrocode}
+ if (open (PIPE, ">$pipe")) {
+ autoflush PIPE 1;
+ print PIPE $pipestring;
+ close PIPE;
+ }
+% \end{macrocode}
+%
+% We have to perform one final \LaTeX-to-Perl synchronization step.
+% Otherwise, a subsequent |\perl|[|re|]|newcommand| would see that
+% |$fromflag| already exists and race ahead, finding that |$fromperl|
+% does not contain what it's supposed to.
+% \begin{macrocode}
+ awaitexists($toperl);
+ delete_files($fromflag);
+ open (DONEFLAG, ">$doneflag") || die "open($doneflag): $!\n";
+ close DONEFLAG;
+% \end{macrocode}
+% Again, we awaken the |latex| process, which is blocked on |$pipe|. If
+% writing to the pipe takes more than one second we assume that |latex|
+% has exited and trigger the \signal{ALRM} handler
+% (page~\pageref{code:sigalrm}).
+% \begin{macrocode}
+ alarm 1;
+ if (open (PIPE, ">$pipe")) {
+ autoflush PIPE 1;
+ print PIPE $pipestring;
+ close PIPE;
+ }
+ alarm 0;
+}
+% \end{macrocode}
+%
+% \subsubsection{Final cleanup}
+%
+% If we exit abnormally we should do our best to kill the child |latex|
+% process so that it doesn't continue running forever, holding onto
+% system resources.
+% \begin{macrocode}
+END {
+ close LOGFILE;
+ if (defined $latexpid) {
+ kill (9, $latexpid);
+ exit 1;
+ }
+
+ if (defined $styfile) {
+% \end{macrocode}
+% \changes{v1.4}{2007/09/29}{Added support for a \texttt{--makesty}
+% option that generates a \PerlTeX-free style file called
+% \texttt{noperltex.sty}}
+% This is the big moment for the \texttt{--makesty} option. We've
+% accumulated the output from each \PerlTeX\ macro invocation into
+% |@macroexpansions|, and now we need to produce a
+% \noperlmac\ file. We start by generating a boilerplate
+% header in which we set up the package and load both \pkgname{perltex}
+% and \pkgname{filecontents}.
+% \begin{macrocode}
+ print STYFILE <<"STYFILEHEADER1";
+\\NeedsTeXFormat{LaTeX2e}[1999/12/01]
+\\ProvidesPackage{noperltex}
+ [2007/09/29 v1.4 Perl-free version of PerlTeX specific to $jobname.tex]
+STYFILEHEADER1
+ ;
+ print STYFILE <<'STYFILEHEADER2';
+\RequirePackage{filecontents}
+
+% Suppress the "Document must be compiled using perltex" error from perltex.
+\let\noperltex@PackageError=\PackageError
+\renewcommand{\PackageError}[3]{}
+\RequirePackage{perltex}
+\let\PackageError=\noperltex@PackageError
+
+% \end{macrocode}
+% \begin{macro}{\plmac@macro@invocation@num}
+% \begin{macro}{\plmac@show@placeholder}
+% \noperlmac\ works by redefining the |\plmac@show@placeholder| macro,
+% which normally outputs a framed ``\PerlTeX'' when \perltex\ isn't
+% running, changing it to input |noperltex-|\meta{number}|.tex| instead
+% (where \meta{number} is the contents of the
+% |\plmac@macro@invocation@num| counter). Each
+% |noperltex-|\meta{number}|.tex| file contains the output from a single
+% invocation of a \PerlTeX-defined macro.
+% \begin{macrocode}
+% Modify \plmac@show@placeholder to input the next noperltex-*.tex file
+% each time a PerlTeX-defined macro is invoked.
+\newcount\plmac@macro@invocation@num
+\gdef\plmac@show@placeholder#1#2\@empty{%
+ \ifx#1U\relax
+ \endgroup
+ \advance\plmac@macro@invocation@num by 1\relax
+ \global\plmac@macro@invocation@num=\plmac@macro@invocation@num
+ \input{noperltex-\the\plmac@macro@invocation@num.tex}%
+ \else
+ \endgroup
+ \fi
+}
+STYFILEHEADER2
+ ;
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% Finally, we need to have \noperlmac\ generate each of the
+% |noperltex-|\meta{number}|.tex| files. For each element of
+% |@macroexpansions| we use one |filecontents| environment to write the
+% macro expansion verbatim to a file.
+% \begin{macrocode}
+ foreach my $e (0 .. $#macroexpansions) {
+ print STYFILE "\n";
+ printf STYFILE "%% Invocation #%d\n", 1+$e;
+ printf STYFILE "\\begin{filecontents}{noperltex-%d.tex}\n", 1+$e;
+ print STYFILE $macroexpansions[$e], "\\endinput\n";
+ print STYFILE "\\end{filecontents}\n";
+ }
+ print STYFILE "\\endinput\n";
+ close STYFILE;
+ }
+
+ exit 0;
+}
+
+__END__
+% \end{macrocode}
+%
+% \subsubsection{\perltex{} POD documentation}
+%
+% \perltex{} includes documentation in Perl's POD (Plain Old
+% Documentation) format. This is used both to produce manual pages and
+% to provide usage information when \perltex{} is invoked with the
+% |--help| option. The POD documentation is not listed here as part of
+% the documented \perltex{} source code because it contains essentially
+% the same information as that shown in Section~\ref{sec:perltex-man}.
+% If you're curious what the POD source looks like then see the
+% generated \perltex{} file.
+%
+% \iffalse
+% \begin{macrocode}
+
+=head1 NAME
+
+perltex - enable LaTeX macros to be defined in terms of Perl code
+
+
+=head1 SYNOPSIS
+
+perltex
+[B<--help>]
+[B<--latex>=I<program>]
+[B<-->[B<no>]B<safe>]
+[B<--permit>=I<feature>]
+[B<--makesty>]
+[I<latex options>]
+
+
+=head1 DESCRIPTION
+
+LaTeX -- through the underlying TeX typesetting system -- produces
+beautifully typeset documents but has a macro language that is
+difficult to program. In particular, support for complex string
+manipulation is largely lacking. Perl is a popular general-purpose
+programming language whose forte is string manipulation. However, it
+has no typesetting capabilities whatsoever.
+
+Clearly, Perl's programmability could complement LaTeX's typesetting
+strengths. B<perltex> is the tool that enables a symbiosis between
+the two systems. All a user needs to do is compile a LaTeX document
+using B<perltex> instead of B<latex>. (B<perltex> is actually a
+wrapper for B<latex>, so no B<latex> functionality is lost.) If the
+document includes a C<\usepackage{perltex}> in its preamble, then
+C<\perlnewcommand> and C<\perlrenewcommand> macros will be made
+available. These behave just like LaTeX's C<\newcommand> and
+C<\renewcommand> except that the macro body contains Perl code instead
+of LaTeX code.
+
+
+=head1 OPTIONS
+
+B<perltex> accepts the following command-line options:
+
+=over 4
+
+=item B<--help>
+
+Display basic usage information.
+
+=item B<--latex>=I<program>
+
+Specify a program to use instead of B<latex>. For example,
+C<--latex=pdflatex> would typeset the given document using
+B<pdflatex> instead of ordinary B<latex>.
+
+=item B<-->[B<no>]B<safe>
+
+Enable or disable sandboxing. With the default of B<--safe>,
+B<perltex> executes the code from a C<\perlnewcommand> or
+C<\perlrenewcommand> macro within a protected environment that
+prohibits ``unsafe'' operations such as accessing files or executing
+external programs. Specifying B<--nosafe> gives the LaTeX document
+I<carte blanche> to execute any arbitrary Perl code, including that
+which can harm the user's files. See L<Safe> for more information.
+
+=item B<--permit>=I<feature>
+
+Permit particular Perl operations to be performed. The B<--permit>
+option, which can be specified more than once on the command line,
+enables finer-grained control over the B<perltex> sandbox. See
+L<Opcode> for more information.
+
+=item B<--makesty>
+
+Generate a LaTeX style file called F<noperltex.sty>. Replacing the
+document's C<\usepackage{perltex}> line with C<\usepackage{noperltex}>
+produces the same output but does not require PerlTeX, making the
+document suitable for distribution to people who do not have PerlTeX
+installed. The disadvantage is that F<noperltex.sty> is specific to
+the document that produced it. Any changes to the document's PerlTeX
+macro definitions or macro invocations necessitates rerunning
+B<perltex> with the B<--makesty> option.
+
+=back
+
+These options are then followed by whatever options are normally
+passed to B<latex> (or whatever program was specified with
+C<--latex>), including, for instance, the name of the F<.tex> file to
+compile.
+
+
+=head1 EXAMPLES
+
+In its simplest form, B<perltex> is run just like B<latex>:
+
+ perltex myfile.tex
+
+To use B<pdflatex> instead of regular B<latex>, use the B<--latex>
+option:
+
+ perltex --latex=pdflatex myfile.tex
+
+If LaTeX gives a ``C<trapped by operation mask>'' error and you trust
+the F<.tex> file you're trying to compile not to execute malicious
+Perl code (e.g., because you wrote it yourself), you can disable
+B<perltex>'s safety mechansisms with B<--nosafe>:
+
+ perltex --nosafe myfile.tex
+
+The following command gives documents only B<perltex>'s default
+permissions (C<:browse>) plus the ability to open files and invoke the
+C<time> command:
+
+ perltex --permit=:browse --permit=:filesys_open
+ --permit=time myfile.tex
+
+
+=head1 ENVIRONMENT
+
+B<perltex> honors the following environment variables:
+
+=over 4
+
+=item PERLTEX
+
+Specify the filename of the LaTeX compiler. The LaTeX compiler
+defaults to ``C<latex>''. The C<PERLTEX> environment variable
+overrides this default, and the B<--latex> command-line option (see
+L</OPTIONS>) overrides that.
+
+=back
+
+
+=head1 FILES
+
+While compiling F<jobname.tex>, B<perltex> makes use of the following
+files:
+
+=over 4
+
+=item F<jobname.lgpl>
+
+log file written by Perl; helpful for debugging Perl macros
+
+=item F<jobname.topl>
+
+information sent from LaTeX to Perl
+
+=item F<jobname.frpl>
+
+information sent from Perl to LaTeX
+
+=item F<jobname.tfpl>
+
+``flag'' file whose existence indicates that F<jobname.topl> contains
+valid data
+
+=item F<jobname.ffpl>
+
+``flag'' file whose existence indicates that F<jobname.frpl> contains
+valid data
+
+=item F<jobname.dfpl>
+
+``flag'' file whose existence indicates that F<jobname.ffpl> has been
+deleted
+
+=item F<noperltex-#.tex>
+
+file generated by F<noperltex.sty> for each PerlTeX macro invocation
+
+=back
+
+
+=head1 NOTES
+
+B<perltex>'s sandbox defaults to what L<Opcode> calls ``C<:browse>''.
+
+
+=head1 SEE ALSO
+
+latex(1), pdflatex(1), perl(1), Safe(3pm), Opcode(3pm)
+
+
+=head1 AUTHOR
+
+Scott Pakin, I<scott+pt@pakin.org>
+% \end{macrocode}
+% \fi
+%
+% \iffalse
+%</perltex>
+% \fi
+%
+% ^^A Keep track of the number of lines of code in perltex.
+% \makeatletter
+% \immediate\write\@auxout{^^A
+% \noexpand\gdef\noexpand\perltexlines{\the\c@CodelineNo}}
+% \makeatother
+%
+%
+% \subsection{Porting to other languages}
+% \label{sec:porting}
+%
+% Perl is a natural choice for a \LaTeX{} macro language because of its
+% excellent support for text manipulation including extended regular
+% expressions, string interpolation, and ``here'' strings, to name a few
+% nice features. However, Perl's syntax is unusual and its semantics
+% are rife with annoying special cases. Some users will therefore long
+% for a \meta{some-language-other-than-Perl}\TeX\@. Fortunately,
+% porting \PerlTeX{} to use a different language should be fairly
+% straightforward. \perltex{} will need to be rewritten in the target
+% language, of course, but \perlmac{} modifications will likely be
+% fairly minimal. In all probability, only the following changes will
+% need to be made:
+%
+% \begin{itemize}
+% \item Rename \perlmac{} and \perltex{} (and choose a package name
+% other than ``\PerlTeX'') as per the \PerlTeX{} license agreement
+% (Section~\ref{sec:license}).
+%
+% \item In your replacement for \perlmac, replace all occurrences of
+% ``|plmac|'' with a different string.
+%
+% \item In your replacement for \perltex, choose different file
+% extensions for the various helper files.
+% \end{itemize}
+%
+% The importance of these changes is that they help ensure version
+% consistency and that they make it possible to run
+% \meta{some-language-other-than-Perl}\TeX{} alongside \PerlTeX,
+% enabling multiple programming languages to be utilized in the same
+% \LaTeX{} document.
+%
+% \Finale
+\endinput
diff --git a/macros/latex/contrib/perltex/perltex.ins b/macros/latex/contrib/perltex/perltex.ins
new file mode 100644
index 0000000000..6f5b1b2fa5
--- /dev/null
+++ b/macros/latex/contrib/perltex/perltex.ins
@@ -0,0 +1,68 @@
+%%
+%% Copyright (C) 2010 Scott Pakin <scott+pt@pakin.org>
+%%
+%% This file may be distributed and/or modified under the conditions of
+%% the LaTeX Project Public License, either version 1.3c of this license
+%% or (at your option) any later version. The latest version of this
+%% license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of LaTeX version
+%% 2006/05/20 or later.
+%%
+
+\input docstrip.tex
+\keepsilent
+
+\usedir{tex/latex/perltex}
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2010 Scott Pakin <scott+pt@pakin.org>
+
+This file may be distributed and/or modified under the conditions of
+the LaTeX Project Public License, either version 1.3c of this license
+or (at your option) any later version. The latest version of this
+license is in:
+
+ http://www.latex-project.org/lppl.txt
+
+and version 1.3c or later is part of all distributions of LaTeX version
+2006/05/20 or later.
+
+\endpreamble
+
+\generate{\file{perltex.sty}{\from{perltex.dtx}{package}}
+ \file{example.tex}{\from{perltex.dtx}{example}}}
+\generate{\usepreamble\empty\usepostamble\empty
+ \file{perltex.pl}{\from{perltex.dtx}{perltex}}}
+
+\obeyspaces
+\Msg{*************************************************************************}
+\Msg{* To finish the installation you have to move the following file into a *}
+\Msg{* directory searched by TeX: *}
+\Msg{* *}
+\Msg{* perltex.sty *}
+\Msg{* *}
+\Msg{* Also, you'll need to move the following file into a directory on your *}
+\Msg{* executable search path: *}
+\Msg{* *}
+\Msg{* perltex.pl *}
+\Msg{* *}
+\Msg{* On Unix/Linux you may want to rename perltex.pl to just perltex and *}
+\Msg{* enable execute permissions ("chmod +x perltex"). On Windows you may *}
+\Msg{* want to produce a .bat file wrapper for perltex.pl ("pl2bat *}
+\Msg{* perltex.pl") and install perltex.bat in the same directory as *}
+\Msg{* perltex.pl. *}
+\Msg{* *}
+\Msg{* To produce the documentation and a sample PerlTeX file, example.tex, *}
+\Msg{* run the file perltex.dtx through LaTeX. *}
+\Msg{* *}
+\Msg{* Happy TeXing! *}
+\Msg{* *}
+\Msg{*************************************************************************}
+
+\endbatchfile
diff --git a/macros/latex/contrib/perltex/perltex.pdf b/macros/latex/contrib/perltex/perltex.pdf
new file mode 100644
index 0000000000..7b66c014ab
--- /dev/null
+++ b/macros/latex/contrib/perltex/perltex.pdf
Binary files differ