1

Is it possible to get the relative path used in the call to \documentclass so that I can use \input inside a document class, to import files relative to the .cls file?

Example folder structure:

./cls/class.cls
./cls/otherfiles/otherfile.tex
./document/document.tex

I use \documentclass{../cls/class} to import my class.

I'd like to use \input{otherfiles/otherfile} in my class.cls to easily separate some code blocks for better readability.

However, including the document class in ./document/document.tex leads to LaTeX Error: File otherfiles/otherfile.tex` not found..

2
  • All file input is relative to document.tex, so you need \documentclass{../cls/otherfiles/otherfile} Mar 19, 2020 at 12:32
  • Is there a way to get the relative path from document.tex to the class file class.cls in the class iteself?
    – Carsten
    Mar 19, 2020 at 12:52

1 Answer 1

1

Here's a macro to extract the path from the call to a class or package file. If your class file is test.cls, if you call \getrelativepath\thispath{test.cls} then the macro \thispath will contain the relative path used in \documentclass. If no relative path was used the macro will be empty, so you can safely use \input{\thispath otherfile.tex}. This command will only work when used inside a .cls or .sty file, as it relies on LaTeX's file handling code. If you use it in the document you'll get an error.

Here's the code. I put it in a filecontents environment to make it a working example. The second block is the bulk of the definition, and the third one is an example usage:

\begin{filecontents*}{test.cls}
\LoadClass{article}
\RequirePackage{expl3}
\ExplSyntaxOn
\str_new:N \l__carsten_tmpa_str
\cs_new_protected:Npn \__carsten_tmp:w { }
\cs_new_protected:Npn \getrelativepath #1 #2
  {
    \str_set:Nx \l__carsten_tmpa_str { \@currname.\@currext }
    \exp_args:NV \str_if_in:NnTF \l__carsten_tmpa_str {#2}
      {
        \str_if_eq:VnTF \l__carsten_tmpa_str {#2}
          { \tl_set:Nn #1 { } }
          { \exp_args:Nx \__carsten_parse_path:nN { \tl_to_str:n {#2} } #1 }
      }
      { \msg_error:nnxx { carsten } { wrong-path } {#2} { \l__carsten_tmpa_str } }
  }
\cs_new_protected:Npn \__carsten_parse_path:nN #1 #2
  {
    \cs_set_protected:Npn \__carsten_tmp:w ##1 #1 \q_mark ##2 ##3 \q_stop
      {
        \quark_if_nil:nTF {##2}
          { \tl_set:Nn #2 {##1} }
          { \msg_error:nn { carsten } { unexpected-error } }
      }
    \use:x
      {
        \__carsten_tmp:w
          \exp_not:V \l__carsten_tmpa_str \exp_not:n { \q_mark \q_nil }
                        \tl_to_str:n {#1} \exp_not:n { \q_mark \q_mark }
            \exp_not:N \q_stop
      }
  }
\msg_new:nnn { carsten } { wrong-path }
  { Unexpected~path~error.~'#1'~not~found~in~'#2'. }
\msg_new:nnn { carsten } { unexpected-error }
  { This~should~not~happen. }
\ExplSyntaxOff
\getrelativepath\thispath{test.cls}

\end{filecontents*}
\documentclass{../tex.sx/test}
\begin{document}

\texttt{\thispath}

\end{document}

On my system it prints:

enter image description here

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.