94

Is there a way to programmatically determine which document class is in effect?

I'd like to be able to write conditional macros that behave differently depending on which document class is currently being used.

6 Answers 6

104

You want the LaTeX kernel function \@ifclassloaded:

\makeatletter%
\@ifclassloaded{<someclass>}%
  {<true code>}%
  {<false coode>}%
\makeatother%
2
  • 20
    I am sure this is obvious for most people who have reason to use this but it was not for me (who wanted to hack a package out of the preamble when beamer is used): for this to work, you have to enclose it in \makeatletter and \makeatother.
    – Raphael
    Feb 23, 2012 at 10:27
  • What is the reason for why \makeatletter and \makeatother are necessary? Is that changing how the @ symbol is interpreted?
    – Paul Wintz
    Aug 11, 2020 at 10:33
22

If your package executes \@getclass then the current class name will be stored in \@currentclass which you can then test or print out as required (this is probably more general than using \@ifclassloaded which requires a class name in advance). You can define \@getclass like so

\def\@getcl@ss#1.cls#2\relax{\def\@currentclass{#1}}
\def\@getclass{\expandafter\@getcl@ss\@filelist\relax}

and use like:

\@getclass
\typeout{this document uses \@currentclass\space class}
17

Actually a class is loaded with the same internal macros like packages (both are officially "files with options") and LaTeX doesn't store the class file name in a specific macro. So you can't directly test which class was used, only test whether a specific class was used or not using \@ifclassloaded{<class>}{<true>}{<false>} (already mentioned in a previous answer).

Also keep in mind that a class can be based on another class by loading it with \LoadClass or \LoadClassWithOptions. In this case \@ifclassloaded will be true for both. However AFAIK the standard classes are not based on any other classes.

1
  • 3
    Well, the standard ltxdoc document class is based on article. :-) May 9, 2011 at 20:20
16

If you want to differentiate between KOMA-Script-classes (scrartcl, scrbook, scrreprt, scrlttr2) and other classes, you may also test for \KOMAClassName (which is defined by the former classes):

\@ifundefined{KOMAClassName}
  {<code for other classes>}
  {<code for KOMA-Script-classes>}
1
  • I need to have \renewcommand only in case a KOMA-script class is loaded. What do I safely write into the first brackets as code for other classes? Is a simple \relaxa good idea? Or can I leave it empty?
    – Keks Dose
    Feb 18, 2019 at 17:36
12

I came up with the following scenario, which isn't advisable in practice but which is of theoretical interest. David Carlisle's solution still works in this case but doesn't tell the complete story.

% Class file:
\ProvidesClass{testclass}[2012/02/05 v0.1 A test article class (AM)]
\NeedsTeXFormat{LaTeX2e}[2011/06/27]
\RequirePackage{catoptions}
\XDeclareOption*{%
  \ClassWarning{testclass}{Unknown option '\CurrentOption' ignored}%
}
\XProcessOptions*\relax
\endinput


% Document file:
\LoadClass[11pt]{article}
\documentclass{testclass}
\begin{document}
x
\end{document}

David Carlisle's solution

\def\@getcl@ss#1.cls#2\relax{\def\@currentclass{#1}}
\def\@getclass{\expandafter\@getcl@ss\@filelist\relax}
\@getclass
\typeout{This document uses class: \@currentclass}

gives 'article' as the class, while in reality it may be 'testclass' that the user needs. So my approach is to find all the classes in effect, upon which further action can be taken:

\robust@def*\@getdocumentclass{%
  \undefcs\currentclass
  \docommalist*\@filelist{%
    \filename@parse{##1}%
    \ifxFT\filename@ext\@clsextension{}{%
      \ifcsndefFT{opt@\filename@area\filename@base.\filename@ext}{}{%
        \edef\currentclass{%
          \csliststack,\currentclass
          \filename@area\filename@base.\filename@ext
        }%
      }%
    }%
  }%
  \ifdefTF\currentclass{%
    \typeout{This document uses class(es) in this order: \currentclass}%
  }{%
    \@latex@info{Package '\@currname.\@currext' loaded before
      \string\documentclass}%
  }%
}
\robust@def*\getdocumentclass{%
  \ifxTF\@filelist\relax{}{%
    \ifxTF\@filelist\@gobble{}{%
      \ifcsemptyTF\@filelist{}\@getdocumentclass
    }%
  }%
}

This can be called simply as

\getdocumentclass
1
  • I tried this example, but for \robust@def I get ! Undefined control sequence.; it turns out that macro is defined in CTAN: catoptions package.
    – sdaau
    Oct 14, 2014 at 22:31
10

Expanding on Ahmed's idea, here's some code with LaTeX3:

\RequirePackage{expl3}

\ExplSyntaxOn
\seq_new:N \l_pclist_classes_seq
\clist_map_inline:cn { @filelist }
  {
   \tl_if_in:nnT { #1 } { .cls }
     {
      \tl_set:Nn \l_tmpa_tl { #1 }
      \tl_remove_once:Nn \l_tmpa_tl { .cls }
      \seq_put_right:NV \l_pclist_classes_seq \l_tmpa_tl
     }
  }

\seq_if_in:NnTF \l_pclist_classes_seq { article }
  { \msg_term:x { The~class~`article'~is~loaded } }
  { \msg_term:x { The~class~`article'~is~NOT~loaded } }

\ExplSyntaxOff

The final lines show how the information can be used, by testing whether a class name appears in the sequence. One can similarly test what packages have been loaded so far.


Here's a more complete code, where three sequences are built where classes, packages and other files are stored, respectively:

\documentclass{ltxdoc}
\RequirePackage{expl3}

\ExplSyntaxOn
\seq_new:N \l_pclist_classes_seq
\seq_new:N \l_pclist_packages_seq
\seq_new:N \l_pclist_other_seq
\clist_map_inline:cn { @filelist }
  {
   \tl_if_in:nnTF { #1 } { .cls }
     {
      \tl_set:Nn \l_tmpa_tl { #1 }
      \tl_remove_once:Nn \l_tmpa_tl { .cls }
      \seq_put_right:NV \l_pclist_classes_seq \l_tmpa_tl
     }
     {
      \tl_if_in:nnTF { #1 } { .sty }
       {
        \tl_set:Nn \l_tmpa_tl { #1 }
        \tl_remove_once:Nn \l_tmpa_tl { .sty }
        \seq_put_right:NV \l_pclist_packages_seq \l_tmpa_tl
       }
       {
        \seq_put_right:Nn \l_pclist_other_seq { #1 }
       }
     }
  }

\seq_if_in:NnTF \l_pclist_classes_seq { article }
  { \msg_term:x { The~class~`article'~is~loaded } }
  { \msg_term:x { The~class~`article'~is~NOT~loaded } }

\seq_show:N \l_pclist_classes_seq
\seq_show:N \l_pclist_packages_seq
\seq_show:N \l_pclist_other_seq
\ExplSyntaxOff

The example uses ltxdoc as base class in order to show that it's item 0 in the "classes" sequence.

You must log in to answer this question.

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