diff options
Diffstat (limited to 'Master/bin/powerpc-darwin/perltex')
-rwxr-xr-x | Master/bin/powerpc-darwin/perltex | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/Master/bin/powerpc-darwin/perltex b/Master/bin/powerpc-darwin/perltex new file mode 100755 index 00000000000..9c85ef94500 --- /dev/null +++ b/Master/bin/powerpc-darwin/perltex @@ -0,0 +1,476 @@ +#! /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) 2007 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. +#------------------------------------------------------------------- + +sub top_level_eval ($) +{ + return eval $_[0]; +} +use Safe; +use Opcode; +use Getopt::Long; +use Pod::Usage; +use File::Basename; +use Fcntl; +use POSIX; +use warnings; +use strict; +my $latexprog; +my $runsafely = 1; +my @permittedops; +my $usepipe = 1; +my $progname = basename $0; +my $jobname = "texput"; +my $toperl; +my $fromperl; +my $toflag; +my $fromflag; +my $doneflag; +my $logfile; +my $pipe; +my @latexcmdline; +my $styfile; +my @macroexpansions; +my $sandbox = new Safe; +my $sandbox_eval; +my $latexpid; +my $pipestring = "\%\%\%\%\% Generated by $progname\n\\endinput\n"; +$latexprog = $ENV{"PERLTEX"} || "latex"; +Getopt::Long::Configure("require_order", "pass_through"); +GetOptions("help" => sub {pod2usage(-verbose => 1)}, + "latex=s" => \$latexprog, + "safe!" => \$runsafely, + "pipe!" => \$usepipe, + "synctext=s" => \$pipestring, + "makesty" => sub {$styfile = "noperltex.sty"}, + "permit=s" => \@permittedops) || pod2usage(2); +@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; +my $separator = ""; +foreach (1 .. 20) { + $separator .= chr(ord("A") + rand(26)); +} +$toperl = $jobname . ".topl"; +$fromperl = $jobname . ".frpl"; +$toflag = $jobname . ".tfpl"; +$fromflag = $jobname . ".ffpl"; +$doneflag = $jobname . ".dfpl"; +$logfile = $jobname . ".lgpl"; +$pipe = $jobname . ".pipe"; +$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]; +foreach my $file ($toperl, $fromperl, $toflag, $fromflag, $doneflag, $pipe) { + unlink $file while -e $file; +} +open (LOGFILE, ">$logfile") || die "open(\"$logfile\"): $!\n"; +if (defined $styfile) { + open (STYFILE, ">$styfile") || die "open(\"$styfile\"): $!\n"; +} +if (!$usepipe || !eval {mkfifo($pipe, 0600)}) { + sysopen PIPE, $pipe, O_WRONLY|O_CREAT, 0755; + print PIPE $pipestring; + close PIPE; + $usepipe = 0; +} +defined ($latexpid = fork) || die "fork: $!\n"; +unshift @latexcmdline, $latexprog; +if (!$latexpid) { + exec {$latexcmdline[0]} @latexcmdline; + die "exec('@latexcmdline'): $!\n"; +} +if ($runsafely) { + @permittedops=(":browse") if $#permittedops==-1; + $sandbox->permit_only (@permittedops); + $sandbox_eval = sub {$sandbox->reval($_[0])}; +} +else { + $sandbox_eval = \&top_level_eval; +} +while (1) { + 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; + } + } + }; + $awaitexists->($toflag); + my $entirefile; + { + local $/ = undef; + open (TOPERL, "<$toperl") || die "open($toperl): $!\n"; + $entirefile = <TOPERL>; + close TOPERL; + } + my ($optag, $macroname, @otherstuff) = + map {chomp; $_} split "$separator\n", $entirefile; + $macroname =~ s/^[^A-Za-z]+//; + $macroname =~ s/\W/_/g; + $macroname = "latex_" . $macroname; + if ($optag eq "USE") { + foreach (@otherstuff) { + s/\\/\\\\/g; + s/\'/\\\'/g; + $_ = "'$_'"; + } + } + 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"; + } + print LOGFILE "#" x 31, " PERL CODE ", "#" x 32, "\n"; + print LOGFILE $perlcode, "\n"; + 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/\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"; + print LOGFILE "%" x 30, " LATEX RESULT ", "%" x 30, "\n"; + print LOGFILE $result, "\n\n"; + $result .= '\endinput'; + open (FROMPERL, ">$fromperl") || die "open($fromperl): $!\n"; + syswrite FROMPERL, $result; + close FROMPERL; + unlink $toflag while -e $toflag; + unlink $toperl while -e $toperl; + unlink $doneflag while -e $doneflag; + open (FROMFLAG, ">$fromflag") || die "open($fromflag): $!\n"; + close FROMFLAG; + if (open (PIPE, ">$pipe")) { + print PIPE $pipestring; + close PIPE; + } + $awaitexists->($toperl); + unlink $fromflag while -e $fromflag; + open (DONEFLAG, ">$doneflag") || die "open($doneflag): $!\n"; + close DONEFLAG; + if (open (PIPE, ">$pipe")) { + print PIPE $pipestring; + close PIPE; + } +} +END { + close LOGFILE; + if (defined $latexpid) { + kill (9, $latexpid); + exit 1; + } + + if (defined $styfile) { + 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} + +\let\noperltex@PackageError=\PackageError +\renewcommand{\PackageError}[3]{} +\RequirePackage{perltex} +\let\PackageError=\noperltex@PackageError + +\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 + ; + 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__ + +=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> |