3

Consider this MWE, test-0.tex:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents
\usepackage[utf8x]{inputenc}

\begin{filecontents}{test-1.tex}
\usepackage{tikz}
\usepackage{pgfplots}
\end{filecontents}
\input{test-1.tex}

\usepackage{lipsum}
\usepackage{hologo} % tlmgr install oberdiek; http://tex.stackexchange.com/a/7564/2595

\begin{document}

\lipsum[1]

This document was typeset with \hologo{pdfLaTeX}, using packages: \texttt{filecontents}, \texttt{inputenc}, \texttt{tikz}, \texttt{pgfplots}, \texttt{lipsum}, \texttt{hologo}.
\end{document}

I would like somehow to use a macro that will determine the first-level packages used automatically, so I could write instead something like pseudo-code:

This document was typeset with \hologo{pdfLaTeX}, using packages: \typesetUsedPackages.

By first-level packages, I mean packages that are used via \usepackage{} either in the main .tex file, or in (recursively) \input- or \included .tex files - but not packages that may be included from these first-level packages; the MWE shows what output I'd want.

(Also, it would be neat if the executable logo, and the documentclass used, could be determined and typeset automatically, e.g.:

This document was typeset with \typesedUsedExecutable in document class \typesetUsedDocumentclass; using packages: \typesetUsedPackages.

)

Is there anything like this out there?

1

Well, you can rely on the policy that in the preamble, one uses \usepackage, whereas in the packages and classes, it's \RequirePackage:

\documentclass[a4paper]{article}

\def\usedpackages{}
\let\xusepackage\usepackage
\renewcommand\usepackage[2][]{\edef\usedpackages{\usedpackages#2,}\xusepackage[#1]{#2}}

\usepackage[margin=0pt]{geometry}
\usepackage{pgffor}

\begin{document}

Packages:
\begin{itemize}
\foreach \x in \usedpackages{\ifx\x\empty\else \item \x \fi}
\end{itemize}

And the packages really got loaded with the options passed into it since
foreach is working and we get zero margins here.

\end{document}
  • Thanks for that, @tohecz - it seems much more convenient to concatenate in memory, and then use pgf \foreach to split at the commas; cheers! – sdaau Oct 14 '14 at 14:32
0

OK, managed to do something - but, of course, a more erudite answer will be greatly appreciated. First, here is the usage example:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\documentclass{article}

  %%% start scanning
  \input{_usedpackages.tex}


    \usepackage{filecontents} % tlmgr install filecontents
    \usepackage[utf8x]{inputenc}

    \begin{filecontents*}{test-1.tex}
    \usepackage{tikz}
    \usepackage{pgfplots}
    \end{filecontents*}
    \input{test-1.tex}

    \usepackage{lipsum}
    \usepackage{hologo} % tlmgr install oberdiek; http://tex.stackexchange.com/a/7564/2595


  %%% stop scanning - \typesetUsedPackages should be ready after this:
  \stopScanUsedPackages

\begin{document}

  \lipsum[1]

  This document was typeset with \hologo{pdfLaTeX}, using packages: \typesetUsedPackages.

  \typeout{USEDPACK \the\usedpacklinecnt,\the\usedpacklcnt: \typesetUsedPackages}

\end{document}

This code starts scanning on \input{_usedpackages.tex}, and it does so by redefining \usepackage so it first outputs the name of the package in a file usedpacks.texlog, one package name per line. (Since .sty packages are supposed to use \RequirePackage, I guess this in itself ensures that only "first-level" packages are collected).

The same _usedpackages.tex file defines \stopScanUsedPackages, this basically stops the file writing, re-reads it and composes a new macro where the content of each line is formatted with the style in \usedpackstyle (here \texttt{#1}), called \typesetUsedPackages. This macro is output in terminal as:

USEDPACK 6,6: \texttt {filecontents}, \texttt {inputenc}, \texttt {tikz}, \text
tt {pgfplots}, \texttt {lipsum}, \texttt {hologo}

... and the typeset result is:

test-0.png

Of course, you'd need the _usedpackages.tex file - and here it is; simply paste this snippet before the \documentclass in the previous example, and it will be generated (or just copy the part between \begin/\end{filecontents*}):

\RequirePackage{filecontents}
\begin{filecontents*}{_usedpackages.tex}

% NB: Clearly, these three - as any other \usepackages which
% execute before this code is run - will not show in
% used packages list (\typesetUsedPackages)
% http://stackoverflow.com/a/6677461/277826
\usepackage{ifthen} % provides \ifthenelse test
\usepackage{xifthen} % provides \isempty test; tlmgr install xifthen ifmtarg
\usepackage{xstring}

% this starts the scan at point of inclusion:
\newwrite\usedpackfile
\immediate\openout\usedpackfile=usedpacks.texlog

\let\oldusepackage\usepackage
\def\tempty{}
\renewcommand{\usepackage}[2][]{%
  %\immediate\write\usedpackfile{\string\texttt{#2}} % don't style here
  \immediate\write\usedpackfile{#2} %
  \ifthenelse {\isempty{#1}} %
  { %
    %\typeout{EMPTY} %
    \oldusepackage{#2} % optional argument empty
  } %
  { % else
    %\typeout{NOT EMPTY} %
    \oldusepackage[#1]{#2} % optional argument not empty
  } %
}


\newread\usedpackmyread
\newcount\usedpacklinecnt
\newcount\usedpacklcnt
\def\typesetUsedPackages{}
\def\usedpackstyle#1{\texttt{#1}}

% this stops the scan - insert right before \begin{document}
% (cannot get it to work with \newcommand?!)
\makeatletter
\def\stopScanUsedPackages{%
  \immediate\closeout\usedpackfile
  % http://tex.stackexchange.com/a/17674/2595
  % http://tex.stackexchange.com/a/207108/2595
  %  if using:
  %  \readline: ^^M at EOL (must \StrGobbleRight), ^^M at EOF (must \ifx\tmpline\empty)
  %  \read:      "" at EOL, \par at EOF (must \if\tmpline\par)
  %
  % get number of lines
  \immediate\openin\usedpackmyread=usedpacks.texlog
  \@whilesw\unless\ifeof\usedpackmyread\fi{%
    \readline\usedpackmyread t\expandafter o\csname tmpline\endcsname % this just has to be here to have the loop run; but using it to find non-empty lines
    \StrGobbleRight{\tmpline}{1}[\tmpline] % remove the ^^M newline (last char)
    \ifx\tmpline\empty\else %
      \advance\usedpacklinecnt by \@ne %
    \fi %
  }
  \immediate\closein\usedpackmyread
  % now read lines, do formatting & concat into macro \typesetUsedPackages
  \immediate\openin\usedpackmyread=usedpacks.texlog
  \@whilesw\unless\ifeof\usedpackmyread\fi{%
    \read\usedpackmyread to\tmpline %
    \if\tmpline\par\else %
      \advance\usedpacklcnt by \@ne %
      \StrGobbleRight{\tmpline}{1}[\tmpline] % still have to run this, to get rid of a space at end
      \protected@edef\typesetUsedPackages{\typesetUsedPackages \usedpackstyle{\tmpline}} %
      \typeout{cnts: \the\usedpacklcnt=\the\usedpacklinecnt} %
      \ifnum\the\usedpacklcnt=\the\usedpacklinecnt %
        \typeout{YES} %
      \else % if not on last line
        \typeout{NO} %
        \protected@edef\typesetUsedPackages{\typesetUsedPackages,\space} %
      \fi %
    \fi %
  }
  \immediate\closein\usedpackmyread
} % end \def
\makeatother

\end{filecontents*}
%

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.