5

Considering this definition of a latex macro:

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \noexpand\includegraphics[width=##1,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

I try to deal with empty (not optional) parameter. So I tried this definition but it is not working:

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \ifdefempty{##1}{\def\widthCATIA{3cm}}{\def\widthCATIA{##1}}%
      \includegraphics[width=\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

I think it is due to the fact that \widthCATIA is not well defined but what is the right syntax...

I call the command \createCMDMANUV{\tA}{\tB}{\tC}{\tD} where \tA to \tD contains string.

For example if \tC contains AVV and \tB contains test the macro build the command \AVVtest.

MWE (base on the same idea):

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
      \noexpand\textbf{##1}%
    }%
  }%
}
\makeatother

\begin{document}
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{coucou}   
\end{document}

MNWE (Minimal Not Working Example :-) ):

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
    \ifcsempty{##1}{ \expandafter\xdef\csname ttMANU\endcsname{Ahah}}{ \expandafter\xdef\csname ttMANU\endcsname{ohoh}}%
      \noexpand\textbf{\csname ttMANU\endcsname}%
    }%
  }%
}
\makeatother

\begin{document}
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{}    
\AABB{aa}
\end{document}

\ifcsempty seems not doing well the empty test.

SOLUTION of my MNWE:

\documentclass{standalone}
\RequirePackage{xstring}
\RequirePackage{etoolbox}

\makeatletter
\newcommand\createCMDMANUV[2]{%
\ifdefempty{##1}{\def\ttMANU{ahah}}{\def\ttMANU{ohoh}}%
  \expandafter\@ifdefinable\csname #1#2\endcsname{%
    \expandafter\xdef\csname #1#2\endcsname##1{%    
    \noexpand\ifblank{##1}{\def\noexpand\ttMANU{ahah}}{\def\noexpand\ttMANU{##1}}%%
      \noexpand\textbf{\noexpand\ttMANU}%
    }%
  }%
}
\makeatother

\begin{document}    
\def\tA {AA}
\def\tB {BB}    
\createCMDMANUV{\tA}{\tB}

\AABB{}    
\AABB{aa}      
\end{document}
7
  • \def\widthCATIA{...} is only in the local group if \ifdefempty... Please provide a complete example, not just fragments. And I think, you should rather use \ifcsempty, not \ifdefempty, but it's unclear to me
    – user31729
    Commented Apr 7, 2015 at 8:54
  • @ChristianHupfer I edited my post with a MWE.
    – Guuk
    Commented Apr 7, 2015 at 9:05
  • The real problem is the missing key-value expansion of \widthCATIA, in my point of view
    – user31729
    Commented Apr 7, 2015 at 9:16
  • @ChristianHupfer What do you mean by "key-value expansion" ? I want to create the \widthCATIA when I call the final macro.
    – Guuk
    Commented Apr 7, 2015 at 9:17
  • 1
    I think he means when reading width value it still sees a macro but not its expansion.
    – percusse
    Commented Apr 7, 2015 at 9:18

2 Answers 2

5

You are trying to expand \ifdefempty at definition time; but you should use \ifblank;

