Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Let's say that I would like to redefine \@seccntformat so that whenever the section counter is printed, it is prefixed by Section, but other counters should no be changed.

Here is my failed attempt:

\documentclass{article}

\makeatletter
\def\mytest{section}%
\def\myarg#1{#1}
\def\@seccntformat#1{%
  \ifx\myarg#1\mytest{Section}\fi%
  \csname the#1\endcsname\quad}
\makeatother

\begin{document}
\section{Foo}  % Should be printed as "Section 1  Foo"
\subsection{Bar}  % Should be printed as "1.1  Bar"
\end{document}

For some reason I can't manage to get \myarg#1 and \mytest to compare equal when #1 is section. Now this is my first time using \ifx, so I hope I'm missing something trivial.

I would appreciate some hints about how to debug such a macro. Is there a way to see each intermediate expansion step and observe what arguments \ifx is actually receiving?

share|improve this question

1 Answer 1

up vote 9 down vote accepted

The conditional \ifx does no expansion and it compares the next two tokens. So in your test it compares \myarg with the first token in #1.

Therefore the test will be always false, because #1 is the name of a section level counter.

Adding \expandafter before \ifx would not help, even adding braces around #1:

\expandafter\ifx\myarg{#1}\mytest

would become

\ifx section\mytest

which returns false, as it compares s with e.

You could use \pdfstrcmp (or, better, \pdf@strcmp with the pdftexcmds package):

\def\@seccntformat#1{%
  \ifnum\pdf@strcmp{#1}{section}=\z@
    Section % a space is wanted
  \fi
  \csname the#1\endcsname\quad}

Complete example:

\documentclass{article}
\usepackage{pdftexcmds}

\makeatletter
\def\@seccntformat#1{%
  \ifnum\pdf@strcmp{#1}{section}=\z@
    Section %
  \fi
  \csname the#1\endcsname\quad}
\makeatother

\begin{document}
\section{Foo}  % Should be printed as "Section 1  Foo"
\subsection{Bar}  % Should be printed as "1.1  Bar"
\end{document}

enter image description here

Note that the attempt of doing the comparison with \ifx in the following way

\def\section@argument{section}
\def\@seccntformat#1{%
  \def\@argument{#1}%
  \ifx\@argument\section@argument
    Section %
  \fi
  \csname the#1\endcsname\quad}

wouldn't work either. This is because \@seccntformat is passed through an \edef (in the form \protected@edef), so we'd get an error

Undefined control sequence

for \@argument. Adding \noexpand in front of \@argument wouldn't help, because the conditional is expanded during the \edef. This instead would work

\def\section@argument{section}
\def\@seccntformat#1{%
  \unexpanded{%
    \def\@argument{#1}%
    \ifx\@argument\section@argument
      Section %
    \fi
  }
  \csname the#1\endcsname\quad
}

because the argument to \unexpanded is not changed during an \edef, so it will be processed afterwards, when typesetting is involved.

Note that the \protected@edef is necessary because we must get the expansion of \thesection or \thesubsection at the moment the macro \@seccntformat is executed. An \unexpanded free solution is possible, by hiding the part in a macro:

\def\section@argument{section}
\def\check@section#1{%
   \def\@argument{#1}%
   \ifx\@argument\section@argument
     Section %
   \fi
}
\def\@seccntformat#1{%
  \noexpand\check@section{#1}%
  \csname the#1\endcsname\quad}
share|improve this answer
    
Using inner \defs was actually my first try, and I had to move them out of the macro because of the Undefined control sequence error which I did not understand. Thank you for explaining that as well! –  adl Jul 26 at 11:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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