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.

Some programming or scripting languages know the feature of #0 or $0, holding the name of the current script or the current routine.

Does a similar technique (or a workaround) exist for the macro name in TeX/LaTeX?

To clearify my question:

Is it possible to extract the name of the macro in the macro itself in a helper macro, say \CurrentMacroName, for example macro/command \FooBar holds an internal \def\CurrentMacroName{FooBar} which only survives when \FooBar is expanded.

The reason, why I am asking is, that I want to provide some \GenericWarning/\GenericError messages inside my \newcommand definitions, referring to the current macro name without having to type again... I want to behave it generically -- of course, the individual message has to be adjusted for each command.

A small non-working example... (Perhaps working, if the \CurrentMacroName - technique does exist, but may have a different name)

\documentclass{article}

%% This is my favourite (if possible)
\newcommand{\FooBar}{%

%%% Definitions and typesetting commands here...

\GenericWarning{}{Warning from \CurrentMacroName} 
%%% other stuff
}

%%% Doing it the long way

\newcommand{\OtherFooBar}{%

%%% Definitions and typesetting commands here...

\GenericWarning{}{Warning from \OtherFooBar}    
%%% other stuff
}%


\begin{document}
\FooBar%

\OtherFooBar%
\end{document}
share|improve this question
    
Short answer here is going to be 'no': TeX's a macro expansion language, so there is no concept of 'as long [as] \FooBar is executed'. –  Joseph Wright Aug 6 at 7:30
    
May be, as a workaround, renewcommand the \newcommand command, and add some sort of assignment to \CurrentMacroName at the beginning (you loose expandability). –  Manuel Aug 6 at 7:31
    
@JosephWright: I struggled while writing...expanded/executed... I know the difference... –  Christian Hupfer Aug 6 at 7:31
1  
1  
@UlrikeFischer That one's related, and I've linked, but I think this is not a dupe as there is a specific use case to cover: does that sound right? –  Joseph Wright Aug 6 at 7:49

3 Answers 3

up vote 17 down vote accepted

TeX is a macro expansion language: once a macro is expanded, there is no concept of being 'inside' it. As such, there is no stack or similar idea and you can't see where tokens 'came from'. (See Has a command access to its own name? for more on this.)

The usual approach to the problem outlined is to have a secondary internal macro that does the work and set everything up in a semi-automated way. If we look for example at the LaTeX2e definition of \mathrm and this internal helper:

> \mathrm=macro:
->\protect \mathrm  .

> \mathrm =macro:
->\relax \ifmmode \else \non@alpherr \mathrm  \fi \use@mathgroup \M@OT1 \symoperators .

we see \non@alpherr \mathrm, and it's this that does the 'not in math mode' error if you don't have the command in the right place.

The final step is to define command so at the 'user' level you only give the name once. A typical construct would be to use a generator command and perhaps a generic error/warning with 'fill in the blank':

