5

I am trying to make a macro that creates the path to a file from which a listing should be loaded based on its parameters. This fails very early.

Here is a schematic of what I am trying to do:

\documentclass{article}%
\RequirePackage{filecontents}%  for creating dummy contents for now
%
\edef\@dummyPath{\jobname.latexgit.dummy}%  the dummy file path
\begin{filecontents*}{\@dummyPath}
blabla
\end{filecontents*}
%
\def\getFilePath#1#2#3{%
\edef\@argA{#1}% <-- if I have this line, it fails
%% do more complicated stuff, return \@dummyPath as fallback if complicated stuff fails
\@dummyPath%
}%
%
\usepackage{listings}%
\begin{document}%
\lstinputlisting{\getFilePath{a}{b}{c}}%
\end{document}%

Now, the above is only a somewhat MWE showing my problem. My macro gets three parameters. It is supposed to expand the parameters as far as possible (in the future, they may also be macros or something) and do something with them. It is then supposed to "return" a string denoting a path to a file. (Sometimes, it may just return the dummy path, as in the example.)

If I pdflatex example_1.tex, then I get:

This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./example_1.tex
LaTeX2e <2021-11-15> patch level 1
L3 programming layer <2022-01-21>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2021/10/04 v1.4n Standard LaTeX document class
(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texlive/texmf-dist/tex/latex/filecontents/filecontents.sty

Package filecontents Warning: This package is obsolete. Disabling it and
(filecontents)                passing control to the filecontents environment
(filecontents)                defined by the LaTeX kernel.

)

LaTeX Info: File `example_1.latexgit.dummy' already exists on the system.
            Not generating it from this source.

(/usr/share/texlive/texmf-dist/tex/latex/listings/listings.sty
(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty)
(/usr/share/texlive/texmf-dist/tex/latex/listings/lstmisc.sty)
(/usr/share/texlive/texmf-dist/tex/latex/listings/listings.cfg))
(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def)
No file example_1.aux.
! Missing endcsname inserted.
<to be read again> 
                   edef 
l.17 \lstinputlisting{\getFilePath{a}{b}{c}}

Overall idea: I am making a tool a bit similar to BibTeX, but for external files. In other words, if everything works out:

  1. On the first pdflatex run, the \getFilePath would write something to the aux file and always return the path to the dummy file.
  2. The aux file would be processed by the external tool and some contents would be added to it.
  3. Then in the next pdflatex run, \getFilePath would return the paths to the actual files.

Now, I can get all of these steps to work, i.e., I can get \getFilePath to output actual file paths. But they do not work in conjunction with anything that actually uses the paths, i.e., like listings or something. And this fails already at the point in my MWE where I try to access the parameter values... :-(

7
  • @ isn't a letter in your preamble. (This isn't the main problem, but it doesn't help.)
    – cfr
    Nov 21 at 6:51
  • Try to get it working for a simple (non-verbatim) input first. (It is easier with expl3.) But I think you need to construct the name first rather than doing it all at once.
    – cfr
    Nov 21 at 7:02
  • 1
    Your \getFilePath isn't expandable, and hence can't be used in a file-path argument directly, as those have to be expandable. In effect, you have to either work by expansion only (would mean you're unable to write to the .aux, so impractical), or have to split your approach into two macros: The unexpandable setup so that \getFilePath sets an auxiliary macro like \theFilePath to the result, and the real access in which you then use \theFilePath, so \getFilePath{a}{b}{c}\lstinputlisting{\theFilePath}.
    – Skillmon
    Nov 21 at 7:10
  • Yes, the @ slipped in because I used my sty file as basis ... Nov 21 at 8:35
  • OK, so making two sets of commands it is. This sounds like a feasible solution. Thanks. Nov 21 at 8:36

1 Answer 1

3

Your problem stems from the fact that \getFilePath isn't expandable, but you can only use expandable macros where (La)TeX expects a filename.

Unfortunately, you can't expandably write to the AUX file, so your macro can't be expandable by design. If you can't get rid of this AUX-dependency (which I'd guess is unlikely) you'll have to change your approach to a two step solution. Your first step should process your macro arguments and do the unexpandable stuff, and at the end set an auxiliary macro that expands to the chosen name. You can then use that auxiliary for your file accesses.

As an aside: You shouldn't use \def on more or less generic macro names directly. You can still use \def if you check whether the name is free by using \@ifdefinable.

\documentclass{article}%
\RequirePackage{filecontents}%  for creating dummy contents for now
%
\makeatletter
\edef\@dummyPath{\jobname.latexgit.dummy}%  the dummy file path
\begin{filecontents*}{\@dummyPath}
blabla
\end{filecontents*}
%
\newcommand*\theFilePath{}% initialising the auxiliary macro
\@ifdefinable\getFilePath{\protected\def\getFilePath#1#2#3{%
  \edef\@argA{#1}% <-- if I have this line, it fails
  %% do more complicated stuff, return \@dummyPath as fallback if complicated stuff fails
  \let\theFilePath\@dummyPath%
}}
\makeatother
%
\usepackage{listings}%
\begin{document}%
\getFilePath{a}{b}{c}%
\lstinputlisting{\theFilePath}%
\end{document}%

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .