[Tex/LaTex] Macro saving a value for next run

auxiliary-filesmacros

I need a macro, which saves a string (like the content of a label) to the aux file. During the next run, there should be a macro checking, if that string has been set in the last run or not.

My solution so far presented as an example:

\documentclass{minimal}
\usepackage{etoolbox}

\makeatletter
\def\csxdefaux#1{%
    \protected@write\@mainaux{}{%
        \expandafter\string\expandafter\xdef\expandafter\string\csname #1\endcsname{}%
    }%
}
\makeatother

\begin{document}
    \ifcsdef{setValue}{value set}{value \emph{not} set}
    \csxdefaux{setValue}

    \ifcsdef{strange:value}{strange value set}{strange value \emph{not} set}
    \csxdefaux{strange:value}
\end{document}

This results (after multiple compilations) in:
enter image description here

So although the pair of \csxdefaux and \ifcsdef macros obviously works for normal strings, it fails for strings with special characters.

What would be a good way to achieve the same as with my solution but supporting a wide range of special characters like colons, digits, umlauts?

Best Answer

The issue is nothing to do with \ifcsdef, as it is testing correctly and giving the correct answer. To see why, we need to look at the .aux file. With your definition, the .aux file reads

\relax 
\xdef\setValue{}
\xdef\strange:value{}

which is then read back by LaTeX to defined \setValue (as required), and \strange as a delimited macro (wrong). The latter happens as : is an 'other' character at this point, and the tokenization you had before is lost when you write something to a file.

What you therefore need is the \csname ...\endcsname construct inside the .aux file. One working definition is

\def\csxdefaux#1{%
    \protected@write\@mainaux{}{%
        \string\expandafter\string\gdef
          \string\csname\string\detokenize{#1}\string\endcsname{}%
    }%
}

or using the etoolbox wrapper

\def\csxdefaux#1{%
    \protected@write\@mainaux{}{%
        \csgdef{\detokenize{#1}}{}%
    }%
}

I've detokenized #1 when it's read back in case something like babel has made anything active. (I'm not sure why you have \xdef, so went with \gdef instead.)

Related Question