\documentclass{article}
\newcommand\mygenerator[2]{%
  \newcommand#1{%
    % Code here from #2
    \myerrorhelper#1%
  }%
}
\newcommand\myerrorhelper[1]{%
  \GenericWarning{}{Warning from \string#1}%
}
\mygenerator\mycommand{code}
\mygenerator\myothercommand{code}
\begin{document}
\mycommand
\myothercommand

\end{document}

Note that as warnings are not expandable, you might choose to use \DeclareRobustCommand for some or all of this.

share|improve this answer
    
Thanks! I had a similar idea in mind, but since I am lazy, I didn't want to write commands this way -- now I see, it has to be done like in your propositon. I also realize, that I am still thinking too much like a C etc. programmer, trying to force other concepts into TeX ;-) –  Christian Hupfer Aug 6 at 7:54
1  
@ChristianHupfer Understandable: macro expansion is very different from functional programming, and with catcodes as well TeX work needs a specific mindset! –  Joseph Wright Aug 6 at 8:28
    
Well, I hope, my mind is not too much functionally programmed already in order to switch over to learn the whole nine yards of macro expansion –  Christian Hupfer Aug 6 at 8:34

The idea is to replace each occurrence of \thiscsname by the current \name in the macro body when the macro is defined by \mynewcommand. This means, that

\mynewcommand \mynameofmacro {... My name is \string\thiscsname ...}

would be replaced by

\newcommand \mynameofmacro {... My name is \string\mynameofmacro ...}

We can define \mynewcommand such a way:

\newtoks\macrobody
\let\newcommandOri=\newcommand
\def\mynewcommand#1#2#{%
   \def\macroname{#1}\def\macronameN{\noexpand#1}\def\newcommandparams{#2}%
   \afterassignment\mynewcommandA \macrobody
}
\def\mynewcommandA{%
   \replacemacrobody
   \edef\x{\noexpand\newcommandOri\macronameN\newcommandparams{\the\macrobody}}\x
}

The name of the macro is saved in \macroname, the parameters are saved in \newcommandparams and the macro body is saved in \macrobody toks register. The macro \replacemacrobody replaces in this toks register the occurrences of \thiscsname tokens to the contents of the \macroname. Finally, the \newcommad with the original LaTeX meaning is used via expanded \x. You can do \let\newcommand=\mynewcommand if you have bravery.

The core of this idea is the replacement macro which operates with \macrobody toks register. May be, you can use some LaTeX package to do this, but I don't know LaTeX, so I have to make this macro myself. This macro have to stay intact all tokens (spaces, \bgroup, {, }, #, etc.), only does \thiscsname -> \name. I am sorry, my implementation of this macro is somewhat complicated, but this works.

The whole example follows:

\documentclass{article}

%% The \replacemacrobody definition:
\newtoks\macrobody
\def\replacemacrobody{%
   \let\bgroup=\relax\macrobody\expandafter{\expandafter}\expandafter
   \replacemacrobodyA\the\macrobody\endmacrobody}
\def\replacemacrobodyA{\futurelet\tmp\replacemacrobodyB}
\def\replacemacrobodyB{%
   \let\next=\replacemacrobodyD
   \ifx\tmp\spacetoken \let\next=\replacemacrobodyC \addtomacrobody{ }\fi
   \ifx\tmp\thiscsname \let\next=\replacemacrobodyC
       \expandafter\addtomacrobody\macroname \fi 
   \ifx\tmp\endmacrobody \let\next=\replacemacrobodyE \fi
   \ifx\tmp\bgroupOri \let\next=\replacemacrobodyF \fi
   \next}
\def\replacemacrobodyC{\afterassignment\replacemacrobodyA \let\next= }
\long\def\replacemacrobodyD#1{\addtomacrobody#1\replacemacrobodyA}
\def\replacemacrobodyE{\ifx\IamInGroup\relax 
   \expandafter\endgroup \expandafter\macrobody\expandafter\expandafter\expandafter
      {\expandafter\the\expandafter\macrobody\expandafter{\the\macrobody}}%
   \afterassignment\replacemacrobodyA
   \else \let\bgroup=\bgroupOri \fi
   \let\next=}
\def\replacemacrobodyF{\begingroup\let\IamInGroup=\relax
   \afterassignment\replacemacrobody \macrobody=}
\long\def\addtomacrobody#1{\macrobody\expandafter{\the\macrobody#1}}
\let\bgroupOri=\bgroup
\def\tmp/{\let\spacetoken= }\tmp/ %
\def\thiscsname{^\thiscsname^}
\def\endmacrobody{^\endmacrobody^}


%% The \mynewcommand definition:
\let\newcommandOri=\newcommand
\def\mynewcommand#1#2#{%
   \def\macroname{#1}\def\macronameN{\noexpand#1}\def\newcommandparams{#2}%
   \afterassignment\mynewcommandA \macrobody
}
\def\mynewcommandA{%
   \replacemacrobody
   \edef\x{\noexpand\newcommandOri\macronameN\newcommandparams{\the\macrobody}}\x
}

\let\newcommand=\mynewcommand % I have bravery

%% The usage of redefined \newcommand:

\newcommand\testmacro
   {this is test\GenericWarning{}{Warning from \string\thiscsname}}
\newcommand\withparams [2]
   {this is \textbf{macro} with params: #1 and #2 
    \GenericWarning{}{Warning from \string\thiscsname}}

%% The test:

\begin{document}

\testmacro,
Macro \withparams {first}{second}

\end{document}
share|improve this answer
    
Your effort is tremendous, but I fear, ways to complicated, on the other hand, if I could, I would your accept it as well, but I can't split my accept vote. Thank you very much. –  Christian Hupfer Aug 8 at 15:14
    
@ChristianHupfer I hoped that somebody from LaTeX experts shows that the \replacemacrobody is already done in some LaTeX package (such as string.sty, expl3 or similar). My code can be very simplified if such hypothetical package is used. –  wipet Aug 8 at 18:05

While my first attempt solves the task by replacing tokens at definition time, I can show another solution, where \currcmd is set at execution time. You can write:

\keepcurrcmd \newcommand \foo {... My name is \textt{\currcmd} ...}

and the macro \foo prints: ... My name is \foo ...

The \keepcurrcmd defines the macro \foo as

\edef\currcmd{\string\foo}\foo+currcmd

and the internal macro \foo+currcmd is defined by the original \newcommand. The problem of this solution is that the \foo defined by this way isn't fully expanable even though the same \foo defined without \keepcurrcmd prefix is expanable.

The testing code follows:

\documentclass{article}

\def\keepcurrcmd#1#2{%
   \def#2{%
       \edef\currcmd{\string#2}%
       \csname\string#2+currcmd\endcsname}%
   \expandafter#1\csname\string#2+currcmd\endcsname}

\keepcurrcmd \newcommand\testfirst {Text text.
   \GenericWarning{}{Warning from \currcmd}%
}
\keepcurrcmd \newcommand\testsecond [2] {Text, param #1, param #2.
   \GenericWarning{}{Warning from \currcmd}%
}

\begin{document}

Hello \testfirst,
\testsecond{paramA}{paramB}

\end{document}
share|improve this answer

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.