diff options
author | Karl Berry <karl@freefriends.org> | 2009-09-20 23:29:41 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-09-20 23:29:41 +0000 |
commit | 2c20e449c234f30eb26e3cbbd9cd48b281842a37 (patch) | |
tree | 60bd80b52ddd7f2e6250c5ab90e047ad455fa475 /Master/texmf-dist/source/latex | |
parent | b209fd55656d0a2b7714c317d2a6656af4b1505e (diff) |
perltex 1.9 (20sep09)
git-svn-id: svn://tug.org/texlive/trunk@15387 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex')
-rw-r--r-- | Master/texmf-dist/source/latex/perltex/perltex.dtx | 319 |
1 files changed, 203 insertions, 116 deletions
diff --git a/Master/texmf-dist/source/latex/perltex/perltex.dtx b/Master/texmf-dist/source/latex/perltex/perltex.dtx index 51d6ae342fa..ea9bee773ea 100644 --- a/Master/texmf-dist/source/latex/perltex/perltex.dtx +++ b/Master/texmf-dist/source/latex/perltex/perltex.dtx @@ -22,7 +22,7 @@ %<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01] %<package>\ProvidesPackage{perltex} %<*package> - [2009/03/27 v1.8 LaTeX macros for use with PerlTeX] + [2009/09/13 v1.9 LaTeX macros for use with PerlTeX] %</package> % %<*driver> @@ -62,7 +62,7 @@ %</driver> % \fi % -% \CheckSum{594} +% \CheckSum{597} % % \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 @@ -130,6 +130,10 @@ % \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 @@ -141,9 +145,28 @@ % } % % +% ^^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{perlmacro}[1]{^^A +% \newenvironment{perlvar}{^^A % \begingroup % \catcode`\_=11 % \def\PrintMacroName##1{\strut\MacroFont\string##1\ }^^A @@ -153,7 +176,7 @@ % \string\verb\quotechar*\verbatimchar\string##1\verbatimchar##2}^^A % \@esphack % }^^A -% \begin{macro}{#1}^^A +% \begin{macro}^^A % }{^^A % \end{macro}^^A % \endgroup @@ -753,7 +776,7 @@ % 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 @@ -772,7 +795,7 @@ % 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} @@ -835,7 +858,7 @@ # Replace LaTeX code in the text with placeholders. $placeholder = "ABCxyz123"; - %substs; + %substs = (); $replace = sub {$substs{$placeholder} = $_[0]; $placeholder++}; $text =~ s/\\(begin|end)\s+\{[a-z]+\}/$replace->($&)/gse; $text =~ s/\\[a-z]+/$replace->($&)/gse; @@ -1840,10 +1863,10 @@ % & & & & Delete & \topl \\ % & & & & Delete & \dfpl \\ % & Await & \ffpl & $\leftarrow$ & Touch & \ffpl \\ -% & Read & \frpl & & & \\ % & Touch & \topl & $\rightarrow$ & Await & \topl \\ % & & & & Delete & \ffpl \\ % & Await & \dfpl & $\leftarrow$ & Touch & \dfpl \\ +% & Read & \frpl & & & \\ % \cline{2-3}\cline{5-6} % \end{tabular} % \MakeShortVerb\| @@ -1851,7 +1874,17 @@ % \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} @@ -1863,12 +1896,13 @@ % % 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 ``|\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 -% ``|\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. +% 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} @@ -1876,7 +1910,9 @@ % \end{macrocode} % \begin{macrocode} \newcommand{\plmac@await@existence}[1]{% - \input\plmac@pipe + \begin{lrbox}{\@tempboxa}% + \input\plmac@pipe + \end{lrbox}% \loop \IfFileExists{#1}% {\plmac@file@existstrue}% @@ -2077,6 +2113,8 @@ % 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> @@ -2154,6 +2192,7 @@ use Pod::Usage; use File::Basename; use Fcntl; use POSIX; +use IO::Handle; use warnings; use strict; % \end{macrocode} @@ -2166,10 +2205,10 @@ use strict; % variables. % % \paragraph{Variables corresponding to command-line arguments} -% \begin{perlmacro}{$latexprog} -% \begin{perlmacro}{$runsafely} -% \begin{perlmacro}{@permittedops} -% \begin{perlmacro}{$usepipe} +% \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 @@ -2185,21 +2224,21 @@ my $runsafely = 1; my @permittedops; my $usepipe = 1; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} % % \paragraph{Filename variables} -% \begin{perlmacro}{$progname} -% \begin{perlmacro}{$jobname} -% \begin{perlmacro}{$toperl} -% \begin{perlmacro}{$fromperl} -% \begin{perlmacro}{$toflag} -% \begin{perlmacro}{$fromflag} -% \begin{perlmacro}{$doneflag} -% \begin{perlmacro}{$logfile} -% \begin{perlmacro}{$pipe} +% \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 @@ -2225,23 +2264,23 @@ my $doneflag; my $logfile; my $pipe; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} % % \paragraph{Other global variables} -% \begin{perlmacro}{@latexcmdline} -% \begin{perlmacro}{$styfile} -% \begin{perlmacro}{@macroexpansions} -% \begin{perlmacro}{$sandbox} -% \begin{perlmacro}{$sandbox_eval} -% \begin{perlmacro}{$latexpid} +% \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 @@ -2260,14 +2299,14 @@ my $sandbox = new Safe; my $sandbox_eval; my $latexpid; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} +% \end{perlvar} % -% \begin{perlmacro}{$pipestring} +% \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 @@ -2285,7 +2324,7 @@ my $latexpid; % \begin{macrocode} my $pipestring = "\%\%\%\%\% Generated by $progname\n\\endinput\n"; % \end{macrocode} -% \end{perlmacro} +% \end{perlvar} % % \subsubsection{Command-line conversion} % @@ -2322,8 +2361,8 @@ GetOptions("help" => sub {pod2usage(-verbose => 1)}, % \end{macrocode} % % \paragraph{Preparing a \LaTeX{} command line} -% \begin{perlmacro}{$firstcmd} -% \begin{perlmacro}{$option} +% \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|. @@ -2341,10 +2380,10 @@ for ($firstcmd=0; $firstcmd<=$#latexcmdline; $firstcmd++) { } push @latexcmdline, "" if $#latexcmdline==-1; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} +% \end{perlvar} +% \end{perlvar} % -% \begin{perlmacro}{$separator} +% \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, @@ -2355,7 +2394,7 @@ foreach (1 .. 20) { $separator .= chr(ord("A") + rand(26)); } % \end{macrocode} -% \end{perlmacro} +% \end{perlvar} % % Now that we have the name of the \LaTeX{} job (|$jobname|) we can % assign |$toperl|, |$fromperl|, |$toflag|, |$fromflag|, |$doneflag|, @@ -2388,6 +2427,81 @@ $latexcmdline[$firstcmd] = $latexcmdline[$firstcmd]; % \end{macrocode} % +% \subsubsection{Increasing \PerlTeX's robustness} +% +% \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|, @@ -2399,17 +2513,8 @@ $latexcmdline[$firstcmd] = % 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. -% -% Note that here and elsewhere in \perltex, |unlink| is called -% repeatedly until the file is actually deleted. This works around a -% race condition that occurs in some filesystems in which file deletions -% are executed somewhat lazily. -% \changes{v1.0a}{2003/08/21}{Made all \texttt{unlink} calls wait for the -% file to actually disappear} % \begin{macrocode} -foreach my $file ($toperl, $fromperl, $toflag, $fromflag, $doneflag, $pipe) { - unlink $file while -e $file; -} +delete_files($toperl, $fromperl, $toflag, $fromflag, $doneflag, $pipe); open (LOGFILE, ">$logfile") || die "open(\"$logfile\"): $!\n"; if (defined $styfile) { open (STYFILE, ">$styfile") || die "open(\"$styfile\"): $!\n"; @@ -2418,6 +2523,7 @@ if (defined $styfile) { % \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; @@ -2467,38 +2573,14 @@ else { while (1) { % \end{macrocode} % -% \begin{perlmacro}{$awaitexists} -% We define a local subroutine |$awaitexists| which 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} -% \begin{macrocode} - my $awaitexists = sub { - while (!-e $_[0]) { - sleep 0; - if (waitpid($latexpid, &WNOHANG)==-1) { - foreach my $file ($toperl, $fromperl, $toflag, - $fromflag, $doneflag, $pipe) { - unlink $file while -e $file; - } - undef $latexpid; - exit 0; - } - } - }; -% \end{macrocode} -% \end{perlmacro} -% -% \begin{perlmacro}{$entirefile} +% \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); + awaitexists($toflag); my $entirefile; { local $/ = undef; @@ -2507,11 +2589,11 @@ while (1) { close TOPERL; } % \end{macrocode} -% \end{perlmacro} +% \end{perlvar} % -% \begin{perlmacro}{$optag} -% \begin{perlmacro}{$macroname} -% \begin{perlmacro}{@otherstuff} +% \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 @@ -2522,9 +2604,9 @@ while (1) { my ($optag, $macroname, @otherstuff) = map {chomp; $_} split "$separator\n", $entirefile; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} -% \end{perlmacro} +% \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 @@ -2549,7 +2631,7 @@ while (1) { } % \end{macrocode} % -% \begin{perlmacro}{$perlcode} +% \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|, @@ -2623,7 +2705,7 @@ while (1) { die "${progname}: Internal error -- unexpected operation tag \"$optag\"\n"; } % \end{macrocode} -% \end{perlmacro} +% \end{perlvar} % % Log what we're about to evaluate. % \begin{macrocode} @@ -2631,8 +2713,8 @@ while (1) { print LOGFILE $perlcode, "\n"; % \end{macrocode} % -% \begin{perlmacro}{$result} -% \begin{perlmacro}{$msg} +% \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 @@ -2691,8 +2773,8 @@ while (1) { } push @macroexpansions, $result if defined $styfile && $optag eq "USE"; % \end{macrocode} -% \end{perlmacro} -% \end{perlmacro} +% \end{perlvar} +% \end{perlvar} % % Log the resulting \LaTeX{} code. % \begin{macrocode} @@ -2718,9 +2800,7 @@ while (1) { close FROMPERL; % \end{macrocode} % \begin{macrocode} - unlink $toflag while -e $toflag; - unlink $toperl while -e $toperl; - unlink $doneflag while -e $doneflag; + delete_files($toflag, $toperl, $doneflag); % \end{macrocode} % \begin{macrocode} open (FROMFLAG, ">$fromflag") || die "open($fromflag): $!\n"; @@ -2728,6 +2808,7 @@ while (1) { % \end{macrocode} % \begin{macrocode} if (open (PIPE, ">$pipe")) { + autoflush PIPE 1; print PIPE $pipestring; close PIPE; } @@ -2738,17 +2819,23 @@ while (1) { % |$fromflag| already exists and race ahead, finding that |$fromperl| % does not contain what it's supposed to. % \begin{macrocode} - $awaitexists->($toperl); - unlink $fromflag while -e $fromflag; + 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|. +% 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} % |