\newcommand\createCMDMANUV[4]{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\xdef\csname #3#2\endcsname##1{%
      \noexpand\vcenteredhbox{%
      \noexpand\ifblank{##1}{\def\noexpand\widthCATIA{3cm}}{\def\noexpand\widthCATIA{##1}}%
      \noexpand\includegraphics[width=\noexpand\widthCATIA,trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}

If I call

\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}

\createCMDMANUV{\tA}{\tB}{\tC}{\tD}

\show\AVVtest

I get the following response:

> \AVVtest=macro:
#1->\vcenteredhbox {\ifblank {#1}{\def \widthCATIA {3cm}}{\def \widthCATIA {#1}
}\includegraphics [width=\widthCATIA ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.

It's easier with expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand\createCMDMANUV { mmmm }
 {
  \guuk_create_cmd_manuv:xxxx { #1 } { #2 } { #3 } { #4 }
 }

\tl_new:N \l__guuk_width_catia_tl

\cs_new_protected:Nn \guuk_create_cmd_manuv:nnnn
 {
  \cs_new_protected:cpn { #3#2 } ##1
   {
    \vcenteredhbox
     {
      \tl_if_empty:nTF { ##1 }
       { \tl_set:Nn \l__guuk_width_catia_tl { 3cm } }
       { \tl_set:Nn \l__guuk_width_catia_tl { ##1 } }
      \includegraphics[width=\l__guuk_width_catia_tl,trim=0 ~ 0 ~ 1 ~ -1]{BD_CATIA/#4/#1.png}
     }
   }
 }

\cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
\ExplSyntaxOff
\def\tA{AA}\def\tB{test}\def\tC{AVV}\def\tD{DD}

\createCMDMANUV{\tA}{\tB}{\tC}{\tD}

\show\AVVtest

The response is

> \AVVtest=\protected\long macro:
#1->\vcenteredhbox {\tl_if_empty:nTF {#1}{\tl_set:Nn \l__guuk_width_catia_tl {3
cm}}{\tl_set:Nn \l__guuk_width_catia_tl {#1}}\includegraphics [width=\l__guuk_w
idth_catia_tl ,trim=0 0 1 -1]{BD_CATIA/DD/AA.png}}.

How it works

  1. I define a “user level command” \createCMDMANUV with four arguments. Its task is just to pass the arguments to \guuk_create_cmd_manuv:xxxx

  2. I define the \guuk_create_cmd_manuv:nnnn function; the four n mean that it is a macro with four “normal” arguments.

  3. This function in turn defines a new macro based on the passed arguments; it does \cs_new_protected:cpn which is the analog of \expandafter\def\csname ...\endcsname, but adding the “undefinedness test”, so

    \cs_new_protected:cpn { <tokens> } #1 { ... }
    

    is what you're doing with

    \expandafter\def\csname <tokens>\endcsname##1{...}
    
  4. As requested, the constructed macro has one argument, which is tested for emptyness with \tl_if_blank:nTF that returns the second argument if the argument is blank, the third argument otherwise. This test is the same as etoolbox \ifblank; the code just sets the internal token list to the argument, if not blank or to 3cm

  5. The inner code of the built function is exactly the same as you build with the traditional method, but without any \noexpand

  6. The final trick: with

    \cs_generate_variant:Nn \guuk_create_cmd_manuv:nnnn { xxxx }
    

    we define from the stated function another one named \guuk_create_cmd_manuv:xxxx that, when called, first does full expansion of its four arguments and then passes the expanded arguments as normal arguments to \guuk_create_cmd_manuv:nnnn

  7. Note that in the programming environment, between \ExplSyntaxOn and \ExplSyntaxOff, spaces and blank lines are ignored, so there's no need of worrying about protecting end-of-lines. The only small complication is that wanted spaces must be explicitly inserted with ~ as in the value to the trim key above.

2
  • Thank you. The expl3 seems complicated for me but I think I will take time for examining it.
    – Guuk
    Commented Apr 7, 2015 at 10:57
  • @Guuk The expl3 code is pretty much the same, but there are less complications with expansion, because we tell LaTeX precisely what we want to be expanded before being fed to the main macro.
    – egreg
    Commented Apr 7, 2015 at 11:00
1

I removed my first answer because it seems that your code is overcomplicated (as usually for many users:). First of all, you have to ask why I need to use \xdef instead normal \gdef? I don't see the reason. So, your example can work with \gdef:

\def\createCMDMANUV#1#2#3#4{%
  \expandafter\@ifdefinable\csname #3#2\endcsname{%
    \expandafter\gdef\csname #3#2\endcsname##1{%
      \vcenteredhbox{%
      \includegraphics[width=\widthCATIA{##1},trim=0 0 1 -1]{BD_CATIA/#4/#1.png}}%
    }%
  }%
}
\def\withCATIA#1{\ifx^#1^3cm\else#1\fi}

Edit (in response to the comment about expansions of parameters during declaration). If you need to use expanded parameters in your \declaremacro code, then you can think about the following code:

\def\delcleremacro#1#2#3#4{\edef\tmp{\noexpand\declaremacroA{#1}{#2}{#3}{#4}\tmp}
\def\declaremacroA#1#2#3#4{%
    \expandafter\gdef\csname #3#2\endcsname##1{%
        ... here is my complicated macro, which uses declared
            and {\bf expanded} parameters #1, #2, #3, #4 and one real parameter ##1.
            I need not to use fifty times \noexpand here.
            The test of empty parameter ##1 can be done by
            \ifx^##1^empty\else nonempty\fi or (more robust but nonexpandable)
            \def\tmp{##1}\ifx\tmp\empty \def\tmp{3cm}\else\def\tmp{##1}\fi
            and you can use \tmp in your meaning of \widthCATIA.
            Here is no \noexpand problem.
}}
2
  • This is why I wrote the MWE and MWNE... The reason of the use of \xdef in place of \gdef is only due to the fact that I use a solution found on the internet without changing this syntax. Thank you for your solution.
    – Guuk
    Commented Apr 7, 2015 at 12:15
  • The expansion is not needed for #2 and #3, but it is for #1 and #4, because in the given usage example they should depend on the given value at definition time, not at call time.
    – egreg
    Commented Apr 7, 2015 at 12:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .