Macro argument expansion problem in addcontentsline

I'm trying to add a section* to the toc with addcontentsline. It's a macro as part of a larger group of commands I'm working on. What I want is to add the toc entry based on a section level counter. But using a macro to get the string for the current section level in addcontentsline causes an error I can't figure out. This is a minimal (not)working example of my problem (I'm using overleaf btw.)

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{xifthen}        % If else commands

\makeatletter
\newcounter{counter@section@level}

\newcommand{\currentSectionString}{
\ifthenelse{\equal{\value{counter@section@level}}{0}}{section}{}
}

\makeatother

\begin{document}

\tableofcontents

\currentSectionString                    % to check the macro itself, works as expected

\section*{Foo}

\section*{Bar}

\section{FooBar}                                     % overlapping in toc

\end{document}

• For further reading, this is case 2 of my answer here. Jun 5 at 13:17

\ifthenelse is not expandable. You need that argument to expand to section but

\addcontentsline{toc}{\currentSectionString}{Bar}


is like

\addcontentsline{toc}{\def\tmp{section}\tmp}{Bar}


which would not work for the same reason.

You could use an expandable test such as \ifcase

\addcontentsline{toc}{\ifcase\mycounter section\or subsection\else error\fi}{Bar}

• Thanks. I tried the ifcase version. It's a little long for all levels, but it works. Jun 27, 2021 at 18:47

My impression is that you want to automatically add starred sections to the TOC.

\documentclass{article}
\usepackage[utf8]{inputenc}

\NewCommandCopy{\latexsection}{\section}
\NewCommandCopy{\latexsubsection}{\subsection}

\RenewDocumentCommand{\section}{sO{#3}m}{%
\IfBooleanTF{#1}{% starred section
\latexsection*{#3}%
}{% nonstarred section
\latexsection[#2]{#3}%
}%
}
\RenewDocumentCommand{\subsection}{sO{#3}m}{%
\IfBooleanTF{#1}{% starred subsection
\latexsubsection*{#3}%
}{% nonstarred section
\latexsubsection[#2]{#3}%
}%
}
% do the same for the other sectional levels you need

\ExplSyntaxOn
\NewDocumentCommand{\checkfortoc}{mm}
{
\str_if_eq:eeF { #1 } { \contentsname } { #2 }
}
\ExplSyntaxOff

\begin{document}

\tableofcontents

\section*{Foo}

\section*{Bar}

\section{FooBar}

\end{document}


An additional check is needed for \section, because \tableofcontents does \section*{\contentsname}, but the table of contents should not go in the table of contents.

• Thanks for your answer. I went with the other approach because it fits the rest of my code better. You are almost right. It's part of a relative sectioning I'm writing with key-value arguments. Jun 27, 2021 at 18:51

E.g., \addcontentsline{toc}{section}{Foo} beneath other things triggers that during the inputting of the .toc-file the macro \contentsline does
\csname l@section\endcsname\l@section.

Thus the second argument of \addcontentsline must consist of tokens which can be used between \csname..\endcsname, i.e., tokens whose expansion does not yield non-character-tokens.
\ifthenelse-stuff yields non-character-tokens and therefore can be used neither between \csname..\endcsname nor with macro-arguments that at some stage are inserted between \csname..\endcsname. Same for macros whose expansion at some stage yields \ifthenelse-stuff.

If you insist in sticking to \ifthenelse-stuff you need to change the order of processing to have \ifthenelse-stuff done before it comes to processing \addcontentsline—what about this? :

\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage{xifthen}        % If else commands

\makeatletter
\newcounter{counter@section@level}%
% The optional argument of \DoWithCurrentSectionString denotes tokens that
% process "{section}" as argument.
\newcommand{\DoWithCurrentSectionString}[1][\@firstofone]{%
\ifthenelse{\equal{\value{counter@section@level}}{0}}{#1{section}}{%
%      \ifthenelse{\equal{\value{counter@section@level}}{1}}{#1{subsection}}{%
%         ...
%      }%
}%
}%
\makeatother

\begin{document}

\tableofcontents

\noindent\hrulefill

\DoWithCurrentSectionString               % to check the macro itself, works as expected

\kern\ht\strutbox\hrule\hfill

\section*{Foo}

\section*{Bar}

\section{FooBar}                                     % overlapping in toc

\end{document}


the .aux-file:

\relax
\@writefile{toc}{\contentsline {section}{Foo}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{Bar}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {1}FooBar}{1}{}\protected@file@percent }
\gdef \@abspage@last{1}


the .toc-file:

\contentsline {section}{Foo}{1}{}%
\contentsline {section}{Bar}{1}{}%
\contentsline {section}{\numberline {1}FooBar}{1}{}%


For the sake of having fun here is an expandable approach which does with delimited arguments instead of \if...-constructs:

\documentclass{article}
\usepackage[utf8]{inputenc}

\makeatletter
\newcounter{counter@section@level}
\newcommand{\currentSectionString}{%
\expandafter\currentSectionStringSelect\expandafter{\number\value{counter@section@level}}%
}%
\newcommand\currentSectionStringSelect[1]{%
\currentSectionStringFork
#1!1!2!3!4!{section}%
0!#1!2!3!4!{subsection}%
0!1!#1!3!4!{subsubsection}%
0!1!2!#1!4!{paragraph}%
0!1!2!3!#1!{subparagraph}%
0!1!2!3!4!{subparagraph}%
!!!!%
}%
\@ifdefinable\currentSectionStringFork{%
\long\def\currentSectionStringFork#10!1!2!3!4!#2#3!!!!{#2}%
}%
\makeatother

\begin{document}

\tableofcontents

\noindent\hrulefill

\currentSectionString               % to check the macro itself, works as expected

\kern\ht\strutbox\hrule\hfill

\section*{Foo}

\section*{Bar}

\section{FooBar}                                     % overlapping in toc

\end{document}


the .aux-file:

\relax
\@writefile{toc}{\contentsline {section}{Foo}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{Bar}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\numberline {1}FooBar}{1}{}\protected@file@percent }
\gdef \@abspage@last{1}


the .toc-file:

\contentsline {section}{Foo}{1}{}%
\contentsline {section}{Bar}{1}{}%
\contentsline {section}{\numberline {1}FooBar}{1}{}%