The \apptocmd command from etoolbox is giving me an error I don't understand. I know how to work around the error in this particular case, but I'd like to understand what it's complaining about so that I can fix similar errors in the future.
This is the error I'm getting:
[debug] tracing \apptocmd on input line 28
[debug] analyzing \H@old@part
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] ++ control sequence is a macro with parameters
[debug] -- nested patching command and parameters in patch
[debug] -> the patching command seems to be nested in the
[debug] argument to some other command
[debug] -> the patch text seems to contain # characters
[debug] -> either avoid nesting or use # characters with
[debug] category code 12 in the patch text
[debug] -> simply doubling the # characters will not work
! Package cont Error: can't patch \H@old@part.
See the cont package documentation for explanation.
Type H <return> for immediate help.
...
l.28 }
?
The following produces the above error:
\documentclass{report}
\usepackage{etoolbox}
\tracingpatches
\usepackage{hyperref}
\makeatletter
% error handler for patching commands
\newrobustcmd{\cont@err}[1]{\PackageError{cont}{can't patch \protect#1}{}}%
% contains the name of the current part
\gdef\cont@name@part{\PackageError{cont}{not in a part}{}}
% patch \part to save the part name to \cont@name@part. note
% that \part is a parameterless macro that has \@part as its last
% token, which does take the arguments. Thus, \part can't be
% appended to; \@part has to be appended to instead.
%
% The hyperref package redefines \@part, so when hyperref is
% loaded \H@old@part needs to be patched instead.
\ifdef{\H@old@part}{
\apptocmd{\H@old@part}{%
\gdef\cont@name@part{#2}%
}{}{\cont@err{\H@old@part}}
}{
\apptocmd{\@part}{%
\gdef\cont@name@part{#2}%
}{}{\cont@err{\H@old@part}}
}
\begin{document}
\part{first part}
this part's name is ``\cont@name@part''
\end{document}
The following also doesn't work:
\catcode`\#=12
\ifdef{\H@old@part}{
\apptocmd{\H@old@part}{%
\gdef\cont@name@part{#2}%
}{}{\cont@err{\H@old@part}}
}{
\apptocmd{\@part}{%
\gdef\cont@name@part{#2}%
}{}{\cont@err{\H@old@part}}
}
\catcode`\#=6
It produces the following error:
[debug] analyzing \H@old@part
[debug] ++ control sequence is defined
[debug] ++ control sequence is a macro
[debug] ++ control sequence is a macro with parameters
[debug] -- macro cannot be retokenized cleanly
[debug] -> the macro may have been defined under a category
[debug] code regime different from the current one
[debug] -> the replacement text may contain special control
[debug] sequence tokens formed with \csname...\endcsname;
[debug] -> the replacement text may contain carriage return,
[debug] newline, or similar characters
I can work around the problem by doing the following instead:
\expandafter\apptocmd\expandafter{%
\csname\ifdef{\H@old@part}{H@old}{}@part\endcsname%
}{%
\gdef\cont@name@part{#2}%
}{}{\cont@error{\@part}}
However, I'd like to know how to fix the error while using the former approach (\apptocmd in an argument of \ifdef).
debug] -> either avoid nesting or use # characters with [debug] category code 12 in the patch textie put\catcode#=12before the ifdef and\catcode\#=6after it – David Carlisle Apr 14 '12 at 20:49\apptocmdis giving the error message?\ifdefis a command, so the error is correct.\ifcsname H@old@part\endcsname \apptocmd{\H@old@part}{% \gdef\cont@name@part{#2}% }{}{\cont@err{\H@old@part}} \else \apptocmd{\@part}{% \gdef\cont@name@part{#2}% }{}{\cont@err{\H@old@part}} \fiworks. – Stephan Lehmke Apr 14 '12 at 20:53\ifdef). A working solution often helps explain why it is an error, but not always. – Richard Hansen Apr 14 '12 at 20:59\verbwhile there are things you can do to make\verbhalf work in some arguments, the basic rule of TeX is that commands using catcode changes do not work in the arguments of other commands. – David Carlisle Apr 14 '12 at 21:26