% \iffalse meta-comment
% (The MIT License)
%
% Copyright (c) 2021-2022 Yegor Bugayenko
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the 'Software'), to deal
% in the Software without restriction, including without limitation the rights
% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
% copies of the Software, and to permit persons to whom the Software is
% furnished to do so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included in all
% copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
% SOFTWARE.
% \fi

% \CheckSum{0}
%
% \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         \~}

% \GetFileInfo{iexec.dtx}
% \DoNotIndex{\endgroup,\begingroup,\let,\else,\fi,\newcommand,\newenvironment}

% \iffalse
%<*driver>
\ProvidesFile{iexec.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{iexec}
%<*package>
[2022-10-12 0.9.0 Inputable Shell Executions]
%</package>
%<*driver>
\documentclass{ltxdoc}
\usepackage[tt=false, type1=true]{libertine}
\usepackage{microtype}
\usepackage{iexec}
\usepackage{href-ul}
\PageIndex
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
	\DocInput{iexec.dtx}
	\PrintChanges
	\PrintIndex
\end{document}
%</driver>
% \fi

% \title{|iexec|: \LaTeX{} Package \\ for Inputable Shell Executions\thanks{The sources are in GitHub at \href{https://github.com/yegor256/iexec}{yegor256/iexec}}}
% \author{Yegor Bugayenko \\ \texttt{yegor256@gmail.com}}
% \date{\filedate, \fileversion}
%
% \maketitle
%
% \section{Introduction}
%
% This package helps you execute shell commands right from the
% document and then put their output to the document:
%
% \begin{multicols}{2}
% \setlength{\parskip}{0pt}
% \small
% \raggedcolumns
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
Today is
  \iexec{date +\%e-\%b-\%Y}
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi
%
% \columnbreak
%
% Today is \iexec[log]{date +\%e-\%b-\%Y}
% \end{multicols}

% \DescribeMacro{\iexec}
% The only command provided by this package is |\iexec| \oarg{options} \marg{cmd}.
% Its only mandatory argument \meta{cmd} is the command to be executed
% through the terminal shell (bash, or whatever is set as the default one
% on your user console).

% You have to run |pdflatex| (or just |latex|)
% with the |--shell-escape| flag
% in order to let |shellesc| (the package we use)
% to execute your shell command.

% \section{Options}

% \DescribeMacro{quiet}
% If you don't want the output to be visible,
% use |\phantom\{\iexec{...}}|.
% Otherwise, you can use |quiet| option:
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
I just want to delete some file:
\iexec[quiet]{rm -f foo.txt}
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi
% In this case, whatever the shell command produces will not be included
% into the document.

% \DescribeMacro{stdout}
% The output of your code is saved into the file provided as an
% optional argument of |\iexec| (the default value is |iexec.tmp|):
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
Today is \iexec[stdout=date.txt]{date +\%e-\%b-\%Y | tr -d '\\n'}.
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi
% The tailing part of the command here removes all ends-of-line.

% \DescribeMacro{stderr}
% The error output of the code is saved into the file provided as an
% optional argument of |\iexec| (by default the error output
% is streamed into |stdout|):
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
Today is \iexec[stderr=my.txt]{broken-command}.
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi

% \DescribeMacro{trace}
% The file specified will be deleted right after its usage. If you don't
% want this to happen, use |trace| package option: all files will remain
% in the directory where they were created.
% It's possible to turn tracing on globbaly, for the entire document, using
% |trace| option of the package:
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage[trace]{iexec}
\begin{document}
This file won't be deleted: \iexec[stdout=me.txt]{whoami}.
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi

% \DescribeMacro{append}
% The stdout produced will be appended to the file specified:
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage[trace]{iexec}
\begin{document}
\iexec[append,stdout=foo.txt,quiet]{echo 'Hello, '}
\iexec[append,stdout=foo.txt,quiet]{echo 'Jeffrey!'}
\input{foo.txt}
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi

% \DescribeMacro{log}
% The stdout produced will be printed in \TeX{} log:
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
\iexec[log]{echo 'Hello, \\LaTeX!'}
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi

% \DescribeMacro{null}
% The stdout of the command will be sent to |/dev/null|:
%\iffalse
%<*verb>
%\fi
\begin{verbatim}
\documentclass{article}
\usepackage{iexec}
\begin{document}
\iexec[null]{rm some-file.txt}
\end{document}
\end{verbatim}
%\iffalse
%</verb>
%\fi

% \StopEventually{}

% \section{Implementation}

% \changes{v0.2.0}{2021/07/10}{Initial version}
% \changes{v0.4.0}{2021/08/01}{Runtime verification for --shell-escape option}
% \changes{v0.4.1}{2021/08/08}{Options trace, stdout, and quiet added}
% \changes{v0.5.0}{2022/01/08}{Major bug fixes}
% \changes{v0.6.0}{2022/10/09}{Additional options 'log' and 'append'}
% \changes{v0.7.0}{2022/10/10}{Additional option 'null'}
% \changes{v0.8.0}{2022/10/11}{Bug fixes}
% \changes{v0.9.0}{2022/10/12}{Additional option 'stderr'}

% First, we include a few packages:
%    \begin{macrocode}
\RequirePackage{shellesc}
\RequirePackage{pgfkeys}
\RequirePackage{expl3}
%    \end{macrocode}

% Then, we parse package options:
%    \begin{macrocode}
\RequirePackage{xkeyval}
\makeatletter\newif\ifiexec@trace
\DeclareOptionX{trace}{\iexec@tracetrue}
\ProcessOptionsX\relax\makeatother
\makeatletter\pgfkeys{
  /iexec/.is family,
  /iexec,
  stdout/.estore in = \iexec@stdout,
  stdout/.default = iexec.tmp,
  stderr/.estore in = \iexec@stderr,
  trace/.estore in = \iexec@traceit,
  append/.estore in = \iexec@append,
  log/.estore in = \iexec@log,
  null/.estore in = \iexec@null,
  quiet/.estore in = \iexec@quiet,
  stdout
}\makeatother
%    \end{macrocode}

% \begin{macro}{\iexec@typeout}
% Then, we define an internal command |\iexec@typeout| for printing the content of a file,
% as suggested \href{https://tex.stackexchange.com/questions/660808}{here}:
%    \begin{macrocode}
\makeatletter\ExplSyntaxOn
\NewDocumentCommand{\iexec@typeout}{m}{
  \iexec_typeout_file:n { #1 }}
\ior_new:N \g_iexec_typeout_ior
\cs_new_protected:Nn \iexec_typeout_file:n
{
  \ior_open:Nn \g_iexec_typeout_ior { #1 }
  \ior_str_map_inline:Nn \g_iexec_typeout_ior
    {\iow_term:n { ##1 }}
  \ior_close:N \g_iexec_typeout_ior
}
\ExplSyntaxOff\makeatother
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\iexec}
% Then, we define |\iexec| command.
% It is implemented with the help of |\ShellEscape| from |shellesc| package:
%    \begin{macrocode}
\makeatletter\newcommand\iexec[2][]{%
  \begingroup
    \pgfqkeys{/iexec}{#1}%
%    \end{macrocode}
% First, we verify that |latex| is running with |--shell-escape| option, since without
% it nothing will work; so, it's better to throw an error earlier than later:
%    \begin{macrocode}
    \ifdefined\pdfshellescape\ifnum\pdfshellescape=1\else%
      \PackageError{iexec}{You must run TeX processor with
      --shell-escape option}{}%
    \fi\fi%
    \begingroup%
%    \end{macrocode}
% Then, start the log from a clean line:
%    \begin{macrocode}
      \message{^^J}%
%    \end{macrocode}
% Then, we define a few special chars in order to escape them in the shell
% (the full
% list of them is in \href{https://ctan.mirror.norbert-ruehl.de/info/macros2e/macros2e.pdf}{macros2e}):
%    \begin{macrocode}
      \let\%\@percentchar%
      \let\\\@backslashchar%
      \let\{\@charlb%
      \let\}\@charrb%
%    \end{macrocode}
% Then, we execute it:
%    \begin{macrocode}
      \def\iexec@cmd{(#2)
        \ifdefined\iexec@append>\fi>
        \ifdefined\iexec@null/dev/null\else\iexec@stdout\fi
        \space\ifdefined\iexec@stderr2>\iexec@stderr\else2>&1\fi}
      \ShellEscape{\iexec@cmd}%
%    \end{macrocode}
% Then, a message is printed to TeX log:
%    \begin{macrocode}
      \message{iexec: [\iexec@cmd]^^J}%
    \endgroup%
%    \end{macrocode}
% Then, if required, the content of the stdout file will be printed to the log:
%    \begin{macrocode}
    \ifdefined\iexec@null\else
    \ifdefined\iexec@log
      \message{iexec: this is the content of \iexec@stdout:^^J}%
      \iexec@typeout{\iexec@stdout}
      \message{<EOF>^^J}%
    \fi\fi%
%    \end{macrocode}
% Then, include the produced output into the current document:
%    \begin{macrocode}
    \ifdefined\iexec@null\else
    \ifdefined\iexec@quiet
      \message{iexec: Due to 'quiet' option we didn't read
      the content of '\iexec@stdout' (\pdffilesize{} bytes)^^J}%
    \else%
      \message{iexec: We include the content of
        '\iexec@stdout' (\pdffilesize{} bytes)...^^J}%
      \input{\iexec@stdout}%
      \message{iexec: The content of '\iexec@stdout'
      was included into the document^^J}%
    \fi\fi%
%    \end{macrocode}
% Finally, delete the file or leave it untouched:
%    \begin{macrocode}
    \ifdefined\iexec@null\else
    \ifiexec@trace%
      \message{iexec: Due to package option 'trace',
      the file '\iexec@stdout' was not deleted^^J}%
    \else%
      \ifdefined\iexec@traceit%
        \message{iexec: Due to 'trace' option,
        the file '\iexec@stdout' was not deleted^^J}%
      \else%
        \ShellEscape{rm \iexec@stdout}%
        \message{iexec: The file '\iexec@stdout' was deleted^^J}%
      \fi%
    \fi\fi%
  \endgroup
}\makeatother
%    \end{macrocode}
% \end{macro}

% \Finale

%\clearpage
%
%\PrintChanges
%\clearpage
%\PrintIndex
