%% LaTeX2e file `pstool.sty'
%% generated by the `filecontents' environment
%% from source `pstool' on 2008/08/31.
%%
\ProvidesPackage{pstool}[2008/08/31 v1.0
  Wrapper for processing PostScript/psfrag figures]

% External packages
\RequirePackage{%
  catchfile,color,ifpdf,ifplatform,graphicx,psfrag,suffix,xkeyval}
\RequirePackage{inversepath}[2008/07/31 v0.2]

% Allocations
\newif\if@pstool@always@
\newif\if@pstool@never@
\newif\if@pstool@pdfcrop@
\newif\if@pstool@verbose@
\newwrite\pstool@out

% These are cute
\providecommand\OnlyIfFileExists[2]{\IfFileExists{#1}{#2}{}}
\providecommand\NotIfFileExists[2]{\IfFileExists{#1}{}{#2}}

% \subsection{Package options}

\define@choicekey*{pstool.sty}{crop}[\@tempa\@tempb]{preview,pdfcrop}{%
  \ifcase\@tempb\relax
    \@pstool@pdfcrop@false
  \or
    \@pstool@pdfcrop@true
  \or
  \fi
}

\define@choicekey*{pstool.sty}{process}[\@tempa\@tempb]{all,none,auto}{%
  \ifcase\@tempb\relax
    \@pstool@always@true
  \or
    \@pstool@never@true
  \or
  \fi
}

\define@choicekey*{pstool.sty}{mode}
  [\@tempa\@tempb]{errorstop,nonstop,batch}{%
    \ifnum\@tempb=2\relax
      \@pstool@verbose@false
    \else
      \@pstool@verbose@true
    \fi
    \edef\pstool@mode{\@tempa mode}%
}
\ExecuteOptionsX{mode=batch}

\DeclareOptionX{cleanup}{\def\pstool@rm@files{#1}}
\ExecuteOptionsX{cleanup={.tex,.dvi,.ps,.pdf,.log,.aux}}

\DeclareOptionX{suffix}{\def\pstool@suffix{#1}}
\ExecuteOptionsX{suffix={-pstool}}

\ifshellescape\else
  \ExecuteOptionsX{process=none}
  \PackageWarning{pstool}{^^J\space\space%
    Package option [process=none] activated^^J\space\space
    because -shell-escape is not enabled.^^J%
    This warning occurred}
\fi

\ProcessOptionsX

% \section{Macros}

% Used to echo information to the console output.
% Can't use \typeout because it's asynchronous with
% any |\immediate\write18| processes (for some reason).
\def\pstool@echo#1{%
  \if@pstool@verbose@
    \pstool@echo@verbose{#1}%
  \fi}

\def\pstool@echo@verbose#1{%
  \immediate\write18{echo "#1"}%
}

\let\pstool@includegraphics\includegraphics

% Command line abstractions between platforms:
\edef\pstool@cmdsep{\ifwindows\string&\else\string;\fi\space}
\edef\pstool@rm@cmd{\ifwindows del \else rm -- \fi}

% Delete a file if it exists (only the filename is supplied and the path is inferred):
\newcommand\pstool@rm[2]{%
  \OnlyIfFileExists{#1#2}{%
    \immediate\write18{%
      cd "#1"\pstool@cmdsep\pstool@rm@cmd "#2"}}%
}

% Generic function to execute a command on the shell and pass its exit status back into \LaTeX. Any number of \cmd\pstool@exe\ statements can be made consecutively followed by \cmd\pstool@endprocess, which also takes an argument. If \emph{any} of the shell calls failed, then the execution immediately skips to the end and expands \cmd\pstool@error\ instead of the argument to \cmd\pstool@endprocess.
%
% |#1|: `name' of process\\
% |#2|: relative path where to execute the command\\
% |#3|: the command itself
\newcommand\pstool@exe[3]{%
  \pstool@echo{^^J=== pstool: #1 ===}%
  \pstool@shellexecute{#2}{#3}%
  \pstool@retrievestatus{#2}%
  \ifnum\pstool@status > \z@
    \PackageWarning{pstool}{Execution failed during process:^^J\space\space#3^^JThis warning occurred}%
    \expandafter\pstool@abort
  \fi}

% Edit this definition to print something else when graphic processing fails.
\def\pstool@error{\fbox{\parbox{0.8\linewidth}{\color{red}\raggedright\ttfamily\scshape\small
  An error occured processing graphic \upshape`\ip@directpath\ip@lastelement'}}}

\def\pstool@abort#1\pstool@endprocess{\pstool@error\@gobble}
\let\pstool@endprocess\@firstofone

% It is necessary while executing commands on the shell to write the exit status to a temporary file to test for failures in processing. (If all versions of |pdflatex| supported input pipes, things might be different.)
\def\pstool@shellexecute#1#2{%
  \immediate\write18{%
    cd "#1" \pstool@cmdsep
    #2 \pstool@cmdsep
    \ifwindows
       call echo
         \string^\@percentchar ERRORLEVEL\string^\@percentchar
    \else
       echo \detokenize{$?}
    \fi
    > \pstool@statusfile}%
% That's the execution; now we need to flush the write buffer to the status file. This ensures the file is written to disk properly (allowing it to be read by \cmd\CatchFileEdef). Not necessary on Windows, whose file writing is evidently more crude/immediate.
  \ifwindows\else
    \immediate\write18{%
      touch #1\pstool@statusfile}%
  \fi}
\def\pstool@statusfile{pstool-statusfile.txt}

% Read the exit status from the temporary file and delete it.\\
% |#1| is the path\\
% Status is recorded in \cmd\pstool@status.
\def\pstool@retrievestatus#1{%
  \CatchFileEdef{\pstool@status}{#1\pstool@statusfile}{}%
  \pstool@rm{#1}{\pstool@statusfile}%
  \ifx\pstool@status\pstool@statusfail
    \PackageWarning{pstool}{%
      Status of process unable to be determined:^^J  #1^^J%
      Trying to proceed... }%
    \def\pstool@status{0}%
  \fi}
\def\pstool@statusfail{\par }% what results when \TeX\ reads an empty file

% \subsection{File age detection}
% Use |ls| (or |dir|) to detect if the EPS is newer than the PDF.
\def\pstool@IfnewerEPS{%
  \edef\pstool@filenames{\ip@lastelement.eps\space \ip@lastelement.pdf\space}%
  \immediate\write18{%
    cd "\ip@directpath"\pstool@cmdsep
    \ifwindows
      dir /T:W /B /O-D "\ip@lastelement.eps" "\ip@lastelement.pdf" > \pstool@statusfile
    \else
      ls -t "\ip@lastelement.eps" "\ip@lastelement.pdf" > \pstool@statusfile
    \fi
  }%
  \pstool@retrievestatus{\ip@directpath}%
  \ifx\pstool@status\pstool@filenames
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

% A wrapper for \cs{inversepath*}. Long story short, always need a relative path to a filename even if it's in the same directory.
\def\pstool@getpaths#1{%
  \edef\@tempa{\unexpanded{\inversepath*}{#1}}%
  \@tempa% calculate filename, path \& inverse path
  \ifx\ip@directpath\@empty
    \def\ip@directpath{./}%
  \fi
% Strip off a possible wayward |.eps| suffix.
  \edef\ip@lastelement{%
    \expandafter\pstool@stripEPS\ip@lastelement.eps\@nil
  }%
}

\def\pstool@stripEPS#1.eps#2\@nil{#1}
% |test.eps\@nil|->|test|\\
% |test.eps.eps\@nil|->|test|

% \section{Command parsing}
% User input is \cmd\pstool\ (with optional |*| or |!| suffix) which turns into one of the following three macros depending on the mode.

\newcommand\pstool@alwaysprocess[3][]{%
  \pstool@getpaths{#2}%
  \pstool@process{#1}{#3}}

\newcommand\pstool@neverprocess[3][]{%
  \pstool@includegraphics[#1]{#2}}

% For regular operation, which processes the figure only if
% the command is starred, or the PDF doesn't exist.
\newcommand\pstool@maybeprocess[3][]{%
  \pstool@getpaths{#2}%
  \IfFileExists{#2.pdf}{%
    \pstool@IfnewerEPS{% needs info from |\pstool@getpaths|
      \pstool@process{#1}{#3}%
    }{%
      \pstool@includegraphics[#1]{#2}%
    }%
  }{%
    \pstool@process{#1}{#3}%
  }}

% \section{User commands}
%  Finally, define \cmd\pstool\ as appropriate for the mode:
\ifpdf
  \if@pstool@always@
    \let\pstool\pstool@alwaysprocess
    \WithSuffix\def\pstool!{\pstool@alwaysprocess}
    \WithSuffix\def\pstool*{\pstool@alwaysprocess}
  \else\if@pstool@never@
    \let\pstool\pstool@neverprocess
    \WithSuffix\def\pstool!{\pstool@neverprocess}
    \WithSuffix\def\pstool*{\pstool@neverprocess}
  \else
    \let\pstool\pstool@maybeprocess
    \WithSuffix\def\pstool!{\pstool@neverprocess}
    \WithSuffix\def\pstool*{\pstool@alwaysprocess}
  \fi\fi
\else
  \let\pstool\pstool@neverprocess
  \WithSuffix\def\pstool!{\pstool@neverprocess}
  \WithSuffix\def\pstool*{\pstool@neverprocess}
\fi

% \section{The figure processing}

% \cmd\ip@lastelement\ is the filename of the figure stripped of its path (if any)
\def\pstool@jobname{\ip@lastelement\pstool@suffix}

% And this is the main macro.
\newcommand\pstool@process[2]{%
  \pstool@echo@verbose{^^J=== pstool: begin processing ===}%
  \pstool@write@processfile{#1}{\ip@directpath\ip@lastelement}{#2}%
  \pstool@exe{auxiliary process: \ip@lastelement\space}
    {./}{latex
      -shell-escape
      -output-format=dvi
      -output-directory="\ip@directpath"
      -interaction=\pstool@mode\space
          "\pstool@jobname.tex"}%
% Execute dvips in quiet mode if latex is run in (non/error)stop mode:
  \pstool@exe{dvips}{\ip@directpath}{%
    dvips \if@pstool@verbose@\else -q \fi -Ppdf "\pstool@jobname.dvi"}%
  \if@pstool@pdfcrop@
    \pstool@exe{ps2pdf}{\ip@directpath}{%
      ps2pdf "\pstool@jobname.ps" "\pstool@jobname.pdf"}%
    \pstool@exe{pdfcrop}{\ip@directpath}{%
      pdfcrop "\pstool@jobname.pdf" "\ip@lastelement.pdf"}%
  \else
    \pstool@exe{ps2pdf}{\ip@directpath}{%
      ps2pdf "\pstool@jobname.ps" "\ip@lastelement.pdf"}%
  \fi
  \pstool@echo{^^J=== pstool: end processing ===^^J}%
  \pstool@endprocess{%
    \pstool@cleanup
    \pstool@includegraphics[#1]{\ip@directpath\ip@lastelement}}}

% The file that is written for processing is set up to read the preamble of the original document and set the graphic on an empty page (cropping to size is done either here with \pkg{preview} or later with \pkg{pdfcrop}).
\def\pstool@write@processfile#1#2#3{%
    \immediate\openout\pstool@out #2\pstool@suffix.tex\relax
    \immediate\write\pstool@out{%
      \noexpand\pdfoutput=0^^J% force DVI mode if not already
%
% Input the main document; redefine the document environment so only the preamble is read:
      \unexpanded{%
        \let\origdocument\document^^J%
        \let\EndPreamble\endinput^^J%
        \def\document{\endgroup\endinput}^^J}%
      \noexpand\input{\jobname}^^J%
%
% Now the preamble of the process file: (restoring document's original meaning; empty \cmd\pagestyle\ removes the page number)
      \if@pstool@pdfcrop@\else
        \noexpand\usepackage[active,tightpage]{preview}^^J%
      \fi
      \unexpanded{%
        \let\document\origdocument^^J%
        \pagestyle{empty}^^J}%
%
% And the document body to place the graphic on a page of its own:
      \unexpanded{%
        \begin{document}^^J%
        \centering\null\vfill^^J}%
      \if@pstool@pdfcrop@\else
        \noexpand\begin{preview}^^J%
      \fi
      \unexpanded{#3^^J}% this is the "psfrag" material
      \noexpand\includegraphics[#1]{\ip@lastelement}^^J%
      \if@pstool@pdfcrop@\else
        \noexpand\end{preview}^^J%
      \fi
      \unexpanded{%
        \vfill\end{document}}^^J%
      }%
    \immediate\closeout\pstool@out}

\def\pstool@cleanup{%
  \@for\@ii:=\pstool@rm@files\do{%
    \pstool@rm{\ip@directpath}{\pstool@jobname\@ii}%
}}

\providecommand\EndPreamble{}

% \section{User commands}
%
% These all support the suffixes |*| and |!|, so each user command is defined as a wrapper to \cmd\pstool.

% for EPS figures with psfrag:
\newcommand\psfragfig[2][]{\pstool@psfragfig{#1}{#2}{}}
\WithSuffix\newcommand\psfragfig*[2][]{\pstool@psfragfig{#1}{#2}{*}}
\WithSuffix\newcommand\psfragfig![2][]{\pstool@psfragfig{#1}{#2}{!}}

% Parse optional \<input definitions>
\newcommand\pstool@psfragfig[3]{%
  \@ifnextchar\bgroup{%
    \pstool@@psfragfig{#1}{#2}{#3}%
  }{%
    \pstool@@psfragfig{#1}{#2}{#3}{}%
  }%
}

% Search for both \<filename> and \<filename>|-psfrag| inputs.
\newcommand\pstool@@psfragfig[4]{%
  \IfFileExists{#2-psfrag.eps}{%
    \def\pstool@eps{#2-psfrag}%
    \OnlyIfFileExists{#2.eps}{%
      \PackageWarning{pstool}{Graphic "#2.eps" exists but "#2-psfrag.eps" is being used}%
    }%
  }{%
    \IfFileExists{#2.eps}{%
      \def\pstool@eps{#2}%
    }{%
      \PackageError{pstool}{%
        No graphic "#2.eps" or "#2-psfrag.eps" found%
      }{%
        Check the path and whether the file exists.%
      }%
    }%
  }%
  \pstool#3[#1]{\pstool@eps}{%
    \InputIfFileExists{#2-psfrag.tex}{%
      \OnlyIfFileExists{#2.tex}{%
        \PackageWarning{pstool}{%
          File "#2.tex" exists that may contain macros for "\pstool@eps.eps"^^J%
          But file "#2-psfrag.tex" is being used instead.%
        }%
      }%
    }{%
      \InputIfFileExists{#2.tex}{}{}%
    }%
    #4%
  }%
}

