9

In a macro containing some conditions searching for existing macros that match a pattern, I have a combination of conditions that should be impossible. If the user mistakenly provides parameters that get them into this situation, I'd like the run to fail immediately with an error message. What's the easiest way to make this happen? I'm assuming there's a straightforward answer, but I'm coming up empty with a search – everything is about troubleshooting failed compiles.

I'm imagining something like:

\usepackage{etoolbox}

\newcommand*{\mycommand}[1]{%
    \ifcsdef{somecommandcontaining#1}{
        \ifcsdef{someothercommandcontaining#1}{
            valid condition 1, do something
        }{ %%%%% This combination of conditions is invalid %%%%%
            \failthisrun{Invalid parameter '#1'}
        }%
    }{%
        valid condition 2, do something else
    }
}
7
  • 2
    \PackageError{mypackage}{Invalid parameter '#1'}{dont do that} ? Jul 24 at 17:29
  • 1
    yes although it's not that latex really cares \PackageError{local-hack-in-preamble-i-might-put-in-a-package-one-day} works too Jul 24 at 17:44
  • 3
    \PackageError will error, but the run will not fail, if the user uses \nonstopmode. In such cases you need something more fatal, like trying to input an nonexisting file. Jul 24 at 17:45
  • 2
    personally I think a run with an error has failed, some editors and online tex systems may try to hide that but.... Jul 24 at 21:47
  • 1
    @DavidCarlisle Would the matter "runs that (in some way) fail without an error" be worth a question? I think about scenarios where you silently don't get the desired output - without being notified about it by whatsoever message. (E.g., if you use hyperref's \hyperlink and \hypertarget and a non-pdfTeX-engine you can easily get an output-file with broken hyperlinks without being notified via message.) Jul 24 at 22:24

3 Answers 3

10

You can generate a latex formatted error with

\PackageError{mypackage}{Invalid parameter '#1'}{dont do that}

For a quick debugging error you can simply use \AnyUndefinedCommand (I use \ERROR typically) and it stops

9

In LaTeX you can use the macro \stop as a "panic button" for aborting compilation without having raised an error-message.

I suggest using the package l3msg of expl3 for raising (error-)messages and probably notifying about aborting before aborting compilation via \stop.

"probably" because I don't know what criteria you use to classify a compile/run as "failed" - whether it's enough that there was an error message, or whether there must have been a situation that lead to abortion of compilation.

If your LaTeX distribution is up to date (L3 programming layer <2021-05-18> or more recent), you can do something like this:

\ExplSyntaxOn
\prop_gput:Nnn \g_msg_module_type_prop { MYPREAMBLECODE } {}
\prop_gput:Nnn \g_msg_module_name_prop { MYPREAMBLECODE } {Preamble Code}
\msg_new:nnnn {MYPREAMBLECODE} 
              {Invalid Parameter}
              {Invalid~parameter~'#3'~as~#2~argument~of~macro~#1~\msg_line_context: .} 
              {Don't~pass~'#3'~as~#2~argument~of~macro~#1! }
\msg_new:nnnn {MYPREAMBLECODE} 
              {Abort compilation}
              {Compilation~is~aborted~now.} 
              {The~situation~really~is~weird!~Please~fix~the~reported~errors!}
\cs_new:Npn \InvalidParameterErrorStop #1 #2 #3 {
  % \msg_error:... etc turn their arguments into strings, but let's make sure
  % the control sequence token whose name is to be displayed is stringified with a
  % leading backslash regardless the current value of the \escapechar parameter:
  \exp_args:Nne \use:n  {
    \msg_error:nnnnn {MYPREAMBLECODE} {Invalid Parameter}
    %\msg_expandable_error:nnnnn {MYPREAMBLECODE} {Invalid Parameter}
  }{\iow_char:N \\\cs_to_str:N #1}{#2}{#3}
  % --- the following lines lead to aborting the LaTeX-run 
  %     after notifying about imminent abortion:
  \msg_note:nn {MYPREAMBLECODE} {Abort compilation}
  %\msg_expandable_note:nn {MYPREAMBLECODE} {Abort compilation}
  \stop
  % --------------------------------------------------------
}
\ExplSyntaxOff

\RequirePackage{etoolbox}

\newcommand*{\mycommand}[1]{%
    \ifcsdef{somecommandcontaining#1}{%
        \ifcsdef{someothercommandcontaining#1}{%
            valid condition 1, do something
        }{ %%%%% This combination of conditions is invalid %%%%%
            \InvalidParameterErrorStop{\mycommand}{first}{#1}%
        }%
    }{%
        valid condition 2, do something else
    }%
}%

\newcommand\somecommandcontainingFooBar{This is defined.}

\documentclass{article}

\begin{document}

\mycommand{FooBar}

\end{document}

Output on terminal and in .log-file:

! Preamble Code Error: Invalid parameter 'FooBar' as first argument of macro
(Preamble Code)        \mycommand on line 49.

For immediate help type H <return>.
 ...                                              
                                                  
l.49 \mycommand{FooBar}
                        
? H

Don't pass 'FooBar' as first argument of macro \mycommand!

? 

Preamble Code Info: Compilation is aborted now.
4
  • \stop though does not signal a error it's more like a special form of \end{document} (your code implies this already by giving a error first, but "aborting" in your opening line might suggest an error exit Jul 24 at 21:43
  • @DavidCarlisle According to source2e.pdf \stop is a "panic button to stop LaTeX in the middle". It does not signal an error - that's why I suggested using l3msg for raising an error-message and a note about aborting compilation. Jul 24 at 21:47
  • yes sure as I say your code is fine, just the opening line. Quoting documentation is of course a cruel and unfair blow:-) Jul 24 at 21:49
  • @DavidCarlisle as I say your code is fine, just the opening line Really? Thanks! Code of mine seldom is fine. ... What a rhyme! I must be on a high... - I hope rhyming comes out better than quoting manuals. ;-) Jul 24 at 21:59
6

There is TeX primitive command \errmessage. For example:

\def\mycommand#1{%
   \ifcsname somecommandcontaining#1\endcsname
      \ifcsname someothercommandcontaining#1\endcsname
         valid condition 1, do something
      \else
         \errmessage{Invalid parameter "#1"}%
      \fi
   \else
      valid condition 2, do something else
   \fi
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.